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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore9
-rw-r--r--CMakeLists.txt49
-rw-r--r--SConstruct1
-rw-r--r--build_files/cmake/macros.cmake1
-rw-r--r--build_files/scons/tools/btools.py2
-rw-r--r--extern/CMakeLists.txt1
-rw-r--r--extern/SConscript1
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm1
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm2
-rw-r--r--intern/smoke/CMakeLists.txt7
-rw-r--r--intern/smoke/extern/smoke_API.h25
-rw-r--r--intern/smoke/intern/BASIC_FLUID.cpp0
-rw-r--r--intern/smoke/intern/FLUID_3D.cpp1054
-rw-r--r--intern/smoke/intern/FLUID_3D.h9
-rw-r--r--intern/smoke/intern/MANTA.cpp666
-rw-r--r--intern/smoke/intern/MANTA.h136
-rw-r--r--intern/smoke/intern/WTURBULENCE.cpp186
-rw-r--r--intern/smoke/intern/WTURBULENCE.h5
-rw-r--r--intern/smoke/intern/scenarios/smoke.h361
-rw-r--r--intern/smoke/intern/smoke_API.cpp119
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_smoke.py141
-rw-r--r--source/blender/blenkernel/CMakeLists.txt5
-rw-r--r--source/blender/blenkernel/SConscript4
-rw-r--r--source/blender/blenkernel/intern/pointcache.c27
-rw-r--r--source/blender/blenkernel/intern/smoke.c173
-rw-r--r--source/blender/editors/physics/physics_fluid.c133
-rw-r--r--source/blender/editors/physics/physics_intern.h4
-rw-r--r--source/blender/editors/physics/physics_ops.c11
-rw-r--r--source/blender/makesdna/DNA_smoke_types.h29
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt4
-rw-r--r--source/blender/makesrna/intern/SConscript4
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c113
-rw-r--r--source/blender/python/CMakeLists.txt2
-rw-r--r--source/blender/python/SConscript9
-rw-r--r--source/blender/python/intern/CMakeLists.txt4
-rw-r--r--source/blender/python/intern/bpy_interface.c5
-rwxr-xr-xsource/blender/python/manta_full/CMakeLists.txt597
-rw-r--r--source/blender/python/manta_full/COPYING674
-rw-r--r--source/blender/python/manta_full/Doxyfile.in1719
-rw-r--r--source/blender/python/manta_full/INSTALLING2
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/adler32.c179
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/compress.c80
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/crc32.c425
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/crc32.h441
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/deflate.c1967
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/deflate.h346
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/gzclose.c25
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/gzguts.h209
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/gzlib.c634
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/gzread.c594
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/gzwrite.c577
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/infback.c640
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/inffast.c340
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/inffast.h11
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/inffixed.h94
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/inflate.c1512
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/inflate.h122
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/inftrees.c306
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/inftrees.h62
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/trees.c1226
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/trees.h128
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/uncompr.c59
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/zconf.h511
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/zlib.h1768
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/zutil.c324
-rw-r--r--source/blender/python/manta_full/dependencies/zlib-1.2.8/zutil.h253
-rw-r--r--source/blender/python/manta_full/resources/pause.pngbin0 -> 643 bytes
-rw-r--r--source/blender/python/manta_full/resources/play.pngbin0 -> 734 bytes
-rw-r--r--source/blender/python/manta_full/resources/res.qrc7
-rw-r--r--source/blender/python/manta_full/resources/stop.pngbin0 -> 713 bytes
-rw-r--r--source/blender/python/manta_full/scenes/simpleplume.py61
-rw-r--r--source/blender/python/manta_full/source/cmake/FindTBB.cmake267
-rw-r--r--source/blender/python/manta_full/source/commonkernels.h128
-rw-r--r--source/blender/python/manta_full/source/conjugategrad.cpp303
-rw-r--r--source/blender/python/manta_full/source/conjugategrad.h169
-rw-r--r--source/blender/python/manta_full/source/cuda/buoyancy.cu421
-rw-r--r--source/blender/python/manta_full/source/cuda/cudatools.h176
-rw-r--r--source/blender/python/manta_full/source/cuda/curlnoise.cu110
-rw-r--r--source/blender/python/manta_full/source/cuda/curlnoise.h196
-rw-r--r--source/blender/python/manta_full/source/cuda/meshtools.cu165
-rw-r--r--source/blender/python/manta_full/source/cuda/particle.cu172
-rw-r--r--source/blender/python/manta_full/source/cuda/turbulence.cu164
-rw-r--r--source/blender/python/manta_full/source/edgecollapse.cpp666
-rw-r--r--source/blender/python/manta_full/source/edgecollapse.h36
-rw-r--r--source/blender/python/manta_full/source/fastmarch.cpp424
-rw-r--r--source/blender/python/manta_full/source/fastmarch.h196
-rw-r--r--source/blender/python/manta_full/source/fileio.cpp700
-rw-r--r--source/blender/python/manta_full/source/fileio.h48
-rw-r--r--source/blender/python/manta_full/source/flip.cpp487
-rw-r--r--source/blender/python/manta_full/source/flip.h23
-rw-r--r--source/blender/python/manta_full/source/fluidsolver.cpp172
-rw-r--r--source/blender/python/manta_full/source/fluidsolver.h92
-rw-r--r--source/blender/python/manta_full/source/general.cpp128
-rw-r--r--source/blender/python/manta_full/source/general.h138
-rw-r--r--source/blender/python/manta_full/source/grid.cpp445
-rw-r--r--source/blender/python/manta_full/source/grid.h473
-rw-r--r--source/blender/python/manta_full/source/gui/customctrl.cpp172
-rw-r--r--source/blender/python/manta_full/source/gui/customctrl.h129
-rw-r--r--source/blender/python/manta_full/source/gui/glwidget.cpp292
-rw-r--r--source/blender/python/manta_full/source/gui/glwidget.h72
-rw-r--r--source/blender/python/manta_full/source/gui/mainwindow.cpp243
-rw-r--r--source/blender/python/manta_full/source/gui/mainwindow.h73
-rw-r--r--source/blender/python/manta_full/source/gui/meshpainter.cpp300
-rw-r--r--source/blender/python/manta_full/source/gui/meshpainter.h59
-rw-r--r--source/blender/python/manta_full/source/gui/painter.cpp539
-rw-r--r--source/blender/python/manta_full/source/gui/painter.h111
-rw-r--r--source/blender/python/manta_full/source/gui/particlepainter.cpp456
-rw-r--r--source/blender/python/manta_full/source/gui/particlepainter.h61
-rw-r--r--source/blender/python/manta_full/source/gui/qtmain.cpp150
-rw-r--r--source/blender/python/manta_full/source/gui/qtmain.h77
-rw-r--r--source/blender/python/manta_full/source/kernel.cpp36
-rw-r--r--source/blender/python/manta_full/source/kernel.h80
-rw-r--r--source/blender/python/manta_full/source/levelset.cpp334
-rw-r--r--source/blender/python/manta_full/source/levelset.h44
-rw-r--r--source/blender/python/manta_full/source/mesh.cpp775
-rw-r--r--source/blender/python/manta_full/source/mesh.h257
-rw-r--r--source/blender/python/manta_full/source/movingobs.cpp92
-rw-r--r--source/blender/python/manta_full/source/movingobs.h42
-rw-r--r--source/blender/python/manta_full/source/noisefield.cpp296
-rw-r--r--source/blender/python/manta_full/source/noisefield.h393
-rw-r--r--source/blender/python/manta_full/source/particle.cpp358
-rw-r--r--source/blender/python/manta_full/source/particle.h608
-rw-r--r--source/blender/python/manta_full/source/plugin/advection.cpp324
-rw-r--r--source/blender/python/manta_full/source/plugin/extforces.cpp144
-rw-r--r--source/blender/python/manta_full/source/plugin/initplugins.cpp105
-rw-r--r--source/blender/python/manta_full/source/plugin/kepsilon.cpp183
-rw-r--r--source/blender/python/manta_full/source/plugin/meshplugins.cpp623
-rw-r--r--source/blender/python/manta_full/source/plugin/pressure.cpp310
-rw-r--r--source/blender/python/manta_full/source/plugin/vortexplugins.cpp312
-rw-r--r--source/blender/python/manta_full/source/plugin/waveletturbulence.cpp296
-rw-r--r--source/blender/python/manta_full/source/preprocessor/code.cpp92
-rw-r--r--source/blender/python/manta_full/source/preprocessor/code.h134
-rw-r--r--source/blender/python/manta_full/source/preprocessor/codegen_kernel.cpp365
-rw-r--r--source/blender/python/manta_full/source/preprocessor/codegen_python.cpp505
-rw-r--r--source/blender/python/manta_full/source/preprocessor/main.cpp120
-rw-r--r--source/blender/python/manta_full/source/preprocessor/merge.cpp179
-rw-r--r--source/blender/python/manta_full/source/preprocessor/parse.cpp356
-rw-r--r--source/blender/python/manta_full/source/preprocessor/prep.h46
-rw-r--r--source/blender/python/manta_full/source/preprocessor/tokenize.cpp348
-rw-r--r--source/blender/python/manta_full/source/preprocessor/tokenize.h69
-rw-r--r--source/blender/python/manta_full/source/preprocessor/util.cpp217
-rw-r--r--source/blender/python/manta_full/source/preprocessor/util.h63
-rw-r--r--source/blender/python/manta_full/source/pwrapper/manta.h33
-rw-r--r--source/blender/python/manta_full/source/pwrapper/manta_api.cpp27
-rw-r--r--source/blender/python/manta_full/source/pwrapper/manta_api.h6
-rw-r--r--source/blender/python/manta_full/source/pwrapper/pclass.cpp178
-rw-r--r--source/blender/python/manta_full/source/pwrapper/pclass.h106
-rw-r--r--source/blender/python/manta_full/source/pwrapper/pconvert.cpp422
-rw-r--r--source/blender/python/manta_full/source/pwrapper/pconvert.h204
-rw-r--r--source/blender/python/manta_full/source/pwrapper/pvec3.cpp286
-rw-r--r--source/blender/python/manta_full/source/pwrapper/pymain.cpp112
-rw-r--r--source/blender/python/manta_full/source/pwrapper/pymain.h8
-rwxr-xr-xsource/blender/python/manta_full/source/pwrapper/pythonInclude.h41
-rw-r--r--source/blender/python/manta_full/source/pwrapper/registry.cpp682
-rw-r--r--source/blender/python/manta_full/source/pwrapper/registry.h87
-rw-r--r--source/blender/python/manta_full/source/python/defines.py27
-rw-r--r--source/blender/python/manta_full/source/shapes.cpp381
-rw-r--r--source/blender/python/manta_full/source/shapes.h130
-rw-r--r--source/blender/python/manta_full/source/test.cpp151
-rw-r--r--source/blender/python/manta_full/source/turbulencepart.cpp141
-rw-r--r--source/blender/python/manta_full/source/turbulencepart.h53
-rw-r--r--source/blender/python/manta_full/source/util/integrator.h75
-rw-r--r--source/blender/python/manta_full/source/util/interpol.h209
-rw-r--r--source/blender/python/manta_full/source/util/interpolHigh.h58
-rw-r--r--source/blender/python/manta_full/source/util/mcubes.h323
-rw-r--r--source/blender/python/manta_full/source/util/quaternion.h89
-rw-r--r--source/blender/python/manta_full/source/util/randomstream.h377
-rw-r--r--source/blender/python/manta_full/source/util/solvana.h176
-rw-r--r--source/blender/python/manta_full/source/util/vectorbase.cpp35
-rw-r--r--source/blender/python/manta_full/source/util/vectorbase.h585
-rw-r--r--source/blender/python/manta_full/source/vortexfilament.cpp340
-rw-r--r--source/blender/python/manta_full/source/vortexfilament.h72
-rw-r--r--source/blender/python/manta_full/source/vortexpart.cpp96
-rw-r--r--source/blender/python/manta_full/source/vortexpart.h45
-rw-r--r--source/blender/python/manta_full/source/vortexsheet.cpp92
-rw-r--r--source/blender/python/manta_full/source/vortexsheet.h87
-rw-r--r--source/blender/python/manta_pp/CMakeLists.txt137
-rw-r--r--source/blender/python/manta_pp/commonkernels.h140
-rw-r--r--source/blender/python/manta_pp/commonkernels.h.reg1
-rw-r--r--source/blender/python/manta_pp/commonkernels.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/conjugategrad.cpp316
-rw-r--r--source/blender/python/manta_pp/conjugategrad.h181
-rw-r--r--source/blender/python/manta_pp/conjugategrad.h.reg1
-rw-r--r--source/blender/python/manta_pp/conjugategrad.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/edgecollapse.cpp678
-rw-r--r--source/blender/python/manta_pp/edgecollapse.h48
-rw-r--r--source/blender/python/manta_pp/edgecollapse.h.reg1
-rw-r--r--source/blender/python/manta_pp/edgecollapse.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/fastmarch.cpp438
-rw-r--r--source/blender/python/manta_pp/fastmarch.h197
-rw-r--r--source/blender/python/manta_pp/fastmarch.h.reg1
-rw-r--r--source/blender/python/manta_pp/fastmarch.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/fileio.cpp771
-rw-r--r--source/blender/python/manta_pp/fileio.h62
-rw-r--r--source/blender/python/manta_pp/fileio.h.reg1
-rw-r--r--source/blender/python/manta_pp/fileio.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/fluidsolver.cpp137
-rw-r--r--source/blender/python/manta_pp/fluidsolver.h92
-rw-r--r--source/blender/python/manta_pp/fluidsolver.h.reg9
-rw-r--r--source/blender/python/manta_pp/fluidsolver.h.reg.cpp23
-rw-r--r--source/blender/python/manta_pp/general.cpp141
-rw-r--r--source/blender/python/manta_pp/general.h151
-rw-r--r--source/blender/python/manta_pp/general.h.reg1
-rw-r--r--source/blender/python/manta_pp/general.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/grid.cpp560
-rw-r--r--source/blender/python/manta_pp/grid.h508
-rw-r--r--source/blender/python/manta_pp/grid.h.reg46
-rw-r--r--source/blender/python/manta_pp/grid.h.reg.cpp107
-rw-r--r--source/blender/python/manta_pp/gui/customctrl.cpp198
-rw-r--r--source/blender/python/manta_pp/gui/customctrl.h148
-rw-r--r--source/blender/python/manta_pp/gui/customctrl.h.reg31
-rw-r--r--source/blender/python/manta_pp/gui/customctrl.h.reg.cpp48
-rw-r--r--source/blender/python/manta_pp/gui/glwidget.cpp311
-rw-r--r--source/blender/python/manta_pp/gui/glwidget.h87
-rw-r--r--source/blender/python/manta_pp/gui/glwidget.h.reg1
-rw-r--r--source/blender/python/manta_pp/gui/glwidget.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/gui/mainwindow.cpp318
-rw-r--r--source/blender/python/manta_pp/gui/mainwindow.h106
-rw-r--r--source/blender/python/manta_pp/gui/mainwindow.h.reg1
-rw-r--r--source/blender/python/manta_pp/gui/mainwindow.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/gui/meshpainter.cpp313
-rw-r--r--source/blender/python/manta_pp/gui/meshpainter.h71
-rw-r--r--source/blender/python/manta_pp/gui/meshpainter.h.reg1
-rw-r--r--source/blender/python/manta_pp/gui/meshpainter.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/gui/moc_customctrl.cxx165
-rw-r--r--source/blender/python/manta_pp/gui/moc_customctrl.cxx_parameters5
-rw-r--r--source/blender/python/manta_pp/gui/moc_glwidget.cxx132
-rw-r--r--source/blender/python/manta_pp/gui/moc_glwidget.cxx_parameters5
-rw-r--r--source/blender/python/manta_pp/gui/moc_mainwindow.cxx175
-rw-r--r--source/blender/python/manta_pp/gui/moc_mainwindow.cxx_parameters5
-rw-r--r--source/blender/python/manta_pp/gui/moc_meshpainter.cxx93
-rw-r--r--source/blender/python/manta_pp/gui/moc_meshpainter.cxx_parameters5
-rw-r--r--source/blender/python/manta_pp/gui/moc_painter.cxx170
-rw-r--r--source/blender/python/manta_pp/gui/moc_painter.cxx_parameters5
-rw-r--r--source/blender/python/manta_pp/gui/moc_particlepainter.cxx80
-rw-r--r--source/blender/python/manta_pp/gui/moc_particlepainter.cxx_parameters5
-rw-r--r--source/blender/python/manta_pp/gui/moc_qtmain.cxx182
-rw-r--r--source/blender/python/manta_pp/gui/moc_qtmain.cxx_parameters5
-rw-r--r--source/blender/python/manta_pp/gui/painter.cpp555
-rw-r--r--source/blender/python/manta_pp/gui/painter.h127
-rw-r--r--source/blender/python/manta_pp/gui/painter.h.reg1
-rw-r--r--source/blender/python/manta_pp/gui/painter.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/gui/particlepainter.cpp370
-rw-r--r--source/blender/python/manta_pp/gui/particlepainter.h74
-rw-r--r--source/blender/python/manta_pp/gui/particlepainter.h.reg1
-rw-r--r--source/blender/python/manta_pp/gui/particlepainter.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/gui/qtmain.cpp163
-rw-r--r--source/blender/python/manta_pp/gui/qtmain.h89
-rw-r--r--source/blender/python/manta_pp/gui/qtmain.h.reg1
-rw-r--r--source/blender/python/manta_pp/gui/qtmain.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/hginfo.h4
-rw-r--r--source/blender/python/manta_pp/kernel.cpp49
-rw-r--r--source/blender/python/manta_pp/kernel.h95
-rw-r--r--source/blender/python/manta_pp/kernel.h.reg1
-rw-r--r--source/blender/python/manta_pp/kernel.h.reg.cpp0
-rw-r--r--source/blender/python/manta_pp/levelset.cpp346
-rw-r--r--source/blender/python/manta_pp/levelset.h56
-rw-r--r--source/blender/python/manta_pp/levelset.h.reg9
-rw-r--r--source/blender/python/manta_pp/levelset.h.reg.cpp22
-rw-r--r--source/blender/python/manta_pp/mesh.cpp800
-rw-r--r--source/blender/python/manta_pp/mesh.h273
-rw-r--r--source/blender/python/manta_pp/mesh.h.reg12
-rw-r--r--source/blender/python/manta_pp/mesh.h.reg.cpp26
-rw-r--r--source/blender/python/manta_pp/movingobs.cpp105
-rw-r--r--source/blender/python/manta_pp/movingobs.h54
-rw-r--r--source/blender/python/manta_pp/movingobs.h.reg7
-rw-r--r--source/blender/python/manta_pp/movingobs.h.reg.cpp21
-rw-r--r--source/blender/python/manta_pp/noisefield.cpp309
-rw-r--r--source/blender/python/manta_pp/noisefield.h405
-rw-r--r--source/blender/python/manta_pp/noisefield.h.reg12
-rw-r--r--source/blender/python/manta_pp/noisefield.h.reg.cpp26
-rw-r--r--source/blender/python/manta_pp/particle.cpp519
-rw-r--r--source/blender/python/manta_pp/particle.h665
-rw-r--r--source/blender/python/manta_pp/particle.h.reg58
-rw-r--r--source/blender/python/manta_pp/particle.h.reg.cpp119
-rw-r--r--source/blender/python/manta_pp/plugin/advection.cpp337
-rw-r--r--source/blender/python/manta_pp/plugin/extforces.cpp207
-rw-r--r--source/blender/python/manta_pp/plugin/flip.cpp500
-rw-r--r--source/blender/python/manta_pp/plugin/initplugins.cpp201
-rw-r--r--source/blender/python/manta_pp/plugin/kepsilon.cpp195
-rw-r--r--source/blender/python/manta_pp/plugin/meshplugins.cpp636
-rw-r--r--source/blender/python/manta_pp/plugin/pressure.cpp327
-rw-r--r--source/blender/python/manta_pp/plugin/vortexplugins.cpp324
-rw-r--r--source/blender/python/manta_pp/plugin/waveletturbulence.cpp309
-rw-r--r--source/blender/python/manta_pp/plugin/waves.cpp174
-rw-r--r--source/blender/python/manta_pp/pwrapper/manta.h33
-rw-r--r--source/blender/python/manta_pp/pwrapper/manta_api.cpp27
-rw-r--r--source/blender/python/manta_pp/pwrapper/manta_api.h6
-rw-r--r--source/blender/python/manta_pp/pwrapper/pclass.cpp177
-rw-r--r--source/blender/python/manta_pp/pwrapper/pclass.h106
-rw-r--r--source/blender/python/manta_pp/pwrapper/pconvert.cpp410
-rw-r--r--source/blender/python/manta_pp/pwrapper/pconvert.h204
-rw-r--r--source/blender/python/manta_pp/pwrapper/pvec3.cpp286
-rw-r--r--source/blender/python/manta_pp/pwrapper/pymain.cpp264
-rwxr-xr-xsource/blender/python/manta_pp/pwrapper/pythonInclude.h41
-rw-r--r--source/blender/python/manta_pp/pwrapper/registry.cpp681
-rw-r--r--source/blender/python/manta_pp/pwrapper/registry.h87
-rw-r--r--source/blender/python/manta_pp/python/defines.py11
-rw-r--r--source/blender/python/manta_pp/python/defines.py.reg2
-rw-r--r--source/blender/python/manta_pp/python/defines.py.reg.cpp2
-rw-r--r--source/blender/python/manta_pp/shapes.cpp394
-rw-r--r--source/blender/python/manta_pp/shapes.h142
-rw-r--r--source/blender/python/manta_pp/shapes.h.reg25
-rw-r--r--source/blender/python/manta_pp/shapes.h.reg.cpp43
-rw-r--r--source/blender/python/manta_pp/test.cpp164
-rw-r--r--source/blender/python/manta_pp/timing.cpp128
-rw-r--r--source/blender/python/manta_pp/timing.h72
-rw-r--r--source/blender/python/manta_pp/timing.h.reg6
-rw-r--r--source/blender/python/manta_pp/timing.h.reg.cpp20
-rw-r--r--source/blender/python/manta_pp/turbulencepart.cpp154
-rw-r--r--source/blender/python/manta_pp/turbulencepart.h64
-rw-r--r--source/blender/python/manta_pp/turbulencepart.h.reg9
-rw-r--r--source/blender/python/manta_pp/turbulencepart.h.reg.cpp34
-rw-r--r--source/blender/python/manta_pp/util/integrator.h75
-rw-r--r--source/blender/python/manta_pp/util/interpol.h209
-rw-r--r--source/blender/python/manta_pp/util/interpolHigh.h58
-rw-r--r--source/blender/python/manta_pp/util/mcubes.h323
-rw-r--r--source/blender/python/manta_pp/util/quaternion.h89
-rw-r--r--source/blender/python/manta_pp/util/randomstream.h377
-rw-r--r--source/blender/python/manta_pp/util/solvana.h176
-rw-r--r--source/blender/python/manta_pp/util/vectorbase.cpp35
-rw-r--r--source/blender/python/manta_pp/util/vectorbase.h585
-rw-r--r--source/blender/python/manta_pp/vortexpart.cpp109
-rw-r--r--source/blender/python/manta_pp/vortexpart.h56
-rw-r--r--source/blender/python/manta_pp/vortexpart.h.reg7
-rw-r--r--source/blender/python/manta_pp/vortexpart.h.reg.cpp32
-rw-r--r--source/blender/python/manta_pp/vortexsheet.cpp105
-rw-r--r--source/blender/python/manta_pp/vortexsheet.h98
-rw-r--r--source/blender/python/manta_pp/vortexsheet.h.reg7
-rw-r--r--source/blender/python/manta_pp/vortexsheet.h.reg.cpp21
-rw-r--r--source/blender/render/CMakeLists.txt4
-rw-r--r--source/blenderplayer/CMakeLists.txt1
-rw-r--r--source/creator/CMakeLists.txt13
333 files changed, 63588 insertions, 451 deletions
diff --git a/.gitignore b/.gitignore
index b172c446553..78ac65a63f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,9 +26,14 @@ Desktop.ini
# local patches
/*.patch
/*.diff
-
# in-source doc-gen
/doc/doxygen/html/
/doc/python_api/sphinx-in-tmp/
/doc/python_api/sphinx-in/
-/doc/python_api/sphinx-out/
+/doc/python_api/sphinx-out/.gitignore
+Roman_Pogribnyi/
+Roman_Pogribnyi.tar.gz
+Archive.zip
+Roman_Pogribnyi 2/
+make_diffs.txt
+series \ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8e54ddc9274..6b879b45401 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -222,6 +222,7 @@ option(WITH_GAMEENGINE "Enable Game Engine" ${_init_GAMEENGINE})
option(WITH_PLAYER "Build Player" OFF)
option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ${_init_OPENCOLORIO})
option(WITH_COMPOSITOR "Enable the tile based nodal compositor" ON)
+option(WITH_MOD_MANTA "Enable Mantaflow Framework" ON)
# GHOST Windowing Library Options
option(WITH_GHOST_DEBUG "Enable debugging output for the GHOST library" OFF)
@@ -2483,15 +2484,47 @@ if(WITH_PYTHON_MODULE)
endif()
#-----------------------------------------------------------------------------
+# Configure mantaflow.
+if(WITH_MOD_MANTA)
+ add_definitions(-DWITH_MANTA)
+endif()
+
+#if(WITH_MOD_MANTA)
+# message("including manta")
+# include(ExternalProject)
+# set(QT_QMAKE_EXECUTABLE /usr/bin/qmake-4.8)
+# #set(BULLET_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/extern/bullet2/src")
+# ExternalProject_Add(
+# MantaFlow
+# CVS_MODULE CMake
+## CVS_TAG -r CMake-2-6-4
+# #CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:
+# # PATH=<INSTALL_DIR>
+# #CMAKE_ARGS -DGUI=OFF
+# # -DPREPDEBUG=ON
+# UPDATE_COMMAND ""
+# DOWNLOAD_COMMAND ""
+# INSTALL_COMMAND ""
+# SOURCE_DIR ${CMAKE_SOURCE_DIR}/source/blender/python/manta_pp
+#)
+#ExternalProject_Add_Step(MantaFlow forceconfigure
+# COMMAND ${CMAKE_COMMAND} -E echo "Force configure of MantaFlow"
+# DEPENDEES update
+# DEPENDERS configure
+# ALWAYS 0)
+##set_target_properties(MantaFlow PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
+#endif()
+
+#-----------------------------------------------------------------------------
# Extra compile flags
if(CMAKE_COMPILER_IS_GNUCC)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ALL -Wall)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_CAST_ALIGN -Wcast-align)
- ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_DECLARATION_AFTER_STATEMENT -Werror=declaration-after-statement)
- ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_IMPLICIT_FUNCTION_DECLARATION -Werror=implicit-function-declaration)
- ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_RETURN_TYPE -Werror=return-type)
+# ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_DECLARATION_AFTER_STATEMENT -Werror=declaration-after-statement)
+# ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_IMPLICIT_FUNCTION_DECLARATION -Werror=implicit-function-declaration)
+# ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_RETURN_TYPE -Werror=return-type)
# system headers sometimes do this, disable for now, was: -Werror=strict-prototypes
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_STRICT_PROTOTYPES -Wstrict-prototypes)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_MISSING_PROTOTYPES -Wmissing-prototypes)
@@ -2506,7 +2539,6 @@ if(CMAKE_COMPILER_IS_GNUCC)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_NULL -Wnonnull) # C only
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_MISSING_INCLUDE_DIRS -Wmissing-include-dirs)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_DIV_BY_ZERO -Wno-div-by-zero)
- ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_TYPE_LIMITS -Wtype-limits)
# gcc 4.2 gives annoying warnings on every file with this
if(NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "4.3")
@@ -2533,8 +2565,7 @@ if(CMAKE_COMPILER_IS_GNUCC)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_INIT_SELF -Winit-self) # needs -Wuninitialized
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_MISSING_INCLUDE_DIRS -Wmissing-include-dirs)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_DIV_BY_ZERO -Wno-div-by-zero)
- ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_TYPE_LIMITS -Wtype-limits)
-
+
# gcc 4.2 gives annoying warnings on every file with this
if(NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "4.3")
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_UNINITIALIZED -Wuninitialized)
@@ -2562,9 +2593,9 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
# strange, clang complains these are not supported, but then yses them.
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ALL -Wall)
- ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_DECLARATION_AFTER_STATEMENT -Werror=declaration-after-statement)
- ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_IMPLICIT_FUNCTION_DECLARATION -Werror=implicit-function-declaration)
- ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_RETURN_TYPE -Werror=return-type)
+# ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_DECLARATION_AFTER_STATEMENT -Werror=declaration-after-statement)
+# ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_IMPLICIT_FUNCTION_DECLARATION -Werror=implicit-function-declaration)
+# ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_RETURN_TYPE -Werror=return-type)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_AUTOLOGICAL_COMPARE -Wno-tautological-compare)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_UNKNOWN_PRAGMAS -Wno-unknown-pragmas)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_CHAR_SUBSCRIPTS -Wno-char-subscripts)
diff --git a/SConstruct b/SConstruct
index 00a95b0114b..a151d493a73 100644
--- a/SConstruct
+++ b/SConstruct
@@ -263,6 +263,7 @@ if 'blenderlite' in B.targets:
target_env_defs['WITH_BF_FLUID'] = False
target_env_defs['WITH_BF_OCEANSIM'] = False
target_env_defs['WITH_BF_SMOKE'] = False
+ target_env_defs['WITH_BF_MANTA'] = False
target_env_defs['WITH_BF_BOOLEAN'] = False
target_env_defs['WITH_BF_REMESH'] = False
target_env_defs['WITH_BF_PYTHON'] = False
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index b266602fa63..c4363b97c4a 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -510,6 +510,7 @@ macro(SETUP_BLENDER_SORTED_LIBS)
bf_render
bf_python
bf_python_ext
+# bf_python_manta # configured separately in source/creator/CMakeLists.txt
bf_python_mathutils
bf_python_bmesh
bf_freestyle
diff --git a/build_files/scons/tools/btools.py b/build_files/scons/tools/btools.py
index c5342d6f349..aa0631af9fe 100644
--- a/build_files/scons/tools/btools.py
+++ b/build_files/scons/tools/btools.py
@@ -171,6 +171,7 @@ def validate_arguments(args, bc):
'WITH_BF_REMESH',
'WITH_BF_OCEANSIM',
'WITH_BF_SMOKE',
+ 'WITH_BF_MANTA',
'WITH_BF_CXX_GUARDEDALLOC',
'WITH_BF_JEMALLOC', 'WITH_BF_STATICJEMALLOC', 'BF_JEMALLOC', 'BF_JEMALLOC_INC', 'BF_JEMALLOC_LIBPATH', 'BF_JEMALLOC_LIB', 'BF_JEMALLOC_LIB_STATIC',
'BUILDBOT_BRANCH',
@@ -288,6 +289,7 @@ def read_opts(env, cfg, args):
(BoolVariable('WITH_BF_REMESH', 'Build with remesh modifier', True)),
(BoolVariable('WITH_BF_OCEANSIM', 'Build with ocean simulation', False)),
(BoolVariable('WITH_BF_SMOKE', 'Build with smoke simulation', True)),
+ (BoolVariable('WITH_BF_MANTA', 'Build with Mantaflow Framework', True)),
('BF_PROFILE_FLAGS', 'Profiling compiler flags', ''),
(BoolVariable('WITH_BF_OPENAL', 'Use OpenAL if true', False)),
('BF_OPENAL', 'Base path for OpenAL', ''),
diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt
index 110c88f8e4a..0caa5e21782 100644
--- a/extern/CMakeLists.txt
+++ b/extern/CMakeLists.txt
@@ -30,6 +30,7 @@ add_subdirectory(colamd)
add_subdirectory(rangetree)
add_subdirectory(wcwidth)
add_subdirectory(libmv)
+#add_subdirectory(manta_pp)
if(WITH_BULLET)
if(NOT WITH_SYSTEM_BULLET)
diff --git a/extern/SConscript b/extern/SConscript
index 1f94f50507f..b02e705220c 100644
--- a/extern/SConscript
+++ b/extern/SConscript
@@ -11,6 +11,7 @@ SConscript(['colamd/SConscript'])
SConscript(['rangetree/SConscript'])
SConscript(['wcwidth/SConscript'])
SConscript(['libmv/SConscript'])
+#SConscript(['manta_pp/SConscript'])
if env['WITH_BF_GAMEENGINE']:
SConscript(['recastnavigation/SConscript'])
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index 0b290c617a5..57cf53af11c 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -193,6 +193,7 @@ static void makeAttribList(
* Maybe a command line flag is better... */
if (getenv("BLENDER_SOFTWAREGL")) {
attribs.push_back(NSOpenGLPFARendererID);
+
attribs.push_back(kCGLRendererGenericFloatID);
}
else {
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 65d371c8ca8..2914b36b9a7 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -1355,7 +1355,7 @@ GHOST_TSuccess GHOST_WindowCocoa::endProgressBar()
// With OSX 10.8 and later, we can use notifications to inform the user when the progress reached 100%
// Atm. just fire this when the progressbar ends, the behavior is controlled in the NotificationCenter
// If Blender is not frontmost window, a message pops up with sound, in any case an entry in notifications
-
+
if ([NSUserNotificationCenter respondsToSelector:@selector(defaultUserNotificationCenter)]) {
postNotification();
}
diff --git a/intern/smoke/CMakeLists.txt b/intern/smoke/CMakeLists.txt
index 8cda0fd140f..54b4da4c369 100644
--- a/intern/smoke/CMakeLists.txt
+++ b/intern/smoke/CMakeLists.txt
@@ -26,13 +26,16 @@
set(INC
intern
../memutil
+ ../../source/blender/blenlib
)
set(INC_SYS
${BULLET_INCLUDE_DIRS}
${PNG_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
+ ${PYTHON_INCLUDE_DIRS}
)
+add_definitions(-DWITH_PYTHON)
set(SRC
intern/EIGENVALUE_HELPER.cpp
@@ -59,6 +62,10 @@ set(SRC
intern/VEC3.h
intern/WAVELET_NOISE.h
intern/WTURBULENCE.h
+ intern/MANTA.h
+ intern/MANTA.cpp
+ intern/scenarios/smoke.h
+
intern/tnt/jama_eig.h
intern/tnt/jama_lu.h
intern/tnt/tnt.h
diff --git a/intern/smoke/extern/smoke_API.h b/intern/smoke/extern/smoke_API.h
index 08dbded176e..11bb26eb6ca 100644
--- a/intern/smoke/extern/smoke_API.h
+++ b/intern/smoke/extern/smoke_API.h
@@ -35,10 +35,11 @@
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);
+struct FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, int use_fire, int use_colors, struct SmokeModifierData *smd);
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,
@@ -65,19 +66,20 @@ void smoke_get_ob_velocity(struct FLUID_3D *fluid, float **x, float **y, float *
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);
+
+int *smoke_get_manta_flags(struct FLUID_3D *fluid);
+float *smoke_get_inflow_grid(struct FLUID_3D *fluid);
+void smoke_manta_export(struct SmokeModifierData *smd);
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);
+struct WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors,struct SmokeDomainSettings *sds);
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);
@@ -92,27 +94,32 @@ 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);
-
/* flame spectrum */
void flame_get_spectrum(unsigned char *spec, int width, float t1, float t2);
-
/* 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);
+
+ /*Mantaflow functions*/
+int smoke_mantaflow_read(struct SmokeDomainSettings *sds, char* name, bool with_wavelets); //1:success, 0: no file,error
+void smoke_mantaflow_stop_sim(struct Manta_API *fluid);
+void manta_write_effectors(struct FLUID_3D *fluid);
+void manta_update_effectors(struct Scene *scene, struct Object *ob,struct SmokeDomainSettings *sds, float dt);
+void manta_write_emitters(struct SmokeFlowSettings *sfs, bool highRes, int min_x, int min_y, int min_z, int max_x, int max_y, int max_z, int d_x, int d_y, int d_z,float *influence, float *vel);
+void manta_export_obstacles(float * influence, int x, int y, int z);
+ int cell_index_3D(int index_2d,int sizex,int sizey, int sizez); /*For 2D sims only: transforms 2D manta cell index into 3D Blender index*/
#ifdef __cplusplus
}
#endif
diff --git a/intern/smoke/intern/BASIC_FLUID.cpp b/intern/smoke/intern/BASIC_FLUID.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/intern/smoke/intern/BASIC_FLUID.cpp
diff --git a/intern/smoke/intern/FLUID_3D.cpp b/intern/smoke/intern/FLUID_3D.cpp
index 4faec894801..a55ab8785c8 100644
--- a/intern/smoke/intern/FLUID_3D.cpp
+++ b/intern/smoke/intern/FLUID_3D.cpp
@@ -35,11 +35,15 @@
#include <zlib.h>
#include "float.h"
-
+#include "MANTA.h"
+#include "scenarios/smoke.h"
+#include <iostream>
+#include <fstream>
#if PARALLEL==1
#include <omp.h>
#endif // PARALLEL
+#ifndef WITH_MANTA
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
@@ -167,30 +171,6 @@ void FLUID_3D::initHeat()
}
}
-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) {
@@ -216,47 +196,6 @@ void FLUID_3D::initColors(float init_r, float init_g, float init_b)
}
}
-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()
{
@@ -514,14 +453,355 @@ void FLUID_3D::step(float dt, float gravity[3])
}
+/*===============================================================================================*/
+/*===============================================================================================*/
+#else /*USING MANTAFLOW STRUCTURES*/
+/*===============================================================================================*/
+/*===============================================================================================*/
-// Set border collision model from RNA setting
+FLUID_3D::FLUID_3D(int *res, float dx, float dtdef, int init_heat, int init_fire, int init_colors, SmokeModifierData *smd) :
+_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];
+ /*if two-dimentional, insert manta sim into blender _density field */
+ if (smd->domain->manta_solver_res == 2){
+ _density = new float[_totalCells];
+ _manta_flags = new int[_totalCells];
+ manta_resoution = 2;
+ _yLocation = _yRes / 2;
+ }
+ else{
+ _density = NULL;
+ _manta_flags = NULL;
+ manta_resoution = 3;
+ _yLocation = -1;
+ }
+ _manta_inflow = NULL;
+ _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];
+
+ //initializing manta flag grids
+ // DG TODO: check if alloc went fine
+
+ for (int x = 0; x < _totalCells; x++)
+ {
+ _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;
+ using_heat = false;
+ 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;
+ using_colors = false;
+ 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
+
+ string smoke_script = "";
+ if (smd->domain->flags & MOD_SMOKE_MANTA_USE_LIQUID)
+ smoke_script = smoke_setup_low + liquid_step_low;
+ else
+ smoke_script = smoke_setup_low + smoke_step_low;
+ smd->domain->fluid = this;
+ std::string final_script = Manta_API::parseScript(smoke_script, smd);
+ ofstream myfile;
+ cout<< "INITIALIZING SMOKE" << endl;
+ myfile.open ("manta_scene.py");
+ myfile << final_script;
+ myfile.close();
+ vector<string> a;
+ a.push_back("manta_scene.py");
+ runMantaScript(final_script,a); /*need this to delete previous solvers and grids*/
+ Manta_API::updatePointers(this, using_colors);
+}
-void FLUID_3D::setBorderCollisions() {
+void FLUID_3D::initHeat()
+{
+ if (!_heat) {
+ _heat = NULL;
+ _heatOld = new float[_totalCells];
+ _heatTemp = new float[_totalCells];
+
+ for (int x = 0; x < _totalCells; x++)
+ {
+ _heatOld[x] = 0.0f;
+ }
+ using_heat = true;
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ PyRun_SimpleString(smoke_init_heat_low.c_str());
+ PyGILState_Release(gilstate);
+ Manta_API::updatePointers(this, using_colors);
+ }
+}
- _colloPrev = *_borderColli; // saving the current value
+void FLUID_3D::initColors(float init_r, float init_g, float init_b)
+{
+ if (!_color_r){
+ using_colors = true;
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ stringstream ss;
+ ss << "manta_color_r = " << init_r << endl;
+ ss << "manta_color_g = " << init_g << endl;
+ ss << "manta_color_b = " << init_b << endl;
+ PyRun_SimpleString(ss.str().c_str());
+ PyRun_SimpleString(smoke_init_colors_low.c_str());
+ PyGILState_Release(gilstate);
+ Manta_API::updatePointers(this, true);
+ }
+}
+
+
+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 (_densityOld) delete[] _densityOld;
+ 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])
+{
+ // BLender computes heat buoyancy, not yet impl. in Manta
+ manta_write_effectors(this);
+ Manta_API::updatePointers(this,using_colors);
+// diffuseHeat();
+
+ int sim_frame = 1;
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ std::string frame_str = static_cast<ostringstream*>( &(ostringstream() << sim_frame) )->str();
+ std::string py_string_0 = string("sim_step_low(").append(frame_str);
+ std::string py_string_1 = py_string_0.append(")\0");
+ PyRun_SimpleString(py_string_1.c_str());
+ cout<< "done"<<manta_sim_running<<endl;
+ PyGILState_Release(gilstate);
+ Manta_API::updatePointers(this,using_colors);
+ for (int i = 0; i < _totalCells; i++)
+ {
+ _xForce[i] = _yForce[i] = _zForce[i] = 0.0f;
+ }
+
+}
+#endif /*WITH_MANTA*/
+
+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::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;
+ }
+}
+
+
+
+// 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)
{
@@ -544,13 +824,13 @@ void FLUID_3D::setBorderCollisions() {
_domainBcTop = false;
_domainBcLeft = true;
}
-
+
_domainBcBack = _domainBcFront;
_domainBcBottom = _domainBcTop;
_domainBcRight = _domainBcLeft;
-
-
-
+
+
+
// set side obstacles
setBorderObstacles();
}
@@ -563,55 +843,55 @@ void FLUID_3D::setBorderCollisions() {
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] );
-
+ _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] );
-
+ _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] );
+ _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] );
-
+ _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] );
-
+ _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] );
+ _zVelocityTemp[index+1] + _zVelocityTemp[index-1] +
+ _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] +
+ _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] );
}
-
+
}
}
@@ -621,66 +901,66 @@ 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) {
+ 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
- */
+ * 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] );
-
+ _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] );
-
+ _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] );
+ _zVelocityTemp[index+1] + _zVelocityTemp[index-1] +
+ _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] +
+ _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] );
}
- }
-
- if(_totalSteps % 4 == 3) {
+ }
+
+ 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
- */
+ * 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] );
-
+ _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] );
-
+ _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] );
+ _zVelocityTemp[index+1] + _zVelocityTemp[index-1] +
+ _zVelocityTemp[index+_res[0]] + _zVelocityTemp[index-_res[0]] +
+ _zVelocityTemp[index+_slabSize] + _zVelocityTemp[index-_slabSize] );
}
-
- }
+
+ }
}
}
@@ -692,45 +972,45 @@ 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];
- }
-
+ 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 (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];
@@ -763,14 +1043,14 @@ 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++)
{
@@ -789,7 +1069,7 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
_color_g[index] = 0.0f;
_color_b[index] = 0.0f;
}
-
+
// right slab
index += _xRes - 1;
_xVelocity[index] = 0.0f;
@@ -806,11 +1086,11 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
_color_b[index] = 0.0f;
}
}
-
+
/////////////////////////////////////
// setZeroY
/////////////////////////////////////
-
+
for (z = zBegin; z < zEnd; z++)
for (x = 0; x < _xRes; x++)
{
@@ -829,7 +1109,7 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
_color_g[index] = 0.0f;
_color_b[index] = 0.0f;
}
-
+
// top slab
index += slabSize - _xRes;
_xVelocity[index] = 0.0f;
@@ -845,47 +1125,47 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
_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;
+ 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;
@@ -903,7 +1183,7 @@ void FLUID_3D::wipeBoundariesSL(int zBegin, int zEnd)
}
}
}
-
+
}
//////////////////////////////////////////////////////////////////////
// add forces to velocity field
@@ -912,7 +1192,7 @@ 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];
@@ -927,10 +1207,10 @@ 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);
@@ -940,13 +1220,13 @@ void FLUID_3D::project()
// 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)
@@ -960,44 +1240,44 @@ void FLUID_3D::project()
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 );
-
+ 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);
-
+
// 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;
@@ -1008,7 +1288,7 @@ void FLUID_3D::project()
{
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
@@ -1016,7 +1296,7 @@ void FLUID_3D::project()
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?
@@ -1026,11 +1306,11 @@ void FLUID_3D::project()
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];
@@ -1042,10 +1322,10 @@ void FLUID_3D::project()
_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;
}
@@ -1057,57 +1337,57 @@ 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)
+ if (!_obstacles[index])
{
- // printf("velocity y!\n");
- _yVelocity[index] = _yVelocityOb[index - _xRes];
- _yVelocity[index - _xRes] = _yVelocityOb[index - _xRes];
+ // 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];
+ }
}
- // if(_obstacles[index+_slabSize]) ztop = - _zVelocityOb[index];
- if((_obstacles[index - _slabSize] & 8) && abs(_zVelocityOb[index - _slabSize]) > FLT_EPSILON)
+ else
{
- // printf("velocity z!\n");
- _zVelocity[index] = _zVelocityOb[index - _slabSize];
- _zVelocity[index - _slabSize] = _zVelocityOb[index - _slabSize];
+ _density[index] = 0;
}
- }
- else
- {
- _density[index] = 0;
- }
- //vIndex++;
- } // x loop
- //vIndex += 2;
+ //vIndex++;
+ } // x loop
+ //vIndex += 2;
} // y loop
//vIndex += 2 * _xRes;
} // z loop
@@ -1119,10 +1399,10 @@ void FLUID_3D::setObstacleVelocity(int zBegin, int zEnd)
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])
@@ -1140,7 +1420,7 @@ void FLUID_3D::addObstacle(OBSTACLE* obstacle)
for (int x = 0; x < _xRes; x++, index++)
if (obstacle->inside(x * _dx, y * _dx, z * _dx)) {
_obstacles[index] = true;
- }
+ }
}
//////////////////////////////////////////////////////////////////////
@@ -1148,88 +1428,88 @@ void FLUID_3D::addObstacle(OBSTACLE* obstacle)
//////////////////////////////////////////////////////////////////////
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;
+ // 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
}
-
- 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;
+ //vIndex++;
+ } // x loop
+ //vIndex += 2;
} // y loop
//vIndex += 2 * _xRes;
} // z loop
@@ -1238,16 +1518,16 @@ void FLUID_3D::setObstaclePressure(float *_pressure, int zBegin, int zEnd)
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;
@@ -1264,7 +1544,7 @@ void FLUID_3D::setObstacleBoundaries(float *_pressure, int zBegin, int zEnd)
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++;
@@ -1272,7 +1552,7 @@ void FLUID_3D::setObstacleBoundaries(float *_pressure, int zBegin, int zEnd)
if (right) counter++;
if (top) counter++;
if (bottom) counter++;
-
+
if (counter < 3)
_obstacles[index] = EMPTY;
}
@@ -1297,7 +1577,7 @@ void FLUID_3D::setObstacleBoundaries(float *_pressure, int zBegin, int zEnd)
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++)
@@ -1314,7 +1594,7 @@ void FLUID_3D::addBuoyancy(float *heat, float *density, float gravity[3], int zB
// 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)]])
+((_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)
{
@@ -1322,54 +1602,54 @@ void FLUID_3D::addVorticity(int zBegin, int zEnd)
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++)
@@ -1377,43 +1657,43 @@ void FLUID_3D::addVorticity(int zBegin, int zEnd)
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]);
-
+ _yVorticity[vIndex] * _yVorticity[vIndex] +
+ _zVorticity[vIndex] * _zVorticity[vIndex]);
+
}
vIndex++;
}
@@ -1421,44 +1701,44 @@ void FLUID_3D::addVorticity(int zBegin, int zEnd)
}
//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)
{
@@ -1467,19 +1747,19 @@ void FLUID_3D::addVorticity(int zBegin, int zEnd)
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
+ vIndex++;
+ } // x loop
+ vIndex+=2;
+ } // y loop
+ //vIndex+=2*_xRes;
+ } // z loop
+
if (_xVorticity) delete[] _xVorticity;
if (_yVorticity) delete[] _yVorticity;
if (_zVorticity) delete[] _zVorticity;
@@ -1490,7 +1770,7 @@ void FLUID_3D::addVorticity(int zBegin, int zEnd)
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);
@@ -1502,16 +1782,16 @@ void FLUID_3D::advectMacCormackBegin(int zBegin, int zEnd)
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);
@@ -1528,7 +1808,7 @@ void FLUID_3D::advectMacCormackEnd1(int zBegin, int 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
}
@@ -1539,12 +1819,12 @@ 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) {
@@ -1562,17 +1842,17 @@ void FLUID_3D::advectMacCormackEnd2(int zBegin, int 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) {
@@ -1594,7 +1874,7 @@ void FLUID_3D::processBurn(float *fuel, float *smoke, float *react, float *heat,
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];
@@ -1613,7 +1893,7 @@ void FLUID_3D::processBurn(float *fuel, float *smoke, float *react, float *heat,
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;
diff --git a/intern/smoke/intern/FLUID_3D.h b/intern/smoke/intern/FLUID_3D.h
index cd2147b2bee..b0fab50b843 100644
--- a/intern/smoke/intern/FLUID_3D.h
+++ b/intern/smoke/intern/FLUID_3D.h
@@ -46,7 +46,7 @@ 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(int *res, float dx, float dtdef, int init_heat, int init_fire, int init_colors, struct SmokeModifierData *smd);
FLUID_3D() {};
virtual ~FLUID_3D();
@@ -112,6 +112,10 @@ struct FLUID_3D
float* _zForce;
unsigned char* _obstacles; /* only used (useful) for static obstacles like domain boundaries */
unsigned char* _obstaclesAnim;
+ float* _manta_inflow;
+ bool using_heat;
+ int manta_resoution;
+ int _yLocation;/*at which Y-coordinate store the information*/
// Required for proper threading:
float* _xVelocityTemp;
@@ -139,8 +143,9 @@ struct FLUID_3D
float *_color_b;
float *_color_bOld;
float *_color_bTemp;
+ bool using_colors;
-
+ int *_manta_flags;
// CG fields
int _iterations;
diff --git a/intern/smoke/intern/MANTA.cpp b/intern/smoke/intern/MANTA.cpp
new file mode 100644
index 00000000000..6772fb44759
--- /dev/null
+++ b/intern/smoke/intern/MANTA.cpp
@@ -0,0 +1,666 @@
+#include "MANTA.h"
+#include "WTURBULENCE.h"
+#include "scenarios/smoke.h"
+
+extern "C" bool manta_check_grid_size(struct FLUID_3D *fluid, int dimX, int dimY, int dimZ)
+{
+ /*Y and Z axes are swapped in manta and blender*/
+ if (!(dimX == fluid->xRes() && dimY == fluid->yRes() && dimZ == fluid->zRes())) {
+ for (int cnt(0); cnt < fluid->_totalCells; cnt++)
+ fluid->_density[cnt] = 0.0f;
+ return false;
+ }
+ return true;
+}
+
+extern "C" bool manta_check_wavelets_size(struct WTURBULENCE *wt, int dimX, int dimY, int dimZ)
+{
+ /*Y and Z axes are swapped in manta and blender*/
+ if (!(dimX == wt->_xResBig && dimY == wt->_yResBig && dimZ == wt->_zResBig)) {
+ for (int cnt(0); cnt < wt->_totalCellsBig; cnt++)
+ wt->_densityBig[cnt] = 0.0f;
+ return false;
+ }
+ return true;
+}
+
+void read_rotated_grid(gzFile gzf, float *data, int size_x, int size_y, int size_z)
+{
+ assert(size_x > 1 && size_y > 1 && size_z > 1);
+ float* temp_data = (float*)malloc(sizeof(float) * size_x * size_y * size_z);
+// data = (float*)malloc(sizeof(float) * size_x * size_y * size_z);
+ gzread(gzf, temp_data, sizeof(float)* size_x * size_y * size_z);
+ for (int cnt_x(0); cnt_x < size_x; ++cnt_x)
+{
+ for (int cnt_y(0); cnt_y < size_y; ++cnt_y)
+ {
+ for (int cnt_z(0); cnt_z < size_z; ++cnt_z)
+ {
+ data[cnt_x + size_x * cnt_y + size_x*size_y * cnt_z] = temp_data[cnt_x + size_x * cnt_y + size_x*size_y * cnt_z];
+ }
+ }
+ }
+}
+
+static void wavelets_add_lowres_density(SmokeDomainSettings *sds)
+{
+ assert(sds != NULL);
+ for (int cnt_x(0); cnt_x < sds->wt->_xResBig; ++cnt_x)
+ {
+ for (int cnt_y(0); cnt_y < sds->wt->_yResBig; ++cnt_y)
+ {
+ for (int cnt_z(0); cnt_z < sds->wt->_zResBig; ++cnt_z)
+ {
+ //scale down to domain res
+ float x_sc = 1. * sds->base_res[0] * cnt_x / sds->wt->_xResBig;
+ float y_sc = 1. * sds->base_res[1] * cnt_y / sds->wt->_yResBig;
+ float z_sc = 1. * sds->base_res[2] * cnt_z / sds->wt->_zResBig;
+ //finding cells to interpolate from
+ int start_x = int(x_sc / 1);
+ int start_y = int(y_sc / 1);
+ int start_z = int(z_sc / 1);
+ int end_x = ((x_sc - start_x > 0.001) && (start_x + 1 < sds->base_res[0]))? start_x + 1: start_x;
+ int end_y = ((y_sc - start_y > 0.001) && (start_y + 1 < sds->base_res[1]))? start_y + 1: start_y;
+ int end_z = ((z_sc - start_z > 0.001) && (start_z + 1 < sds->base_res[2]))? start_z + 1: start_z;
+ //interpolation
+ float add_value = 0;
+ int cnt=0;
+ for(int x(start_x); x <= end_x; ++x)
+ {
+ for(int y(start_y); y <= end_y; ++y)
+ {
+ for(int z(start_z); z <= end_z; ++z)
+ {
+ cnt++;
+ add_value += sds->fluid->_density[x + y*sds->base_res[0] + z * sds->base_res[0]*sds->base_res[1]];
+ }
+ }
+ }
+ add_value /= float(cnt);
+ sds->wt->_densityBig[cnt_x + cnt_y *sds->wt->_xResBig + cnt_z*sds->wt->_xResBig*sds->wt->_yResBig] += add_value;
+ }
+ }
+ }
+}
+
+//PR need SMD data here for wavelets
+extern "C" int read_mantaflow_sim(struct SmokeDomainSettings *sds, char *name, bool reading_wavelets)
+{
+ /*! l /*! 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;
+
+ /* uni file header - currently used */
+ typedef struct {
+ int dimX, dimY, dimZ;
+ int gridType, elementType, bytesPerElement;
+ char info[256]; /* mantaflow build information */
+ unsigned long long timestamp; /* creation time */
+ } UniHeader;
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name, "rb");
+// if (!gzf) {
+// if(reading_wavelets){
+// for (int cnt(0); cnt < sds->wt->_totalCellsBig; cnt++)
+// sds->wt->_densityBig[cnt] = 0.0f;
+// }
+// else{
+// for (int cnt(0); cnt < sds->fluid->_totalCells; cnt++)
+// sds->fluid->_density[cnt] = 0.0f;
+// }
+// return 0;
+// }
+
+ char ID[5] = {0,0,0,0,0};
+ gzread(gzf, ID, 4);
+ /* legacy file format */
+ if (!strcmp(ID, "DDF2")) {
+ UniLegacyHeader head;
+ gzread(gzf, &head, sizeof(UniLegacyHeader));
+ int numEl = head.dimX*head.dimY*head.dimZ;
+ gzseek(gzf, numEl, SEEK_CUR);
+ /* actual grid read */
+ if ( ! reading_wavelets){
+// if (!manta_check_grid_size(sds->fluid, head.dimX, head.dimY, head.dimZ)) return 0;
+ gzread(gzf, sds->fluid->_density, sizeof(float)*numEl);
+ }
+ else {
+ if (!manta_check_wavelets_size(sds->wt, head.dimX, head.dimY, head.dimZ)) return 0;
+ gzread(gzf, sds->wt->_densityBig, sizeof(float)*numEl);
+ }
+ }
+ /* legacy file format 2 */
+ else if (!strcmp(ID, "MNT1")) {
+ UniLegacyHeader2 head;
+ gzread(gzf, &head, sizeof(UniLegacyHeader2));
+ /* actual grid read*/
+ if ( ! reading_wavelets){
+// if (!manta_check_grid_size(sds->fluid, head.dimX, head.dimY, head.dimZ)) return 0;
+ gzread(gzf, sds->fluid->_density, sizeof(float)*head.dimX*head.dimY*head.dimZ);
+ }
+ else{
+ if (!manta_check_wavelets_size(sds->wt, head.dimX, head.dimY, head.dimZ)) return 0;
+ gzread(gzf, sds->wt->_densityBig, sizeof(float)*head.dimX*head.dimY*head.dimZ);
+ }
+ }
+ /* current file format*/
+ else if (!strcmp(ID, "MNT2")) {
+ UniHeader head;
+ gzread(gzf, &head, sizeof(UniHeader));
+ /* actual grid read */
+ if ( ! reading_wavelets){
+// if (!manta_check_grid_size(sds->fluid, head.dimX, head.dimY, head.dimZ)) return 0;
+ /*Y and Z axes are swapped in manta and blender*/
+ gzread(gzf,sds->fluid->_density, sizeof(float)*head.dimX*head.dimY*head.dimZ);
+
+ }
+ else{
+ if (!manta_check_wavelets_size(sds->wt, head.dimX, head.dimY, head.dimZ)) return 0;
+ /*Y and Z axes are swapped in manta and blender*/
+ gzread(gzf,sds->wt->_densityBig, sizeof(float)*head.dimX*head.dimY*head.dimZ);
+ gzread(gzf,sds->wt->_densityBigOld, sizeof(float)*head.dimX*head.dimY*head.dimZ);
+// wavelets_add_lowres_density(sds);
+ }
+ }
+ gzclose(gzf);
+ return 1;
+# endif /*zlib*/
+ return 0;
+}
+
+
+void Manta_API::indent_ss(stringstream& ss, int indent)
+{
+ /*two-spaces indent*/
+ if (indent < 0) return;
+ std::string indentation = "";
+ for (size_t cnt(0); cnt < indent; ++cnt) {
+ indentation += " ";
+ }
+ ss << indentation;
+}
+
+void Manta_API::manta_gen_noise(stringstream& ss, char* solver, int indent, char *noise, int seed, bool load, bool clamp, float clampNeg, float clampPos, float valScale, float valOffset, float timeAnim)
+{
+ if (ss == NULL)/*should never be here*/
+ {
+ return;
+ }
+ indent_ss(ss, indent);
+ ss << noise << " = "<<solver<<".create(NoiseField, fixedSeed=" << seed << ", loadFromFile="<< (load?"True":"False") <<") \n";
+ ss << noise << ".posScale = vec3(20) \n";
+ ss << noise << ".clamp = " << ((clamp)?"True":"False") << " \n";
+ ss << noise << ".clampNeg = " << clampNeg << " \n";
+ ss << noise << ".clampPos = " << clampPos << " \n";
+ ss << noise << ".valScale = " << valScale << " \n";
+ ss << noise << ".valOffset = " << valOffset << " \n";
+ ss << noise << ".timeAnim = " << timeAnim << " \n";
+}
+
+void Manta_API::manta_solve_pressure(stringstream& ss, char *flags, char *vel, char *pressure, bool useResNorms, int openBound, int solver_res,float cgMaxIterFac, float cgAccuracy)
+{
+ /*open:0 ; vertical : 1; closed:2*/
+ ss << " solvePressure(flags=" << flags << ", vel=" << vel << ", pressure=" << pressure << ", useResNorm=" << (useResNorms?"True":"False") << ", openBound='";
+
+ if(openBound == 1) /*vertical*/
+ {
+ ss << "yY'";
+ }
+ else if (openBound == 0) /*open*/
+ {
+ if(solver_res == 2)
+ ss << "xXyY";
+ else
+ ss << "xXyYzZ";
+ }
+ ss << "'"; /*empty for closed bounds*/
+
+ ss << ", cgMaxIterFac=" << cgMaxIterFac << ", cgAccuracy=" << cgAccuracy << ") \n";
+}
+
+void Manta_API::manta_advect_SemiLagr(stringstream& ss, int indent, char *flags, char *vel, char *grid, int order)
+{
+ if((order <=1) || (flags == NULL) || (vel == NULL) || (grid == NULL)){return;}
+ indent_ss(ss, indent);
+ ss << "advectSemiLagrange(flags=" << flags << ", vel=" << vel \
+ << ", grid=" << grid << ", order=" << order << ") \n";
+}
+
+/*create solver, handle 2D case*/
+void Manta_API::manta_create_solver(stringstream& ss, char *name, char *nick, char *grid_size_name, int x_res, int y_res, int z_res, int dim)
+{
+ if ((dim != 2) && (dim != 3))
+ { return; }
+ if (dim == 2)
+ { y_res = 1; }
+ ss << grid_size_name << " = vec3(" << x_res << ", " << y_res << ", " << z_res << ")" << " \n";
+ ss << name << " = Solver(name = '" << nick << "', gridSize = " << grid_size_name << ", dim = " << dim << ") \n";
+}
+
+inline bool file_exists (const std::string& name) {
+ return ( access( name.c_str(), F_OK ) != -1 );
+}
+
+/*blender transforms obj coords to [-1,1]. This method transforms them back*/
+void Manta_API::add_mesh_transform_method(stringstream& ss)
+{
+ ss << "def transform_back(obj, gs):\n" <<
+ " obj.scale(gs/2)\n" <<
+ " obj.offset(gs/2)\n\n";
+}
+
+void Manta_API::manta_cache_path(char *filepath)
+{
+ char *name="manta";
+ BLI_make_file_string("/", filepath, BLI_temp_dir_session(), name);
+}
+
+void Manta_API::stop_manta_sim()
+{
+ pthread_cancel(manta_thread);
+}
+
+string Manta_API::gridNameFromType(const string &type)
+{
+ if (type == "float")
+ {
+ return "RealGrid";
+ }
+ else if (type == "Vec3")
+ {
+ return "MACGrid";
+ }
+ else
+ {
+ cout<<"ERROR: can not create grid from type: "<< type << endl;
+ return "";
+ }
+}
+
+void Manta_API::addGrid(void * data, string name, string type, int x, int y, int z, bool is2D = false)
+{
+ if (data == NULL || name == "" || gridNameFromType(type) == "") return;
+ cout << "Adding Grid:" << name<<endl;
+ std::ostringstream stringStream;
+ stringStream << "temp_" << name;
+ std::string grid_name = stringStream.str();
+ stringStream.str("");
+ stringStream << grid_name << " = s.create(" << gridNameFromType(type) << ")";
+ const std::string command_1 = stringStream.str();
+ stringStream.str("");
+ if (is2D){
+ /*for 2D case, Y and Z axes are switched, Y axis is '1' for Mantaflow*/
+ stringStream << grid_name << ".readGridFromMemory(\'"<< data << "\', " << x << "," << z << "," << 1 << ")";
+ }
+ else{
+ stringStream << grid_name << ".readGridFromMemory(\'"<< data << "\', " << x << "," << y << "," << z << ")";
+ }
+ const std::string command_2 = stringStream.str();
+ const std::string command_3 = name + ".add(" + grid_name + ")";
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ PyRun_SimpleString(command_1.c_str());
+ PyRun_SimpleString(command_2.c_str());
+ PyRun_SimpleString(command_3.c_str());
+ PyGILState_Release(gilstate);
+}
+
+void Manta_API::addAdaptiveGrid(void * data, string gridName, string solverName, string type, int minX, int minY, int minZ, int maxX, int maxY, int maxZ, bool is2D = false)
+{
+ if (data == NULL || gridName == "" || gridNameFromType(type) == "") return;
+ {
+ cout << "NULL values passed to grid addAdaptiveGrid for grid " << gridName <<endl;
+ return;
+ }
+ std::ostringstream stringStream;
+ stringStream << "temp_" <<gridName;
+ std::string temp_grid_name = stringStream.str();
+ stringStream.str("");
+ stringStream << temp_grid_name << " = "<< solverName << ".create(" << gridNameFromType(type) << ")";
+ const std::string command_1 = stringStream.str();
+ stringStream.str("");
+
+ if (is2D){
+ stringStream << temp_grid_name << ".readAdaptiveGridFromMemory(\'"<< data << "\', vec3(" << minX << "," << minZ << "," << 1 <<
+ "), vec3(" << maxX << "," << maxZ << "," << 1 << ") )";
+ }
+ else{
+ stringStream << temp_grid_name << ".readAdaptiveGridFromMemory(\'"<< data << "\', vec3(" << minX << "," << minY << "," << minZ <<
+ "), vec3(" << maxX << "," << maxY << "," << maxZ << ") )";
+ }
+ const std::string command_2 = stringStream.str();
+ const std::string command_3 = gridName + ".add(" + temp_grid_name + ")";
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ PyRun_SimpleString("print('Reading Adaptive grid from memory')");
+ PyRun_SimpleString("print (s)");
+ PyRun_SimpleString(command_1.c_str());
+ PyRun_SimpleString(command_2.c_str());
+ PyRun_SimpleString(command_3.c_str());
+ PyGILState_Release(gilstate);
+}
+
+void Manta_API::export_obstacles(float *data, int x, int y, int z, bool is2D = false)
+{
+ if (data == NULL){
+ cout << "NULL passed to grid export_obstacles " <<endl; return;
+ }
+ std::ostringstream stringStream;
+ std::string grid_name = "obs_sdf";
+ stringStream.str("");
+ stringStream << grid_name << " = s.create(RealGrid)";
+ const std::string command_1 = stringStream.str();
+ stringStream.str("");
+ cout<<"Exporting obstacles"<<endl;
+ if (is2D){
+ stringStream << grid_name << ".readGridFromMemory(\'"<< data << "\', " << x << "," << z << "," << 1 << ")";
+ }
+ else{
+ stringStream << grid_name << ".readGridFromMemory(\'"<< data << "\', " << x << "," << y << "," << z << ")";
+ }
+ const std::string command_2 = stringStream.str();
+ const std::string command_3 = grid_name + ".applyToGrid(grid = flags, value = FlagObstacle)";
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ PyRun_SimpleString(command_1.c_str());
+ PyRun_SimpleString(command_2.c_str());
+ PyRun_SimpleString(command_3.c_str());
+ PyGILState_Release(gilstate);
+}
+
+void Manta_API::run_manta_sim_highRes(WTURBULENCE *wt)
+{
+ if (wt == NULL){
+ cout << "ERROR: cannot run wt step, wt object is NULL " <<endl; return;
+ }
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ int sim_frame = 1;
+// manta_write_effectors(fluid);
+ std::string frame_str = static_cast<ostringstream*>( &(ostringstream() << sim_frame) )->str();
+ std::string py_string_0 = string("sim_step_high(").append(frame_str);
+ std::string py_string_1 = py_string_0.append(")\0");
+ cout << "Debug C++: densityPointer:" << Manta_API::getGridPointer("density", "s")<<endl;
+ PyRun_SimpleString("print ('pyhton density pointer:' + density.getDataPointer())");
+ PyRun_SimpleString(py_string_1.c_str());
+ cout<< "done"<<manta_sim_running<<endl;
+ PyGILState_Release(gilstate);
+ updateHighResPointers(wt,false);
+}
+
+void Manta_API::generate_manta_sim_file_highRes(SmokeModifierData *smd)
+{
+ string smoke_script = smoke_setup_high + smoke_step_high;
+ std::string final_script = parseScript(smoke_script, smd);
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ PyRun_SimpleString(final_script.c_str());
+ PyGILState_Release(gilstate);
+}
+
+std::string Manta_API::getRealValue( const std::string& varName, SmokeModifierData *smd)
+{
+ ostringstream ss;
+ bool is2D = smd->domain->fluid->manta_resoution == 2;
+ if (varName == "UVS_CNT")
+ ss << smd->domain->manta_uvs_num ;
+ else if (varName == "UPRES")
+ ss << smd->domain->amplify+1;
+ else if (varName == "WLT_STR")
+ ss << smd->domain->strength ;
+ else if (varName == "RES")
+ ss << smd->domain->maxres;
+ else if (varName == "RESX")
+ ss << smd->domain->fluid->_xRes;
+
+ else if (varName == "RESY")
+ if (is2D){ ss << smd->domain->fluid->_zRes;}
+ else{ ss << smd->domain->fluid->_yRes;}
+
+ else if (varName == "RESZ")
+ if (is2D){ ss << 1;}
+ else{ ss << smd->domain->fluid->_zRes;}
+
+ else if (varName == "SOLVER_DIM")
+ ss << smd->domain->manta_solver_res;
+ else if (varName == "NOISE_CN")
+ ss << smd->domain->noise_clamp_neg;
+ else if (varName == "NOISE_CP")
+ ss << smd->domain->noise_clamp_pos;
+ else if (varName == "NOISE_VALSCALE")
+ ss << smd->domain->noise_val_scale;
+ else if (varName == "NOISE_VALOFFSET")
+ ss << smd->domain->noise_val_offset;
+ else if (varName == "NOISE_TIMEANIM")
+ ss << smd->domain->noise_time_anim;
+ else if (varName == "HRESX")
+ ss << smd->domain->wt->getResBig()[0];
+ else if (varName == "HRESY")
+ if (is2D){ ss << smd->domain->wt->getResBig()[2];}
+ else{ ss << smd->domain->wt->getResBig()[1];}
+
+ else if (varName == "HRESZ")
+ if (is2D){ ss << 1;}
+ else{ ss << smd->domain->wt->getResBig()[2];}
+
+ else if (varName == "TIMESTEP")
+ ss << smd->domain->time_scale * 0.1f;
+ else if (varName == "XL_TIMESTEP")
+ ss << smd->domain->time_scale * 0.1f;
+ else if (varName == "USE_WAVELETS")
+ ss << (smd->domain->flags & MOD_SMOKE_HIGHRES)?"True":"False";
+ else if (varName == "BUYO_X")
+ ss << 0.;
+ else if (varName == "BUYO_Y")
+ ss << 0.;
+ else if (varName == "BUYO_Z")
+ ss << (-smd->domain->beta);
+ else if (varName == "ALPHA")
+ ss << (-smd->domain->alpha);
+ else if (varName == "BETA")
+ ss << (-smd->domain->beta);
+ else if (varName == "ADVECT_ORDER")
+ ss << 2;
+ else if (varName == "MANTA_EXPORT_PATH"){
+ char parent_dir[1024];
+ BLI_split_dir_part(smd->domain->_manta_filepath, parent_dir, sizeof(parent_dir));
+ ss << parent_dir;
+ }
+ else if (varName == "VORTICITY"){
+ cout << "Vorticity :" << smd->domain->vorticity / smd->domain->fluid->_constantScaling << endl;
+ ss << smd->domain->vorticity / smd->domain->fluid->_constantScaling;
+ }else if (varName == "BOUNDCONDITIONS"){
+ if(smd->domain->border_collisions == SM_BORDER_OPEN) ss << "xXyY";
+ else if (smd->domain->border_collisions == SM_BORDER_VERTICAL) ss << "xXyY";
+ else if (smd->domain->border_collisions == SM_BORDER_CLOSED) ss << "xXyY";
+
+ if (smd->domain->manta_solver_res == 3){
+ if(smd->domain->border_collisions == SM_BORDER_OPEN) ss << "z";
+ else if (smd->domain->border_collisions == SM_BORDER_VERTICAL) ss << "z";
+ else if (smd->domain->border_collisions == SM_BORDER_CLOSED) ss << "zZ";
+ }
+ }
+ else if (varName == "GRAVITY")
+ ss << "vec3(0,0,-0.981)";
+ else if (varName == "ABS_FLOW")
+ ss << (smd->flow->flags & MOD_SMOKE_FLOW_ABSOLUTE)?"True":"False";
+ else if (varName == "DENSITY_MEM")
+ ss << smd->domain->fluid->_density;
+ else if (varName == "DENSITY_SIZE")
+ ss << sizeof(float) * smd->domain->total_cells;
+ else if (varName == "XL_DENSITY_MEM")
+ ss << smd->domain->wt->_densityBig;
+ else if (varName == "XL_DENSITY_SIZE")
+ ss << sizeof(float) * smd->domain->wt->_xResBig * smd->domain->wt->_yResBig * smd->domain->wt->_zResBig;
+ else
+ cout<< "ERROR: Unknown option:"<< varName <<endl;
+ return ss.str();
+}
+
+std::string Manta_API::parseLine(const string& line, SmokeModifierData *smd)
+{
+ if (line.size() == 0) return "";
+ 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), smd);
+ }
+ currPos ++;
+ }
+ res += line.substr(end_del+1, line.size()- end_del);
+ return res;
+}
+
+std::string Manta_API::parseScript(const string & setup_string, SmokeModifierData *smd)
+{
+ std::istringstream f(setup_string);
+ ostringstream res;
+ string line="";
+ while(getline(f,line)){
+ res << parseLine(line,smd) << "\n";
+ }
+ return res.str();
+}
+
+void Manta_API::manta_export_grids(SmokeModifierData *smd){
+ std::string smoke_script;
+ if (smd->domain->flags & MOD_SMOKE_MANTA_USE_LIQUID)
+ smoke_script = smoke_setup_low + liquid_step_low;
+ else
+ smoke_script = smoke_setup_low + smoke_step_low;
+ std::string final_script = Manta_API::parseScript(smoke_script, smd) + standalone;
+ ofstream myfile;
+ myfile.open (smd->domain->_manta_filepath);
+ myfile << final_script;
+ myfile.close();
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ PyRun_SimpleString(Manta_API::parseScript(smoke_export_low,smd).c_str());
+ PyGILState_Release(gilstate);
+}
+
+string Manta_API::getGridPointer(std::string gridName, std::string solverName)
+{
+ if ((gridName == "") && (solverName == "")){
+ return "";
+ }
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ PyObject *main = PyImport_AddModule("__main__");
+ if (main == NULL){cout << "null" << 1 << endl;return "";}
+ PyObject *globals = PyModule_GetDict(main);
+ if (globals == NULL){cout << "null" << 12 << endl;return "";}
+ PyObject *grid_object = PyDict_GetItemString(globals, gridName.c_str());
+ if (grid_object == NULL){cout << "null" << 13 << endl;return "";}
+ PyObject* func = PyObject_GetAttrString(grid_object,(char*)"getDataPointer");
+ if (func == NULL){cout << "null" << 14 << endl;return "";}
+ PyObject* retured_value = PyObject_CallObject(func, NULL);
+ PyObject* encoded = PyUnicode_AsUTF8String(retured_value);
+ if (retured_value == NULL){cout << "null" << 15 << endl;return "";}
+ std::string res = strdup(PyBytes_AsString(encoded));
+ cout << "Pointer on "<< gridName << " " << res << endl;
+ PyGILState_Release(gilstate);
+ return res;
+}
+
+// init direct access functions from blender
+void Manta_API::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;
+}
+
+void * Manta_API::pointerFromString(const std::string& s){
+ stringstream ss(s);
+ void *gridPointer = NULL;
+ ss >> gridPointer;
+ return gridPointer;
+}
+
+
+void Manta_API::updatePointers(FLUID_3D *fluid, bool updateColor)
+{
+ //blender_to_manta: whether we copy data from blender density/velocity field to mantaflow or the other way around
+ /*in 2D case, we want to copy in the Z-axis field that is in the middle of X and Y axes */
+ //x + y * max_x + z * max_x*max_y
+// int position_to_copy_from(0 + (fluid->xRes()/2) * fluid->xRes() + (fluid->zRes()/2) * fluid->xRes()*fluid->yRes());
+// float *whereToCopy = &fluid->_density[position_to_copy_from];
+ if (fluid->manta_resoution == 2)
+ {
+ float* manta_fluid_density = (float* )pointerFromString(getGridPointer("density", "s"));
+ int* manta_fluid_flags = (int* )pointerFromString(getGridPointer("flags", "s"));
+ if (fluid->_density != NULL){
+ for (int cnt(0); cnt < fluid->xRes() * fluid->yRes() * fluid->zRes(); ++cnt){
+ fluid->_density[cnt] = 0.;
+ fluid->_manta_flags[cnt] = 2;
+ }
+ }
+ int step = 0;
+ for (int cnty(0);cnty<fluid->yRes(); ++cnty)
+ for(int cntz(0);cntz<fluid->zRes(); ++cntz)
+ {
+ step = fluid->xRes() + cnty * fluid->xRes() + cntz * fluid->xRes()*fluid->yRes();
+ if ((step < 0) || (step > fluid->_totalCells)){
+ cout << "UpdatePointers: step is larger tahn cell dim" << step << endl;
+ }
+ fluid->_density[step] = manta_fluid_density[cnty + cntz*fluid->xRes()];
+ fluid->_manta_flags[step] = manta_fluid_flags[cnty + cntz*fluid->xRes()];
+ }
+ }
+ else{
+ fluid->_density = (float* )pointerFromString(getGridPointer("density", "s"));
+ fluid->_manta_flags = (int* )pointerFromString(getGridPointer("flags", "s"));
+ }
+// fluid->_density = (float* )pointerFromString(getGridPointer("density", "s"));
+
+ fluid->_manta_inflow = (float* )pointerFromString(getGridPointer("inflow_grid", "s"));
+ if (fluid-> manta_resoution == 2){return;}
+ if (fluid->using_colors){
+ cout<< "POINTER FOR R_LOW" << fluid->_color_r<< endl;
+ fluid->_color_r = (float* )pointerFromString(getGridPointer("color_r_low", "s"));
+ cout<< "POINTER FOR R_LOW" << fluid->_color_r<< endl;
+ fluid->_color_g = (float* )pointerFromString(getGridPointer("color_g_low", "s"));
+ fluid->_color_b = (float* )pointerFromString(getGridPointer("color_b_low", "s"));
+ }
+ if(fluid->using_heat){
+ cout<< "Updating Heat" << fluid->_heat<< endl;
+ fluid->_heat = (float* )pointerFromString(getGridPointer("heat_low", "s"));
+ cout<< "Updating Heat" << fluid->_heat<< endl;
+ }
+}
+
+void Manta_API::updateHighResPointers(WTURBULENCE *wt, bool updateColor)
+{
+ wt->_densityBig = (float* )pointerFromString(getGridPointer("xl_density", "xl"));;
+ if (updateColor){
+ cout<< "POINTER FOR R_HIGH" << wt->_color_rBig << endl;
+ wt->_color_rBig = (float* )pointerFromString(getGridPointer("color_r_high", "xl"));
+ cout<< "POINTER FOR R_HIGH" << wt->_color_rBig << endl;
+ wt->_color_gBig = (float* )pointerFromString(getGridPointer("color_g_high", "xl"));
+ wt->_color_bBig = (float* )pointerFromString(getGridPointer("color_b_high", "xl"));
+ }
+}
+
diff --git a/intern/smoke/intern/MANTA.h b/intern/smoke/intern/MANTA.h
new file mode 100644
index 00000000000..fad858a5983
--- /dev/null
+++ b/intern/smoke/intern/MANTA.h
@@ -0,0 +1,136 @@
+#ifndef MANTA_H
+#define MANTA_H
+#include "FLUID_3D.h"
+#include "zlib.h"
+#include "../../../source/blender/makesdna/DNA_scene_types.h"
+#include "../../../source/blender/makesdna/DNA_modifier_types.h"
+#include "../../../source/blender/makesdna/DNA_smoke_types.h"
+#include <sstream>
+#include <stdlib.h>
+#include <fstream>
+#include <pthread.h>
+#include <Python.h>
+#include <vector>
+
+#include "BLI_path_util.h"
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+void export_force_fields(int size_x, int size_y, int size_z, float *f_x, float*f_y, float*f_z);/*defined in pymain.cpp*/
+void export_em_fields(float *em_map, float flow_density, int min_x, int min_y, int min_z, int max_x, int max_y, int max_z, int d_x, int d_y, int d_z, float *inf, float *vel);/*defined in pymain.cpp*/
+extern "C" void manta_write_effectors(struct FLUID_3D *fluid); /*defined in smoke_api.cpp*/
+void runMantaScript(const string& ss,vector<string>& args);//defined in manta_pp/pwrapper/pymain.cpp
+
+/*for passing to detached thread*/
+struct manta_arg_struct {
+ Scene s;
+ SmokeModifierData smd;
+};
+
+static bool manta_sim_running=true;
+
+extern "C" bool manta_check_grid_size(struct FLUID_3D *fluid, int dimX, int dimY, int dimZ);
+
+extern "C" int read_mantaflow_sim(struct SmokeDomainSettings *sds, char *name, bool read_wavelets);
+
+class Manta_API{
+private:
+ Manta_API() {}
+ Manta_API(const Manta_API &);
+ Manta_API & operator=(const Manta_API &);
+public:
+ ~Manta_API();
+ Manta_API(int *res, float dx, float dtdef, int init_heat, int init_fire, int init_colors, struct SmokeDomainSettings *sds);
+ 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);
+ int _totalCells;
+ int _xRes, _yRes, _zRes;
+ float _res;
+ int _slabSize;
+ float _dt,_dx;
+ float* _density;
+ float* _xVelocity;
+ float* _yVelocity;
+ float* _zVelocity;
+ float* _xVelocityOb;
+ float* _yVelocityOb;
+ float* _zVelocityOb;
+ float* _xForce;
+ float* _yForce;
+ float* _zForce;
+ 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 *_dtFactor;
+ float *_vorticityRNA; // RNA-pointer.
+ int *_borderColli; // border collision rules <-- as pointer to get blender RNA in here
+ 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
+
+ unsigned char* _obstacles; /* only used (useful) for static obstacles like domain */
+ void step(float dt, float gravity[3]);
+// void runMantaScript(const string&, vector<string>& args);//defined in manta_pp/pwrapper/pymain.cpp
+
+ void indent_ss(stringstream& ss, int indent);
+
+ void manta_gen_noise(stringstream& ss, char* solver, int indent, char *noise, int seed, bool load, bool clamp, float clampNeg, float clampPos, float valScale, float valOffset, float timeAnim);
+
+ void manta_solve_pressure(stringstream& ss, char *flags, char *vel, char *pressure, bool useResNorms, int openBound, int solver_res,float cgMaxIterFac=1.0, float cgAccuracy = 0.01);
+
+ void manta_advect_SemiLagr(stringstream& ss, int indent, char *flags, char *vel, char *grid, int order);
+
+ /*create solver, handle 2D case*/
+ void manta_create_solver(stringstream& ss, char *name, char *nick, char *grid_size_name, int x_res, int y_res, int z_res, int dim);
+
+ inline bool file_exists (const std::string& name);
+
+ /*blender transforms obj coords to [-1,1]. This method transforms them back*/
+ void add_mesh_transform_method(stringstream& ss);
+
+ void manta_cache_path(char *filepath);
+
+ void create_manta_folder();
+
+ void *run_manta_scene_thread(void *threadid);
+
+ void run_manta_sim_highRes(WTURBULENCE *wt);
+
+ void run_manta_scene(Manta_API * fluid);
+
+ void stop_manta_sim();
+
+ static void generate_manta_sim_file_highRes(SmokeModifierData *smd);
+
+ void manta_sim_step(int frame);
+
+ static std::string getRealValue(const string& varName, SmokeModifierData *sds);
+
+ static std::string parseLine(const string& line, SmokeModifierData *sds);
+
+ static std::string parseScript(const string& setup_string, SmokeModifierData *sds);
+
+ pthread_t manta_thread;
+
+ static void * pointerFromString(const std::string& s);
+
+ static string gridNameFromType(const string& type);
+ static void addGrid(void * data,string name, string type, int x, int y, int z, bool is2D);
+ static void addAdaptiveGrid(void * data, string gridName, string solverName, string type,int minX, int minY, int minZ, int maxX, int maxY, int maxZ, bool is2D);
+ static void export_obstacles(float *data, int x, int y, int z, bool is2D);
+
+ static std::string getGridPointer(string gridName, string solverName);
+ static void updatePointers(FLUID_3D *fluid, bool updateColor);
+ static void updateHighResPointers(WTURBULENCE *wt,bool updateColor);
+ static void manta_export_grids(SmokeModifierData *smd);
+};
+
+
+
+#endif /* MANTA_H */
+
diff --git a/intern/smoke/intern/WTURBULENCE.cpp b/intern/smoke/intern/WTURBULENCE.cpp
index 3d712d2124a..000a78e03b8 100644
--- a/intern/smoke/intern/WTURBULENCE.cpp
+++ b/intern/smoke/intern/WTURBULENCE.cpp
@@ -37,6 +37,7 @@
#include "SPHERE.h"
#include <zlib.h>
#include <math.h>
+#include "scenarios/smoke.h"
// needed to access static advection functions
#include "FLUID_3D.h"
@@ -48,6 +49,12 @@
// 2^ {-5/6}
static const float persistence = 0.56123f;
+#ifdef WITH_MANTA
+#include "MANTA.h"
+#endif
+
+#ifndef WITH_MANTA /*old WTurbulence Solver*/
+
//////////////////////////////////////////////////////////////////////
// constructor
//////////////////////////////////////////////////////////////////////
@@ -1196,3 +1203,182 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa
_totalStepsBig++;
}
+
+
+
+
+
+
+#else /*USING MANTAFLOW WTURBULENCE*/
+
+WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors,SmokeDomainSettings *sds)
+{
+ // 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 = NULL;
+ _densityBigOld = new float[_totalCellsBig];
+
+ for(int i = 0; i < _totalCellsBig; 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;
+ using_colors = false;
+ if (init_colors) {
+ using_colors = true;
+ 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);
+ sds->smd->domain->wt = this;
+ Manta_API::generate_manta_sim_file_highRes(sds->smd);
+ Manta_API::updateHighResPointers(this,using_colors);
+}
+/// 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;
+}
+
+void WTURBULENCE::initFire(){}
+void WTURBULENCE::initColors(float init_r, float init_g, float init_b)
+{
+ if (!_color_rBig){
+ using_colors = true;
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ stringstream ss;
+ ss << "manta_color_r = " << init_r << endl;
+ ss << "manta_color_g = " << init_g << endl;
+ ss << "manta_color_b = " << init_b << endl;
+ PyRun_SimpleString(ss.str().c_str());
+ PyRun_SimpleString(smoke_init_colors_high.c_str());
+ PyGILState_Release(gilstate);
+ Manta_API::updateHighResPointers(this,true);
+ }
+}
+
+void WTURBULENCE::setNoise(int type, const char *noisefile_path){}
+void WTURBULENCE::initBlenderRNA(float *strength){}
+
+// step more readable version -- no rotation correction
+void WTURBULENCE::stepTurbulenceReadable(float dt, float* xvel, float* yvel, float* zvel, unsigned char *obstacles){
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ int sim_frame = 1;
+ // manta_write_effectors(fluid);
+ std::string frame_str = static_cast<ostringstream*>( &(ostringstream() << sim_frame) )->str();
+ std::string py_string_0 = string("sim_step_high(").append(frame_str);
+ std::string py_string_1 = py_string_0.append(")\0");
+ PyRun_SimpleString(py_string_1.c_str());
+ PyGILState_Release(gilstate);
+ Manta_API::updateHighResPointers(this,using_colors);
+}
+
+// step more complete version -- include rotation correction
+// and use OpenMP if available
+void WTURBULENCE::stepTurbulenceFull(float dt, float* xvel, float* yvel, float* zvel, unsigned char *obstacles){
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ int sim_frame = 1;
+ // manta_write_effectors(fluid);
+ std::string frame_str = static_cast<ostringstream*>( &(ostringstream() << sim_frame) )->str();
+ std::string py_string_0 = string("sim_step_high(").append(frame_str);
+ std::string py_string_1 = py_string_0.append(")\0");
+ PyRun_SimpleString(py_string_1.c_str());
+ PyGILState_Release(gilstate);
+ Manta_API::updateHighResPointers(this,using_colors);
+}
+
+// texcoord functions
+void WTURBULENCE::advectTextureCoordinates(float dtOrg, float* xvel, float* yvel, float* zvel, float *tempBig1, float *tempBig2){}
+void WTURBULENCE::resetTextureCoordinates(float *_eigMin, float *_eigMax){}
+
+void WTURBULENCE::computeEnergy(float *energy, float* xvel, float* yvel, float* zvel, unsigned char *obstacles){}
+
+void WTURBULENCE::computeEigenvalues(float *_eigMin, float *_eigMax){}
+void WTURBULENCE::decomposeEnergy(float *energy, float *_highFreqEnergy){}
+Vec3 WTURBULENCE::WVelocity(Vec3 p){return Vec3(0.);}
+Vec3 WTURBULENCE::WVelocityWithJacobian(Vec3 p, float* xUnwarped, float* yUnwarped, float* zUnwarped){return Vec3(0.);}
+
+#endif
diff --git a/intern/smoke/intern/WTURBULENCE.h b/intern/smoke/intern/WTURBULENCE.h
index 36635325f62..787177bbb81 100644
--- a/intern/smoke/intern/WTURBULENCE.h
+++ b/intern/smoke/intern/WTURBULENCE.h
@@ -36,7 +36,7 @@ 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);
+ WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype, const char *noisefile_path, int init_fire, int init_colors,struct SmokeDomainSettings *sds);
/// destructor
virtual ~WTURBULENCE();
@@ -128,7 +128,8 @@ struct WTURBULENCE
float* _color_gBigOld;
float* _color_bBig;
float* _color_bBigOld;
-
+ bool using_colors;
+
// texture coordinates for noise
float* _tcU;
float* _tcV;
diff --git a/intern/smoke/intern/scenarios/smoke.h b/intern/smoke/intern/scenarios/smoke.h
new file mode 100644
index 00000000000..91eb27a13ba
--- /dev/null
+++ b/intern/smoke/intern/scenarios/smoke.h
@@ -0,0 +1,361 @@
+#include <string>
+using namespace std;
+const string smoke_clean = "";
+
+const string smoke_setup_low ="from manta import *\n\
+import os, shutil, math, sys\n\
+def transform_back(obj, gs):\n\
+ obj.scale(gs/2)\n\
+ obj.offset(gs/2)\n\
+\n\
+def load_once(grid, file, dict):\n\
+ if grid not in dict:\n\
+ print('Loading file' + file + 'in grid')\n\
+ grid.load(file)\n\
+ dict[grid] = 1\n\
+# solver params\n\
+res = $RES$\n\
+solver_dim = $SOLVER_DIM$\n\
+gs = vec3($RESX$,$RESY$,$RESZ$)\n\
+boundConditions = '$BOUNDCONDITIONS$'\n\
+if solver_dim == 2:\n\
+ gs.z = 1\n\
+s = FluidSolver(name='main', gridSize = gs, dim = $SOLVER_DIM$)\n\
+s.timestep = 0.1\n\
+timings = Timings()\n\
+\n\
+# prepare grids\n\
+flags = s.create(FlagGrid)\n\
+vel = s.create(MACGrid)\n\
+density = s.create(LevelsetGrid)\n\
+pressure = s.create(RealGrid)\n\
+\n\
+# noise field\n\
+#noise = s.create(NoiseField, loadFromFile=True)\n\
+#noise.posScale = vec3(45)\n\
+#noise.clamp = True\n\
+#noise.clampNeg = 0\n\
+#noise.clampPos = 1\n\
+#noise.valScale = 1\n\
+#noise.valOffset = 0.75\n\
+#noise.timeAnim = 0.2\n\
+\n\
+flags.initDomain()\n\
+flags.fillGrid()\n\
+\n\
+inflow_grid = s.create(LevelsetGrid)\n\
+source = s.create(Mesh)\n\
+forces = s.create(MACGrid)\n\
+dict_loaded = dict()\n\
+manta_using_colors = False\n\
+manta_using_heat = False\n\
+low_flags_updated = False\n\
+";
+
+const string smoke_setup_high = "xl_gs = vec3($HRESX$, $HRESY$, $HRESZ$) \n\
+xl = Solver(name = 'larger', gridSize = xl_gs) \n\
+uvs =$UVS_CNT$\n\
+if $USE_WAVELETS$:\n\
+ upres = $UPRES$\n\
+ wltStrength = $WLT_STR$\n\
+ if $UPRES$ > 0:\n\
+ octaves = int( math.log(upres)/ math.log(2.0) + 0.5 ) \n\
+ else:\n\
+ octaves = 0\n\
+if $USE_WAVELETS$ and $UPRES$ > 0:\n\
+ xl.timestep = $XL_TIMESTEP$ \n\
+ xl_vel = xl.create(MACGrid) \n\
+ xl_density = xl.create(RealGrid) \n\
+ xl_flags = xl.create(FlagGrid) \n\
+ xl_flags.initDomain() \n\
+ xl_flags.fillGrid() \n\
+ xl_noise = xl.create(NoiseField, fixedSeed=256, loadFromFile=True) \n\
+ xl_noise.posScale = vec3(20) \n\
+ xl_noise.clamp = False \n\
+ xl_noise.clampNeg = $NOISE_CN$ \n\
+ xl_noise.clampPos = $NOISE_CP$ \n\
+ xl_noise.valScale = $NOISE_VALSCALE$ \n\
+ xl_noise.valOffset = $NOISE_VALOFFSET$ \n\
+ xl_noise.timeAnim = $NOISE_TIMEANIM$ * $UPRES$ \n\
+ xl_wltnoise = xl.create(NoiseField, loadFromFile=True) \n\
+ xl_wltnoise.posScale = vec3( int(1.0*gs.x) ) * 0.5 \n\
+ xl_wltnoise.posScale = xl_wltnoise.posScale * 0.5\n\
+ xl_wltnoise.timeAnim = 0.1 \n\
+";
+
+const string smoke_init_colors_low = "print(\"INitializing Colors\")\n\
+color_r_low = s.create(RealGrid)\n\
+color_g_low = s.create(RealGrid)\n\
+color_b_low = s.create(RealGrid)\n\
+color_r_low.add(density) \n\
+color_r_low.multConst(manta_color_r) \n\
+\n\
+color_g_low.add(density) \n\
+color_g_low.multConst(manta_color_g) \n\
+\n\
+color_b_low.add(density) \n\
+color_b_low.multConst(manta_color_b) \n\
+manta_using_colors = True\n";
+
+const string smoke_del_colors_low = "\n\
+del color_r_low \n\
+del color_g_low \n\
+del color_b_low \n\
+manta_using_colors = False";
+
+const string smoke_init_colors_high = "print(\"INitializing Colors highres\")\n\
+color_r_high = xl.create(RealGrid)\n\
+color_g_high = xl.create(RealGrid)\n\
+color_b_high = xl.create(RealGrid)\n\
+color_r_high.add(xl_density) \n\
+color_r_high.multConst(manta_color_r) \n\
+\n\
+color_g_high.add(xl_density) \n\
+color_g_high.multConst(manta_color_g) \n\
+\n\
+color_b_high.add(xl_density) \n\
+color_b_high.multConst(manta_color_b) \n\
+manta_using_colors = True\n";
+
+const string smoke_init_heat_low = "print(\"INitializing heat lowres\")\n\
+heat_low = s.create(RealGrid)\n\
+manta_using_heat = True\n";
+
+const string smoke_del_colors_high = "\n\
+del color_r_high \n\
+del color_g_high \n\
+del color_b_high \n\
+manta_using_colors = False";
+
+const string smoke_export_low = "\n\
+import os\n\
+density.save(os.path.join('$MANTA_EXPORT_PATH$','density.uni'))\n\
+flags.save(os.path.join('$MANTA_EXPORT_PATH$','flags.uni'))\n\
+inflow_grid.save(os.path.join('$MANTA_EXPORT_PATH$','inflow.uni'))\n\
+forces.save(os.path.join('$MANTA_EXPORT_PATH$','forces.uni'))\n\
+print('Grids exported')";
+
+const string standalone = "\
+if (GUI):\n\
+ gui =Gui()\n\
+ gui.show()\n\
+\n\
+for step in range(100):\n\
+ sim_step_low(step, True)\n";
+
+const string smoke_step_low = "def sim_step_low(t, standalone = False):\n\
+ #applying inflow\n\
+ #if standalone and t==0:\n\
+ # density.load('density.uni')\n\
+ # flags.load('flags.uni')\n\
+ # forces.load('forces.uni')\n\
+ #if standalone:\n\
+ # inflow_grid.load('inflow.uni')\n\
+ # inflow_grid.multConst(0.1)\n\
+ # density.add(inflow_grid)\n\
+ #elif solver_dim == 2:\n\
+ # density.add(inflow_grid)\n\
+ print ('Simulating frame ' + str(t))\n\
+ if not standalone and t == 1 and solver_dim == 2:\n\
+ density.add(inflow_grid)\n\
+ if manta_using_heat:\n\
+ gravity=vec3(0,0,-0.0981) if solver_dim==3 else vec3(0,-0.0981,0)\n\
+ addHeatBuoyancy(density=density, densCoeff = 0.001, vel=vel, gravity=gravity, flags=flags, heat = heat_low, heatCoeff = -0.1*10)\n\
+ else:\n\
+ gravity=vec3(0,0,-0.01) if solver_dim==3 else vec3(0,-0.01,0)\n\
+ addBuoyancy(density=density, vel=vel, gravity=gravity, flags=flags)\n\
+ if manta_using_colors:\n\
+ advectSemiLagrange(flags=flags, vel=vel, grid=color_r_low, order=$ADVECT_ORDER$)\n\
+ advectSemiLagrange(flags=flags, vel=vel, grid=color_g_low, order=$ADVECT_ORDER$)\n\
+ advectSemiLagrange(flags=flags, vel=vel, grid=color_b_low, order=$ADVECT_ORDER$)\n\
+ print ('Advecting density')\n\
+ advectSemiLagrange(flags=flags, vel=vel, grid=density, order=$ADVECT_ORDER$)\n\
+ print ('Advecting velocity')\n\
+ advectSemiLagrange(flags=flags, vel=vel, grid=vel , order=$ADVECT_ORDER$, strength=1.0)\n\
+ \n\
+ print ('Walls')\n\
+ setWallBcs(flags=flags, vel=vel) \n\
+ print ('vorticity')\n\
+ if $VORTICITY$ > 0.01:\n\
+ vorticityConfinement( vel=vel, flags=flags, strength=$VORTICITY$ ) \n\
+ print ('forcefield')\n\
+ addForceField(flags=flags, vel=vel,force=forces)\n\
+ forces.clear()\n\
+ \n\
+ print ('pressure')\n\
+ solvePressure(flags=flags, vel=vel, pressure=pressure, openBound=boundConditions)\n\
+ print ('walls')\n\
+ setWallBcs(flags=flags, vel=vel)\n\
+ \n\
+ s.step()\n";
+
+const string liquid_step_low = "def sim_step_low(t):\n\
+#update flags form density on first step\n\
+ setWallBcs(flags=flags, vel=vel)\n\
+ density.multConst(-1.)\n\
+ print (manta_using_colors)\n\
+ global low_flags_updated\n\
+ if not low_flags_updated:\n\
+ print ('Updating Flags from Levelset on startup!')\n\
+ flags.updateFromLevelset(density)\n\
+ low_flags_updated = True \n\
+ setWallBcs(flags=flags, vel=vel)\n\
+ density.reinitMarching(flags=flags, velTransport=vel)\n\
+ advectSemiLagrange(flags=flags, vel=vel, grid=density, order=2)\n\
+ flags.updateFromLevelset(density)\n\
+ \n\
+ advectSemiLagrange(flags=flags, vel=vel, grid=vel, order=2)\n\
+ addGravity(flags=flags, vel=vel, gravity=vec3(0,0,-0.981))\n\
+ \n\
+ # print current maximal velocity\n\
+ maxvel = vel.getMaxValue()\n\
+ print ('Current max velocity %f ' % maxvel)\n\
+ \n\
+ # pressure solve\n\
+ setWallBcs(flags=flags, vel=vel)\n\
+ solvePressure(flags=flags, vel=vel, pressure=pressure, cgMaxIterFac=0.5, useResNorm=True) \n\
+ setWallBcs(flags=flags, vel=vel)\n\
+ s.step()\n\
+ density.multConst(-1.)\n\
+";
+
+const string smoke_step_high = "def sim_step_high(t):\n\
+ interpolateMACGrid( source=vel, target=xl_vel ) \n\
+ sStr = 1.0 * wltStrength \n\
+ sPos = 2.0 \n\
+ for o in range(octaves): \n\
+ for i in range(uvs): \n\
+ uvWeight = getUvWeight(uv[i]) \n\
+ applyNoiseVec3( flags=xl_flags, target=xl_vel, noise=xl_wltnoise, scale=sStr * uvWeight, scaleSpatial=sPos , weight=energy, uv=uv[i] ) \n\
+ sStr *= 0.06 # magic kolmogorov factor \n\
+ sPos *= 2.0 \n\
+ for substep in range(upres): \n\
+ advectSemiLagrange(flags=xl_flags, vel=xl_vel, grid=xl_density, order=$ADVECT_ORDER$) \n\
+ if manta_using_colors:\n\
+ advectSemiLagrange(flags=xl_flags, vel=xl_vel, grid=color_r_high, order=$ADVECT_ORDER$)\n\
+ advectSemiLagrange(flags=xl_flags, vel=xl_vel, grid=color_g_high, order=$ADVECT_ORDER$)\n\
+ advectSemiLagrange(flags=xl_flags, vel=xl_vel, grid=color_b_high, order=$ADVECT_ORDER$)\n\
+\n\
+ xl.step()\n";
+
+const string full_smoke_setup = "from manta import * \n\
+import os, shutil, math, sys \n\
+def transform_back(obj, gs):\n\
+ obj.scale(gs/2)\n\
+ obj.offset(gs/2)\n\
+\n\
+uvs = $UVS_CNT$\n\
+solver_dim = $SOLVER_DIM$\n\
+velInflow = vec3(0, 0, 1)\n\
+if $USE_WAVELETS$:\n\
+ upres = $UPRES$\n\
+ wltStrength = $WLT_STR$\n\
+ if $UPRES$ > 0:\n\
+ octaves = int( math.log(upres)/ math.log(2.0) + 0.5 ) \n\
+ else:\n\
+ octaves = 0\n\
+res = $RES$\n\
+gs = vec3($RESX$, $RESY$, $RESZ$) \n\
+s = Solver(name = 'main', gridSize = gs, dim = solver_dim) \n\
+s.timestep = $TIMESTEP$ \n\
+noise = s.create(NoiseField, fixedSeed=256, loadFromFile=True) \n\
+noise.posScale = vec3(20) \n\
+noise.clamp = False \n\
+noise.clampNeg = $NOISE_CN$\n\
+noise.clampPos = $NOISE_CP$\n\
+noise.valScale = $NOISE_VALSCALE$\n\
+noise.valOffset = $NOISE_VALOFFSET$\n\
+noise.timeAnim = $NOISE_TIMEANIM$ \n\
+source = s.create(Mesh)\n\
+source.load('manta_flow.obj')\n\
+transform_back(source, gs)\n\
+sourceVel = s.create(Mesh)\n\
+sourceVel.load('manta_flow.obj')\n\
+transform_back(sourceVel, gs)\n\
+xl_gs = vec3($HRESX$, $HRESY$, $HRESZ$) \n\
+xl = Solver(name = 'larger', gridSize = xl_gs, dim = solver_dim) \n\
+if $USE_WAVELETS$ and $UPRES$ > 0:\n\
+ xl.timestep = $XL_TIMESTEP$ \n\
+ xl_vel = xl.create(MACGrid) \n\
+ xl_density = xl.create(RealGrid) \n\
+ xl_flags = xl.create(FlagGrid) \n\
+ xl_flags.initDomain() \n\
+ xl_flags.fillGrid() \n\
+ xl_source = s.create(Mesh)\n\
+ xl_source.load('manta_flow.obj')\n\
+ transform_back(xl_source, gs)\n\
+ xl_noise = xl.create(NoiseField, fixedSeed=256, loadFromFile=True) \n\
+ xl_noise.posScale = vec3(20) \n\
+ xl_noise.clamp = False \n\
+ xl_noise.clampNeg = $NOISE_CN$ \n\
+ xl_noise.clampPos = $NOISE_CP$ \n\
+ xl_noise.valScale = $NOISE_VALSCALE$ \n\
+ xl_noise.valOffset = $NOISE_VALOFFSET$ \n\
+ xl_noise.timeAnim = $NOISE_TIMEANIM$ * $UPRES$ \n\
+flags = s.create(FlagGrid) \n\
+flags.initDomain() \n\
+flags.fillGrid() \n\
+uv = [] \n\
+for i in range(uvs): \n\
+ uvGrid = s.create(VecGrid) \n\
+ uv.append(uvGrid) \n\
+ resetUvGrid( uv[i] ) \n\
+vel = s.create(MACGrid) \n\
+density = s.create(RealGrid) \n\
+pressure = s.create(RealGrid) \n\
+energy = s.create(RealGrid) \n\
+tempFlag = s.create(FlagGrid)\n\
+sdf_flow = s.create(LevelsetGrid)\n\
+forces = s.create(MACGrid)\n\
+source.meshSDF(source, sdf_flow, 1.1)\n\
+source_shape = s.create(Cylinder, center=gs*vec3(0.5,0.1,0.5), radius=res*0.14, z=gs*vec3(0, 0.02, 0))\n\
+xl_wltnoise = s.create(NoiseField, loadFromFile=True) \n\
+xl_wltnoise.posScale = vec3( int(1.0*gs.x) ) * 0.5 \n\
+xl_wltnoise.posScale = xl_wltnoise.posScale * 0.5\n\
+xl_wltnoise.timeAnim = 0.1 \n\
+\n\
+\n\
+def sim_step(t):\n\
+ forces.load('manta_forces.uni')\n\
+ addForceField(flags=flags, vel=vel,force=forces)\n\
+ addBuoyancy(density=density, vel=vel, gravity=vec3($BUYO_X$,$BUYO_Y$,$BUYO_Z$), flags=flags) \n\
+ advectSemiLagrange(flags=flags, vel=vel, grid=density, order=$ADVECT_ORDER$) \n\
+ advectSemiLagrange(flags=flags, vel=vel, grid=vel, order=$ADVECT_ORDER$) \n\
+ for i in range(uvs): \n\
+ advectSemiLagrange(flags=flags, vel=vel, grid=uv[i], order=$ADVECT_ORDER$) \n\
+ updateUvWeight( resetTime=16.5 , index=i, numUvs=uvs, uv=uv[i] )\n\
+ applyInflow=False\n\
+ if (t>=0 and t<75):\n\
+ densityInflowMesh(flags=flags, density=density, mesh=source, value=1)\n\
+ applyInflow=True\n\
+ setWallBcs(flags=flags, vel=vel) \n\
+ vorticityConfinement( vel=vel, flags=flags, strength=0.2 ) \n\
+ solvePressure(flags=flags, vel=vel, pressure=pressure, useResNorm=True, openBound='xXyYzZ', cgMaxIterFac=1, cgAccuracy=0.01) \n\
+ setWallBcs(flags=flags, vel=vel) \n\
+ computeEnergy(flags=flags, vel=vel, energy=energy)\n\
+ tempFlag.copyFrom(flags)\n\
+ extrapolateSimpleFlags( flags=flags, val=tempFlag, distance=2, flagFrom=FlagObstacle, flagTo=FlagFluid )\n\
+ extrapolateSimpleFlags( flags=tempFlag, val=energy, distance=6, flagFrom=FlagFluid, flagTo=FlagObstacle )\n\
+ computeWaveletCoeffs(energy)\n\
+ print(\"Writing Grid to \" + $DENSITY_MEM$ + \"with size\" + $DENSITY_SIZE$)\n\
+ density.writeGridToMemory(memLoc = $DENSITY_MEM$,sizeAllowed = $DENSITY_SIZE$)\n\
+ density.save('den%04d_temp.uni' % t) \n\
+ os.rename('den%04d_temp.uni' % t, 'den%04d.uni' % t) \n\
+ s.step()\n\
+ \n\
+ interpolateMACGrid( source=vel, target=xl_vel ) \n\
+ sStr = 1.0 * wltStrength \n\
+ sPos = 2.0 \n\
+ for o in range(octaves): \n\
+ for i in range(uvs): \n\
+ uvWeight = getUvWeight(uv[i]) \n\
+ applyNoiseVec3( flags=xl_flags, target=xl_vel, noise=xl_wltnoise, scale=sStr * uvWeight, scaleSpatial=sPos , weight=energy, uv=uv[i] ) \n\
+ sStr *= 0.06 # magic kolmogorov factor \n\
+ sPos *= 2.0 \n\
+ for substep in range(upres): \n\
+ advectSemiLagrange(flags=xl_flags, vel=xl_vel, grid=xl_density, order=$ADVECT_ORDER$) \n\
+ if (applyInflow): \n\
+ densityInflowMesh(flags=xl_flags, density=xl_density, mesh=source, value=1)\n\
+ xl_density.save('densityXl_%04d.uni' % t)\n\
+ xl.step()\n\
+";
diff --git a/intern/smoke/intern/smoke_API.cpp b/intern/smoke/intern/smoke_API.cpp
index d79aaf76d56..462af5b12b4 100644
--- a/intern/smoke/intern/smoke_API.cpp
+++ b/intern/smoke/intern/smoke_API.cpp
@@ -35,19 +35,24 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
-
+#include "MANTA.h"
+#include "../../../source/blender/python/manta_pp/util/vectorbase.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)
+extern "C" int *smoke_get_manta_flags(struct FLUID_3D *fluid){
+ return fluid->_manta_flags;
+}
+
+extern "C" FLUID_3D *smoke_init(int *res, float dx, float dtdef, int use_heat, int use_fire, int use_colors, struct SmokeModifierData *smd )
{
- FLUID_3D *fluid = new FLUID_3D(res, dx, dtdef, use_heat, use_fire, use_colors);
+ FLUID_3D *fluid = new FLUID_3D(res, dx, dtdef, use_heat, use_fire, use_colors,smd);
return fluid;
}
-extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors)
+extern "C" WTURBULENCE *smoke_turbulence_init(int *res, int amplify, int noisetype, const char *noisefile_path, int use_fire, int use_colors,struct SmokeDomainSettings *sds)
{
if (amplify)
- return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype, noisefile_path, use_fire, use_colors);
+ return new WTURBULENCE(res[0],res[1],res[2], amplify, noisetype, noisefile_path, use_fire, use_colors,sds);
else
return NULL;
}
@@ -74,6 +79,12 @@ extern "C" size_t smoke_get_index2d(int x, int max_x, int y /*, int max_y, int z
return x + y * max_x;
}
+extern "C" void smoke_manta_export(SmokeModifierData *smd)
+{
+ if (!smd) return;
+ Manta_API::manta_export_grids(smd);
+}
+
extern "C" void smoke_step(FLUID_3D *fluid, float gravity[3], float dtSubdiv)
{
if (fluid->_fuel) {
@@ -233,6 +244,11 @@ extern "C" float *smoke_get_density(FLUID_3D *fluid)
return fluid->_density;
}
+extern "C" float *smoke_get_inflow_grid(FLUID_3D *fluid)
+{
+ return fluid->_manta_inflow;
+}
+
extern "C" float *smoke_get_fuel(FLUID_3D *fluid)
{
return fluid->_fuel;
@@ -506,3 +522,96 @@ extern "C" void smoke_ensure_colors(FLUID_3D *fluid, WTURBULENCE *wt, float init
wt->initColors(init_r, init_g, init_b);
}
}
+
+
+/*MantaFlow funcs*/
+extern "C" int smoke_mantaflow_read(struct SmokeDomainSettings *sds, char* name, bool with_wavelets)
+{
+ return read_mantaflow_sim(sds, name, with_wavelets);
+}
+
+
+extern "C" void manta_write_effectors(struct FLUID_3D *fluid)
+{
+ int size_x = fluid->_xRes;
+ int size_y = fluid->_yRes;
+ int size_z = fluid->_zRes;
+
+ float *force_x = smoke_get_force_x(fluid);
+ float *force_y = smoke_get_force_y(fluid);
+ float *force_z = smoke_get_force_z(fluid);
+// export_force_fields(size_x, size_y, size_z, force_x, force_y, force_z);
+ /*accumulate all force fields in one grid*/
+ Manta::Vec3 * accumulated_force = NULL;
+ long index(0);
+ if (fluid->manta_resoution == 3){
+ accumulated_force = (Manta::Vec3*)calloc(size_x * size_y * size_z , sizeof(Manta::Vec3));
+ for (int z(0); z < size_z; z++){
+ for (int y(0); y < size_y; y++){
+ for (int x(0); x < size_x; x++){
+ index = smoke_get_index(x, size_x, y, size_y, z);
+ accumulated_force[index] = Manta::Vec3(force_x[index], force_y[index], force_z[index]);
+ }
+ }
+ }
+ }
+ else if (fluid->manta_resoution == 2){
+ accumulated_force = (Manta::Vec3*)malloc(size_x * size_z * sizeof(Manta::Vec3));
+ int step(0);
+ for (int x(0); x < size_x; x++){
+ for (int z(0); z < size_z; z++){
+ index = smoke_get_index(x, size_x, size_y/2, size_y, z);
+ accumulated_force[x + z * size_x] = Manta::Vec3(force_x[index], force_z[index], 0.0);
+ }
+ }
+ }
+ else{
+ cout << "ERROR: Manta solver resoltion is neither 2 nor 3; Cannot write forces"<<endl;
+ return;
+ }
+
+
+ bool is2D = (fluid->manta_resoution == 2);
+ Manta_API::addGrid(accumulated_force, "forces", "Vec3", size_x, size_y, size_z, is2D);
+}
+
+extern "C" void manta_write_emitters(struct SmokeFlowSettings *sfs, bool highRes, int min_x, int min_y, int min_z, int max_x, int max_y, int max_z, int d_x, int d_y, int d_z,float *influence, float *vel)
+{
+// manta_update_effectors(s, smd->domain->manta_obj, smd->domain, 0.1f);
+ bool is2D = (sfs->smd->domain->fluid->manta_resoution == 2);
+ if (! highRes)
+ Manta_API::addAdaptiveGrid(influence, "density", "s", "float",
+ min_x, min_y, min_z, max_x, max_y, max_z, is2D);
+ else
+ Manta_API::addAdaptiveGrid(influence, "xl_density", "xl", "float", min_x, min_y, min_z, max_x, max_y, max_z, is2D);
+ // export_em_fields(Manta_API::instance()->_emission_map,sfs->density, min_x, min_y, min_z, max_x, max_y, max_z, d_x, d_y, d_z, influence, vel);
+}
+
+/*deprecated*/
+extern "C" void manta_export_obstacles(float * influence, int x, int y, int z)
+{
+
+ cout << "!!!!!!!!!!Deprecated method manta_export_obstacles is being used" << endl;
+ if (influence == NULL){
+ cout<< "ERROR: empty influence object when exporting smoke obstacles" << endl;
+ return;
+ }
+// Manta_API::export_obstacles(influence, x, y, z);
+}
+
+extern "C" void smoke_mantaflow_stop_sim(struct Manta_API * fluid)
+{
+ if (fluid == NULL){
+ cout<< "ERROR: empty manta_API object when stopping smoke simulation" << endl;
+ return;
+ }
+ fluid->stop_manta_sim();
+}
+
+extern "C" int cell_index_3D(int index_2d, int sizex,int sizey, int sizez)
+{
+
+ return int(sizey * 0.5) * sizex +
+ (index_2d % (sizex)) +
+ int(index_2d/(sizex)) * sizex * sizey;
+}
diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py
index 63268bc6672..c2a2b3be230 100644
--- a/release/scripts/startup/bl_ui/properties_physics_smoke.py
+++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py
@@ -18,6 +18,8 @@
# <pep8 compliant>
import bpy
+import os
+from copy import deepcopy
from bpy.types import Panel
from bl_ui.properties_physics_common import (
@@ -204,13 +206,13 @@ class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel):
md = context.smoke.domain_settings
self.layout.prop(md, "use_adaptive_domain", text="")
-
+
def draw(self, context):
layout = self.layout
domain = context.smoke.domain_settings
layout.active = domain.use_adaptive_domain
-
+
split = layout.split()
split.enabled = (not domain.point_cache.is_baked)
@@ -327,5 +329,140 @@ class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel):
domain = context.smoke.domain_settings
effector_weights_ui(self, context, domain.effector_weights, 'SMOKE')
+class OBJECT_OT_RunMantaButton(bpy.types.Operator):
+ bl_idname = "manta_export_scene.button"
+ bl_label = "Create Python Script and mesh files"
+
+ def execute(self, context):
+ def silent_remove(filename):
+ if os.path.exists(filename):
+ os.remove(filename)
+
+ #need these methods to account for rotated objects
+ def transform_objgroup(obj_list, domain_obj):
+ old_scale = deepcopy(domain_obj.scale)
+ old_loc = deepcopy(domain_obj.location)
+ #link all objects to new reference- domain
+ domain_obj.scale = (1,1,1)
+ domain_obj.location = (0,0,0)
+ for obj in obj_list:
+ obj.select = True
+ obj.location[0] -= old_loc[0]
+ obj.location[1] -= old_loc[1]
+ obj.location[2] -= old_loc[2]
+ obj.constraints.new('CHILD_OF')
+ obj.constraints.active.target = domain_obj
+ #scale domain down
+ domain_obj.scale[0] /= old_scale[0]
+ domain_obj.scale[1] /= old_scale[1]
+ domain_obj.scale[2] /= old_scale[2]
+ return old_scale, old_loc
+
+ def transform_objgroup_back(obj_list, domain_obj, old_data):
+ old_scale, old_loc = old_data
+ domain_obj.scale[0] = old_scale[0]
+ domain_obj.scale[1] = old_scale[1]
+ domain_obj.scale[2] = old_scale[2]
+ domain_obj.location[0] = old_loc[0]
+ domain_obj.location[1] = old_loc[1]
+ domain_obj.location[2] = old_loc[2]
+ #remove used constraint and deselect objects
+ for obj in obj_list:
+ obj.select = False
+ obj.constraints.remove(obj.constraints.active)
+ obj.location[0] += old_loc[0]
+ obj.location[1] += old_loc[1]
+ obj.location[2] += old_loc[2]
+
+ coll_objs = []
+ flow_objs = []
+ selected_before = []
+ domain = None
+ #getting smoke objects
+ for scene in bpy.data.scenes:
+ for ob in scene.objects:
+ for modifier in ob.modifiers:
+ if modifier.type == 'SMOKE':
+ if modifier.smoke_type == 'COLLISION':
+ coll_objs.append(ob)
+ elif modifier.smoke_type == 'FLOW':
+ flow_objs.append(ob)
+ elif modifier.smoke_type == 'DOMAIN' and ob.select:
+ domain = ob
+ if ob.select:
+ selected_before.append(ob)
+ ob.select = False
+
+ silent_remove("./manta_coll.obj")
+ silent_remove("./manta_flow.obj")
+ #exporting here
+ if coll_objs:
+ old_data = transform_objgroup(coll_objs, domain)
+ bpy.ops.export_scene.obj(filepath = "./manta_coll.obj", axis_forward='Y', axis_up='Z', use_selection = True, use_normals = True, use_materials = False, use_triangles = True, group_by_object = True, use_nurbs=True, check_existing= False)
+ transform_objgroup_back(coll_objs,domain,old_data)
+ if flow_objs:
+ old_data = transform_objgroup(flow_objs, domain)
+ bpy.ops.export_scene.obj(filepath = "./manta_flow.obj", axis_forward='Y', axis_up='Z', use_selection = True, use_normals = True, use_materials = False, use_triangles = True, group_by_object = True, use_nurbs=True, check_existing= False)
+ transform_objgroup_back(flow_objs,domain,old_data)
+ for ob in selected_before:
+ ob.select = True
+ # ds = domain.modifiers['Smoke'].domain_settings
+ # if (!global manta_solver_res_switched) and ds.manta_solver_res == 2:
+ # #resize domain s.th. Y-axis dim corresponds to 1
+ # scale_fac = ds.resolution_max / max(domain.scale[0],domain.scale[1],domain.scale[2])
+ # domain.scale[1] /= scale_fac
+ # global manta_solver_res_switched = True
+ bpy.ops.manta.make_file()
+ bpy.ops.manta.sim_step()
+ return{'FINISHED'}
+
+class OBJECT_OT_StopMantaButton(bpy.types.Operator):
+ bl_idname = "manta_stop_sim.button"
+ bl_label = "Stop Mantaflow Simulation"
+ def execute(self, context):
+ domain = context.smoke.domain_settings
+ #setting manta_sim_frame to "stop" value
+ domain.manta_sim_frame = -1
+ return{'FINISHED'}
+
+
+class PHYSICS_PT_smoke_manta_settings(PhysicButtonsPanel, Panel):
+ bl_label = "MantaFlow Settings"
+ bl_options = {'DEFAULT_CLOSED'}
+ name = bpy.props.StringProperty(name="Test Prop", default="Unknown")
+ StringProp = bpy.props.StringProperty(name="manta_status", description="Status Of Simulation", default="Doing Nothing" )
+# filepath = StringProperty(subtype='FILE_PATH',)
+ @classmethod
+ def poll(cls, context):
+ md = context.smoke
+ return md and (md.smoke_type == 'DOMAIN')
+
+ def draw_header(self, context):
+ md = context.smoke.domain_settings
+
+ def draw(self, context):
+ layout = self.layout
+
+ domain = context.smoke.domain_settings
+ split = layout.split()
+ split.prop(domain, "use_manta_liquid", text="Liquid")
+ split.operator("manta_export_scene.button", text="Create Manta Setup")
+ split = layout.split()
+ split.prop(domain, "manta_filepath")
+ split = layout.split()
+ col = split.column()
+ col.prop(domain, "manta_solver_res", text="Solver Resolution")
+ col.prop(domain, "manta_uvs", text="UVs count")
+ split = layout.split()
+ col = split.column()
+ col.label("Noise Settings")
+ col.prop(domain, "noise_clamp_neg", text="Clamp Neg")
+ col.prop(domain, "noise_clamp_pos", text="Clamp Pos")
+ col.prop(domain, "noise_time_anim", text="Time Anim")
+ col = split.column()
+ col.label("")
+ col.prop(domain, "noise_val_scale", text="Scale")
+ col.prop(domain, "noise_val_offset", text="Offset")
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index a826fe26e68..162089c6e1d 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -56,6 +56,7 @@ set(INC
set(INC_SYS
${GLEW_INCLUDE_PATH}
${ZLIB_INCLUDE_DIRS}
+ ${PYTHON_INCLUDE_DIRS}
)
set(SRC
@@ -413,6 +414,10 @@ if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
endif()
+if(WITH_MOD_MANTA)
+ add_definitions(-DWITH_MANTA)
+endif()
+
if(WITH_MOD_OCEANSIM)
add_definitions(-DWITH_OCEANSIM)
endif()
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index 47bba5f5537..4897949ae44 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -52,6 +52,7 @@ incs = [
'#/intern/elbeem/extern',
'#/intern/iksolver/extern',
'#/intern/smoke/extern',
+# '#/source/blender/python/manta_pp',
'#/intern/atomic',
'../avi',
'../blenfont',
@@ -76,6 +77,9 @@ defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_SMOKE']:
defs.append('WITH_SMOKE')
+
+#if env['WITH_BF_MANTA']:
+# defs.append('WITH_MANTA')
if env['WITH_BF_FRAMESERVER']:
defs.append('WITH_FRAMESERVER')
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index c477aabbb71..2b9f7cf1bc5 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -574,6 +574,17 @@ static void ptcache_smoke_error(void *smoke_v, const char *message)
#define SMOKE_CACHE_VERSION "1.04"
+static void writeArrToFile(char* name, float* arr, int numElements)
+{
+ FILE *filePtr;
+ filePtr = fopen(name,"w");
+ int i=0;
+ for (i = 0; i < numElements; i++) {
+ fprintf(filePtr, "%f \n", arr[i]);
+ }
+ fclose(filePtr);
+}
+
static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
{
SmokeModifierData *smd= (SmokeModifierData *)smoke_v;
@@ -587,7 +598,6 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
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));
-
if (sds->fluid) {
size_t res = sds->res[0]*sds->res[1]*sds->res[2];
float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
@@ -601,7 +611,13 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
ptcache_file_compressed_write(pf, (unsigned char *)sds->shadow, in_len, out, mode);
+
+ /* writeArrToFile("sh.txt", sds->shadow, res);
+ */
ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len, out, mode);
+
+ /* writeArrToFile("dens.txt", dens, res);
+*/
if (fluid_fields & SM_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);
@@ -617,8 +633,17 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v)
ptcache_file_compressed_write(pf, (unsigned char *)b, in_len, out, mode);
}
ptcache_file_compressed_write(pf, (unsigned char *)vx, in_len, out, mode);
+
+/* writeArrToFile("vx.txt", vx, res);
+*/
ptcache_file_compressed_write(pf, (unsigned char *)vy, in_len, out, mode);
+
+/* writeArrToFile("vy.txt", vx, res);
+*/
ptcache_file_compressed_write(pf, (unsigned char *)vz, in_len, out, mode);
+
+/* writeArrToFile("vz.txt", vx, res);
+*/
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));
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 559e1e05f3f..7b3c84f7235 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -169,6 +169,7 @@ void flame_get_spectrum(unsigned char *UNUSED(spec), int UNUSED(width), float UN
#ifdef WITH_SMOKE
+
void smoke_reallocate_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old)
{
int use_heat = (sds->active_fields & SM_ACTIVE_HEAT);
@@ -181,10 +182,13 @@ void smoke_reallocate_fluid(SmokeDomainSettings *sds, float dx, int res[3], int
sds->fluid = NULL;
return;
}
- sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors);
+ sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors, sds->smd);
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));
+ /*initializing mantaflow fields only if low-res sim
+ if wavelets present, init in smoke_reallocate_highres_fluid
+ */
/* reallocate shadow buffer */
if (sds->shadow)
MEM_freeN(sds->shadow);
@@ -538,7 +542,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->alpha = -0.001;
smd->domain->beta = 0.1;
smd->domain->time_scale = 1.0;
- smd->domain->vorticity = 2.0;
+ smd->domain->vorticity = 0.01;
smd->domain->border_collisions = SM_BORDER_OPEN; // open domain
smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG;
smd->domain->highres_sampling = SM_HRES_FULLSAMPLE;
@@ -563,6 +567,18 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG;
smd->domain->effector_weights = BKE_add_effector_weights(NULL);
+
+ /*mantaflow settings*/
+ smd-> domain->manta_solver_res = 3;
+ smd->domain->manta_sim_frame = -1;
+ smd-> domain->manta_start_frame = 1;
+ smd-> domain->manta_end_frame = 10;
+ smd->domain->noise_clamp_neg = 0;
+ smd->domain->noise_clamp_pos = 1;
+ smd->domain->noise_val_scale = 0.;
+ smd->domain->noise_val_offset = 0.075;
+ smd->domain->noise_time_anim = 0.2;
+ BLI_make_file_string("/", smd->domain->_manta_filepath, BLI_temp_dir_base(), "manta_scene.py");
}
else if (smd->type & MOD_SMOKE_TYPE_FLOW)
{
@@ -852,6 +868,7 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
unsigned int collIndex;
unsigned char *obstacles = smoke_get_obstacle(sds->fluid);
+ int *manta_obstacles = smoke_get_manta_flags(sds->fluid);
float *velx = NULL;
float *vely = NULL;
float *velz = NULL;
@@ -901,20 +918,25 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
if (collobjs)
MEM_freeN(collobjs);
-
+
+ float *manta_obs_sdf = MEM_callocN(sds->res[0] * sds->res[1] * sds->res[2] * sizeof(float), "manta_obstacle_SDF");
/* 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++)
+ int loopLimit = (sds->manta_solver_res == 3)?sds->res[0] * sds->res[1] * sds->res[2]:sds->res[0] * sds->res[2];
+ for (z = 0; z < loopLimit; z++)
{
+ manta_obs_sdf[z] = 0.;
if (obstacles[z])
{
- velxOrig[z] = 0;
- velyOrig[z] = 0;
- velzOrig[z] = 0;
+ manta_obs_sdf[z] = 1.;
+ manta_obstacles[z] = 2;/*manta obstacle flag*/
+// velxOrig[z] = 0;
+// velyOrig[z] = 0;
+// velzOrig[z] = 0;
density[z] = 0;
- if (fuel) {
- fuel[z] = 0;
- flame[z] = 0;
- }
+// if (fuel) {
+// fuel[z] = 0;
+// flame[z] = 0;
+// }
if (r) {
r[z] = 0;
g[z] = 0;
@@ -922,6 +944,7 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
}
}
}
+ MEM_freeN(manta_obs_sdf);
}
@@ -1554,6 +1577,7 @@ static void sample_derivedmesh(
static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
{
+ clock_t start = clock();
if (sfs->dm) {
DerivedMesh *dm;
int defgrp_index = sfs->vgroup_density - 1;
@@ -1696,6 +1720,10 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
dm->needsFree = 1;
dm->release(dm);
}
+ clock_t end = clock();
+ float seconds = (float)(end - start) / CLOCKS_PER_SEC;
+ printf("TIME FOR RECONSTRUCTING SDF: %f \n", seconds);
+ int kkk = 9;
}
/**********************************************************
@@ -2220,8 +2248,8 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
// we got nice flow object
SmokeFlowSettings *sfs = smd2->flow;
EmissionMap *em = &emaps[flowIndex];
-
float *density = smoke_get_density(sds->fluid);
+ float *inflow_grid = smoke_get_inflow_grid(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);
@@ -2246,7 +2274,11 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size;
size_t e_index, d_index, index_big;
-
+ float *manta_big_inflow_sdf;
+ if ((sds->flags & MOD_SMOKE_USE_MANTA) && (bigdensity)){
+ smoke_turbulence_get_res(sds->wt, bigres);
+ manta_big_inflow_sdf = MEM_callocN(bigres[0] * bigres[1] * bigres[2] * sizeof(float), "manta_highres_inflow");
+ }
// 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++)
@@ -2267,12 +2299,15 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
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, inflow_grid, heat, fuel, react, color_r, color_g, color_b);
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(sds->manta_solver_res == 3){
+ apply_inflow_fields(sfs, emission_map[e_index], d_index, inflow_grid, 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]);
@@ -2359,11 +2394,31 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
}
else { // inflow
apply_inflow_fields(sfs, interpolated_value, index_big, bigdensity, NULL, bigfuel, bigreact, bigcolor_r, bigcolor_g, bigcolor_b);
+ if(sds->flags & MOD_SMOKE_USE_MANTA){
+ manta_big_inflow_sdf[index_big] = interpolated_value;
+ }
}
} // hires loop
} // bigdensity
} // low res loop
+ { /*2D solver*/
+ int cnty;
+ int cntz;
+ int step;
+ for ( cnty=0;cnty<sds->res_max[1]; ++cnty)
+ for( cntz=0;cntz<sds->res_max[2]; ++cntz)
+ {
+ step = sds->res_max[0]/2 + cnty * sds->res_max[0] + cntz * sds->res_max[0]*sds->res_max[1];
+ inflow_grid[cnty + cntz*sds->res_max[0]] = density[step];
+ }
+ }
+
+ if((sds->flags & MOD_SMOKE_USE_MANTA) && (bigdensity)){
+// manta_write_emitters(sfs,true,0,0,0,bigres[0], bigres[1], bigres[2], bigres[0], bigres[1], bigres[2],manta_big_inflow_sdf, NULL);
+ MEM_freeN(manta_big_inflow_sdf);
+ }
+
// free emission maps
em_freeData(em);
@@ -2409,10 +2464,8 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds,
float mag;
float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
-
if (((fuel ? MAX2(density[index], fuel[index]) : density[index]) < FLT_EPSILON) || obstacle[index])
continue;
-
vel[0] = velocity_x[index];
vel[1] = velocity_y[index];
vel[2] = velocity_z[index];
@@ -2448,6 +2501,74 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds,
pdEndEffectors(&effectors);
}
+void manta_update_effectors(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 = pdInitEffectors(scene, ob, NULL, sds->effector_weights, true);
+
+ if (effectors)
+ {
+ float *density = smoke_get_density(sds->fluid);
+ float *fuel = smoke_get_fuel(sds->fluid);
+ float *force_x = smoke_get_force_x(sds->fluid);
+ float *force_y = smoke_get_force_y(sds->fluid);
+ float *force_z = smoke_get_force_z(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);
+ int x;
+
+ // precalculate wind forces
+#pragma omp parallel for schedule(static)
+ for (x = 0; x < sds->res[0]; x++)
+ {
+ int y, z;
+ for (y = 0; y < sds->res[1]; y++)
+ for (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};
+ unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
+
+ vel[0] = velocity_x[index];
+ vel[1] = velocity_y[index];
+ vel[2] = 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(scene, voxelCenter, vel, index, &epoint);
+ pdDoEffectors(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!
+ force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f);
+ force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f);
+ force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f);
+ }
+ }
+ }
+
+ pdEndEffectors(&effectors);
+}
+
static void step(Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh *domain_dm, float fps, bool for_render)
{
SmokeDomainSettings *sds = smd->domain;
@@ -2523,7 +2644,8 @@ static void step(Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh *
if (sds->total_cells > 1) {
update_effectors(scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
- smoke_step(sds->fluid, gravity, dtSubdiv);
+ smoke_step(sds->fluid, gravity, dtSubdiv);
+
}
}
}
@@ -2659,6 +2781,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
else if (smd->type & MOD_SMOKE_TYPE_DOMAIN)
{
SmokeDomainSettings *sds = smd->domain;
+ sds->manta_obj = ob;
PointCache *cache = NULL;
PTCacheID pid;
int startframe, endframe, framenr;
@@ -2669,6 +2792,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
//printf("time: %d\n", scene->r.cfra);
cache = sds->point_cache[0];
+
BKE_ptcache_id_from_smoke(&pid, ob, smd);
BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
@@ -2695,14 +2819,14 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
printf("bad smokeModifier_init\n");
return;
}
-
+
/* try to read from cache */
if (BKE_ptcache_read(&pid, (float)framenr) == PTCACHE_READ_EXACT) {
BKE_ptcache_validate(cache, framenr);
smd->time = framenr;
return;
}
-
+
/* only calculate something when we advanced a single frame */
if (framenr != (int)smd->time + 1)
return;
@@ -2725,8 +2849,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
// simulate the actual smoke (c++ code in intern/smoke)
// DG: interesting commenting this line + deactivating loading of noise files
- if (framenr != startframe)
- {
+ 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);
@@ -2734,20 +2857,16 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
if (sds->wt) {
smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG);
}
-
}
-
step(scene, ob, smd, dm, scene->r.frs_sec / scene->r.frs_sec_base, for_render);
}
-
// create shadows before writing cache so they get stored
smoke_calc_transparency(sds, scene);
- if (sds->wt)
+ if (sds->wt&& !(smd->domain->flags & MOD_SMOKE_USE_MANTA))
{
smoke_turbulence_step(sds->wt, sds->fluid);
}
-
BKE_ptcache_validate(cache, framenr);
if (framenr != startframe)
BKE_ptcache_write(&pid, framenr);
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index b5adf38527b..d96bba4da45 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -54,6 +54,7 @@
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_smoke.h"
#include "LBM_fluidsim.h"
@@ -65,6 +66,11 @@
#include "physics_intern.h" // own include
/* enable/disable overall compilation */
+/*mantaflow include*/
+#include "../../../../intern/smoke/extern/smoke_API.h"
+//#include "../../blenkernel/intern/smoke.c"
+#include "DNA_smoke_types.h"
+
#ifdef WITH_MOD_FLUID
#include "WM_api.h"
@@ -72,7 +78,6 @@
#include "DNA_scene_types.h"
#include "DNA_mesh_types.h"
-
static float get_fluid_viscosity(FluidsimSettings *settings)
{
return (1.0f/powf(10.0f, settings->viscosityExponent)) * settings->viscosityValue;
@@ -1127,3 +1132,129 @@ void FLUID_OT_bake(wmOperatorType *ot)
ot->poll = ED_operator_object_active_editable;
}
+
+
+static int manta_make_file_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Scene *scene= CTX_data_scene(C);
+ SmokeModifierData *smd;
+ Object * smokeDomain = CTX_data_active_object(C);
+ smd = (SmokeModifierData *)modifiers_findByType(smokeDomain, eModifierType_Smoke);
+ /* return OPERATOR_CANCELLED;*/
+
+ return OPERATOR_FINISHED;
+}
+
+static int manta_make_file_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ SmokeModifierData *smd;
+ Object * smokeDomain = CTX_data_active_object(C);
+ smd = (SmokeModifierData *)modifiers_findByType(smokeDomain, eModifierType_Smoke);
+
+ if (smd->domain->fluid == NULL)
+ {
+ smoke_reallocate_fluid(smd->domain, smd->domain->dx, smd->domain->res, 1);
+ if (smd->domain->flags & MOD_SMOKE_HIGHRES) {
+ smoke_reallocate_highres_fluid(smd->domain, smd->domain->dx, smd->domain->res, 1);
+ }
+ }
+ if (smd->domain->fluid)
+ {
+ smoke_manta_export(smd);
+ }
+
+ /* return OPERATOR_CANCELLED;*/
+
+ return OPERATOR_FINISHED;
+}
+
+
+void MANTA_OT_make_file(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Create Mantaflow File";
+ ot->description = "Create Python Script for Simulation";
+ ot->idname = "MANTA_OT_make_file";
+
+ /* api callbacks */
+ ot->invoke = manta_make_file_invoke;
+ ot->exec = manta_make_file_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
+
+static int manta_sim_step_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Scene *scene= CTX_data_scene(C);
+ SmokeModifierData *smd;
+ Object * smokeDomain = CTX_data_active_object(C);
+ smd = (SmokeModifierData *)modifiers_findByType(smokeDomain, eModifierType_Smoke);
+ /* return OPERATOR_CANCELLED;*/
+
+ return OPERATOR_FINISHED;
+}
+
+static int manta_sim_step_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ SmokeModifierData *smd;
+ Object * smokeDomain = CTX_data_active_object(C);
+ smd = (SmokeModifierData *)modifiers_findByType(smokeDomain, eModifierType_Smoke);
+
+ /* return OPERATOR_CANCELLED;*/
+
+ return OPERATOR_FINISHED;
+}
+
+
+void MANTA_OT_sim_step(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Run Mantaflow Step";
+ ot->description = "Run One Step of Mantaflow Simulation";
+ ot->idname = "MANTA_OT_sim_step";
+
+ /* api callbacks */
+ ot->invoke = manta_sim_step_invoke;
+ ot->exec = manta_sim_step_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
+
+static int manta_stop_sim_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+// Scene *scene= CTX_data_scene(C);
+ SmokeModifierData *smd;
+ Object * smokeDomain = CTX_data_active_object(C);
+ smd = (SmokeModifierData *)modifiers_findByType(smokeDomain, eModifierType_Smoke);
+ smoke_mantaflow_stop_sim(smd->domain->fluid);
+ /* return OPERATOR_CANCELLED;*/
+
+ return OPERATOR_FINISHED;
+}
+
+static int manta_stop_sim_exec(bContext *C, wmOperator *op)
+{
+// Scene *scene= CTX_data_scene(C);
+ SmokeModifierData *smd;
+ Object * smokeDomain = CTX_data_active_object(C);
+ smd = (SmokeModifierData *)modifiers_findByType(smokeDomain, eModifierType_Smoke);
+ smoke_mantaflow_stop_sim(smd->domain->fluid);
+
+ /* return OPERATOR_CANCELLED;*/
+
+ return OPERATOR_FINISHED;
+}
+
+
+void MANTA_OT_stop_sim(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Stop Mantaflow Sim";
+ ot->description = "Stop Mantaflow Sim";
+ ot->idname = "MANTA_OT_stop_sim";
+
+ /* api callbacks */
+ ot->invoke = manta_stop_sim_invoke;
+ ot->exec = manta_stop_sim_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 666ed2397d2..3bb87b80333 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -92,7 +92,9 @@ void BOID_OT_state_move_down(struct wmOperatorType *ot);
/* physics_fluid.c */
void FLUID_OT_bake(struct wmOperatorType *ot);
-
+void MANTA_OT_make_file(struct wmOperatorType *ot);
+void MANTA_OT_sim_step(struct wmOperatorType *ot);
+void MANTA_OT_stop_sim(struct wmOperatorType *ot);
/* dynamicpaint.c */
void DPAINT_OT_bake(struct wmOperatorType *ot);
void DPAINT_OT_surface_slot_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index c765bff796e..cc87e61ff61 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -178,6 +178,16 @@ static void operatortypes_fluid(void)
WM_operatortype_append(FLUID_OT_bake);
}
+/********************************* manta ***********************************/
+
+static void operatortypes_manta(void)
+{
+ WM_operatortype_append(MANTA_OT_make_file);
+ WM_operatortype_append(MANTA_OT_sim_step);
+ WM_operatortype_append(MANTA_OT_stop_sim);
+}
+
+
/**************************** point cache **********************************/
static void operatortypes_pointcache(void)
@@ -219,6 +229,7 @@ void ED_operatortypes_physics(void)
operatortypes_particle();
operatortypes_boids();
operatortypes_fluid();
+ operatortypes_manta();
operatortypes_pointcache();
operatortypes_dynamicpaint();
}
diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h
index 25c98b4f07e..f3a88f94029 100644
--- a/source/blender/makesdna/DNA_smoke_types.h
+++ b/source/blender/makesdna/DNA_smoke_types.h
@@ -37,10 +37,13 @@ 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 */
+ MOD_SMOKE_USE_MANTA = (1 << 4),
MOD_SMOKE_HIGH_SMOOTH = (1 << 5), /* -- Deprecated -- */
MOD_SMOKE_FILE_LOAD = (1 << 6), /* flag for file load */
MOD_SMOKE_ADAPTIVE_DOMAIN = (1 << 7),
+ MOD_SMOKE_NOISE_CLAMP = (1 << 8), /*for mantaflow*/
+ MOD_SMOKE_MANTA_USE_LIQUID = (1 << 9),/*enable liquid simulation*/
};
#if (DNA_DEPRECATED_GCC_POISON == 1)
@@ -79,6 +82,14 @@ enum {
#define SM_ACTIVE_COLORS (1<<2)
#define SM_ACTIVE_COLOR_SET (1<<3)
+/*Container for all smoke solvers: blender and manta*/
+typedef struct SmokeSolvers{
+ int type;/*which solver is currently active*/
+ int mock_var;
+ struct FLUID_3D *fluid_blender;
+
+}SmokeSolvers;
+
typedef struct SmokeDomainSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
struct FLUID_3D *fluid;
@@ -91,6 +102,7 @@ typedef struct SmokeDomainSettings {
struct GPUTexture *tex_wt;
struct GPUTexture *tex_shadow;
struct GPUTexture *tex_flame;
+ struct Object *manta_obj;
float *shadow;
/* simulation data */
@@ -106,6 +118,8 @@ typedef struct SmokeDomainSettings {
float imat[4][4]; /* domain object imat */
float obmat[4][4]; /* domain obmat */
+ char _manta_filepath[1024]; /* FILE_MAX */
+
int base_res[3]; /* initial "non-adapted" resolution */
int res_min[3]; /* cell min */
int res_max[3]; /* cell max */
@@ -149,9 +163,22 @@ typedef struct SmokeDomainSettings {
float burning_rate, flame_smoke, flame_vorticity;
float flame_ignition, flame_max_temp;
float flame_smoke_color[3];
+ /* mantaflow settings */
+ int manta_solver_res; /*dimension of manta solver, 2d or 3d*/
+ int manta_start_frame;
+ int manta_end_frame;
+ int manta_uvs_num; /*number of UVs, important for octaves count*/
+ /*noise settings*/
+ float noise_clamp_neg;
+ float noise_clamp_pos;
+ float noise_val_scale;
+ float noise_val_offset;
+ float noise_time_anim;
+ int manta_sim_frame;/*current simulation frame number. If not simulating-> manta_sim_frame == -1*/
+ float mock_var; /*not used*/
+// float mock_var2; /*not used*/
} SmokeDomainSettings;
-
/* inflow / outflow */
/* type */
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index fa7fd6da8bb..fa94e345e3f 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -254,6 +254,10 @@ if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
endif()
+if(WITH_MOD_MANTA)
+ add_definitions(-DWITH_MANTA)
+endif()
+
if(WITH_MOD_OCEANSIM)
add_definitions(-DWITH_OCEANSIM)
endif()
diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript
index 3d190fc6a13..e3dbab0ffa7 100644
--- a/source/blender/makesrna/intern/SConscript
+++ b/source/blender/makesrna/intern/SConscript
@@ -62,6 +62,7 @@ incs = [
'#/intern/audaspace/intern',
'#/intern/cycles/blender',
'#/intern/smoke/extern',
+ '#/source//blender/python/manta_pp',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
@@ -81,6 +82,9 @@ incs = ' '.join(incs)
if env['WITH_BF_SMOKE']:
defs.append('WITH_SMOKE')
+if env['WITH_BF_MANTA']:
+ defs.append('WITH_MANTA')
+
if env['WITH_BF_BULLET']:
defs.append('WITH_BULLET')
incs += ' #/intern/rigidbody'
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 55262a98b2e..221b311aa9e 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -97,6 +97,26 @@ static void rna_Smoke_reset_dependency(Main *bmain, Scene *scene, PointerRNA *pt
rna_Smoke_dependency_update(bmain, scene, ptr);
}
+static void rna_Smoke_manta_write_settings(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
+ rna_Smoke_reset(bmain,scene,ptr);
+}
+
+static void rna_Smoke_manta_switch2D(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
+ if (settings->manta_solver_res == 2)
+ {
+ settings->base_res[1] = 1;
+ }
+ else if(settings->manta_solver_res == 3)
+ {
+ settings->base_res[1] = 5;
+ }
+ rna_Smoke_reset(bmain,scene,ptr);
+}
+
static char *rna_SmokeDomainSettings_path(PointerRNA *ptr)
{
SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data;
@@ -544,6 +564,99 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
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");
+
+ /* mantaflow variables */
+ prop = RNA_def_property(srna, "use_manta", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_USE_MANTA);
+ RNA_def_property_ui_text(prop, "MantaFlow", "Use Mantaflow");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_manta_write_settings");
+
+ prop = RNA_def_property(srna, "manta_filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_string_sdna(prop, NULL, "_manta_filepath");
+ RNA_def_property_ui_text(prop, "Output Path",
+ "Directory/name to save Mantaflow scene for further simulations");
+// RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_manta_write_settings");
+
+ prop = RNA_def_property(srna, "use_manta_liquid", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_MANTA_USE_LIQUID);
+ RNA_def_property_ui_text(prop, "MantaFlow Liquid", "Use Mantaflow liquid");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "manta_solver_res", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "manta_solver_res");
+ RNA_def_property_range(prop, 2, 3);
+ RNA_def_property_ui_range(prop, 2, 3, 1, -1);
+ RNA_def_property_ui_text(prop, "Solver Res", "Solver resolution(2D/3D)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_manta_switch2D");
+
+ prop = RNA_def_property(srna, "manta_sim_frame", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "manta_sim_frame");
+ RNA_def_property_range(prop, -1, 250);
+ RNA_def_property_ui_range(prop, -1, 250, 1, -1);
+ RNA_def_property_ui_text(prop, "Current Simulation Frame", "-1, if not simulating");
+
+ prop = RNA_def_property(srna, "manta_start_frame", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "manta_start_frame");
+ RNA_def_property_range(prop, 0, 249);
+ RNA_def_property_ui_range(prop, 0, 249, 1, -1);
+ RNA_def_property_ui_text(prop, "Sim Start", "Frame from which to start simulation");
+// RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "manta_end_frame", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "manta_end_frame");
+ RNA_def_property_range(prop, 1, 250);
+ RNA_def_property_ui_range(prop, 1, 250, 1, -1);
+ RNA_def_property_ui_text(prop, "Sim End", "Frame on which to end simulation");
+// RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "manta_uvs", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "manta_uvs_num");
+ RNA_def_property_range(prop, 0, 4);
+ RNA_def_property_ui_range(prop, 0, 4, 1, -1);
+ RNA_def_property_ui_text(prop, "UVs number", "Number of UV coordinate grids to use(Better not more than 2)");
+// RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
+
+ prop = RNA_def_property(srna, "manta_clamp_noise", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_NOISE_CLAMP);
+ RNA_def_property_ui_text(prop, "MantaFlow", "Use Mantaflow");
+// RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "noise_clamp_neg", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "noise_clamp_neg");
+ 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, "Clamp Negative Noise", "");
+// RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "noise_clamp_pos", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "noise_clamp_pos");
+ 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, "Clamp Positive Noise", "");
+// RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "noise_val_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "noise_val_scale");
+ 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, "Noise Value Scale", "");
+// RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "noise_val_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "noise_val_offset");
+ 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, "Noise Value Offset", "");
+// RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_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.0, 2.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 5);
+ RNA_def_property_ui_text(prop, "Noise animation time", "");
+// RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+
}
static void rna_def_smoke_flow_settings(BlenderRNA *brna)
diff --git a/source/blender/python/CMakeLists.txt b/source/blender/python/CMakeLists.txt
index e855f3a3756..550e791425c 100644
--- a/source/blender/python/CMakeLists.txt
+++ b/source/blender/python/CMakeLists.txt
@@ -20,3 +20,5 @@ add_subdirectory(intern)
add_subdirectory(generic)
add_subdirectory(mathutils)
add_subdirectory(bmesh)
+#choose "manta_pp" for preprocessed files or "manta_full" for full manta module
+add_subdirectory(manta_pp)
diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript
index 5f032f25cf3..3b46b3ff917 100644
--- a/source/blender/python/SConscript
+++ b/source/blender/python/SConscript
@@ -78,6 +78,12 @@ defs = []
sources = env.Glob('mathutils/*.c')
env.BlenderLib( libname = 'bf_python_mathutils', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core','player'], priority = [362,165])
+# manta
+defs = []
+
+sources = env.Glob('manta_pp/source/*')
+env.BlenderLib( libname = 'bf_python_manta', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core','player'])
+
# bpy
defs = env['BF_GL_DEFINITIONS']
@@ -186,6 +192,9 @@ if env['WITH_BF_REMESH']:
if env['WITH_BF_SMOKE']:
defs.append('WITH_SMOKE')
+if env['WITH_BF_MANTA']:
+ defs.append('WITH_MANTA')
+
if env['WITH_BF_COLLADA']:
defs.append('WITH_COLLADA')
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 8296027f044..42112d41ea6 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -253,6 +253,10 @@ if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
endif()
+if(WITH_MOD_MANTA)
+ add_definitions(-DWITH_MANTA)
+endif()
+
if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 5b4db89a41a..f0c0e2c5fe8 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -83,6 +83,8 @@
#include "../bmesh/bmesh_py_api.h"
#include "../mathutils/mathutils.h"
+#include "../manta_pp/pwrapper/manta_api.h"
+
/* for internal use, when starting and ending python scripts */
@@ -223,6 +225,7 @@ static struct _inittab bpy_internal_modules[] = {
{"bgl", BPyInit_bgl},
{"blf", BPyInit_blf},
{"bmesh", BPyInit_bmesh},
+ { "manta", PyInit_Manta},
#if 0
{"bmesh.types", BPyInit_bmesh_types},
{"bmesh.utils", BPyInit_bmesh_utils},
@@ -275,7 +278,7 @@ void BPY_python_start(int argc, const char **argv)
#endif
Py_FrozenFlag = 1;
-
+// PyImport_AppendInittab("manta", PyInit_Manta);
Py_Initialize();
// PySys_SetArgv(argc, argv); /* broken in py3, not a huge deal */
diff --git a/source/blender/python/manta_full/CMakeLists.txt b/source/blender/python/manta_full/CMakeLists.txt
new file mode 100755
index 00000000000..d04c70bae72
--- /dev/null
+++ b/source/blender/python/manta_full/CMakeLists.txt
@@ -0,0 +1,597 @@
+#******************************************************************************
+#
+# MantaFlow fluid solver framework
+#
+# Copyright 2011-2014 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
+#
+#******************************************************************************
+
+#project (MantaFlow)
+cmake_minimum_required(VERSION 2.8) # 2.8 needed for CUDA
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/source/cmake/")
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+SET(VERBOSE 1)
+
+SET(MANTAVERSION "0.6")
+#******************************************************************************
+# Default paths
+# - CMake's path finder is completely useless for Qt5 + Python on Win64
+
+IF(WIN32)
+ set(WIN_QT_PATH "C:/Qt/Qt5.2.1/5.2.1/msvc2012_64_opengl") # qt5/win64
+ # set(WIN_QT_PATH "C:/Qt/4.8.6") # qt4/win32
+ set(WIN_PYTHON_PATH "C:/Python34")
+ set(WIN_PYTHON_VERSION "34")
+ set(CMAKE_LIBRARY_PATH "C:/Program Files (x86)/Windows Kits/8.0/Lib/win8/um/x64")
+ SET(CMAKE_PREFIX_PATH ${WIN_QT_PATH})
+ENDIF()
+
+IF(APPLE)
+ SET(CMAKE_PREFIX_PATH "/usr/local/Cellar/qt5/5.2.1/") # mac/homebrew
+ENDIF()
+
+#******************************************************************************
+# setup default params
+
+IF(NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE "Debug")
+ELSE()
+ MESSAGE("Build-type: '${CMAKE_BUILD_TYPE}'")
+ENDIF()
+
+# compilation versions
+OPTION(DEBUG "Enable debug compilation" OFF)
+OPTION(GUI "Compile with GUI (requires QT)" OFF)
+OPTION(TBB "Use multi-thread kernels using Intels TBB" OFF)
+OPTION(OPENMP "Use multi-thread kernels using OpenMP" OFF)
+OPTION(CUDA "Compile with CUDA plugins" OFF)
+OPTION(PREPDEBUG "Debug generated files" OFF) # This will beautify generated files, and link to them for compiler errors instead of the original sources
+OPTION(DOUBLEPRECISION "Compile with double floating point precision" OFF)
+
+#check consistency of MT options
+set(MT OFF)
+set(MT_TYPE "NONE")
+if (TBB)
+ set (MT_TYPE "TBB")
+ set (MT ON)
+endif()
+if (OPENMP)
+ set (MT_TYPE "OPENMP")
+ set (MT ON)
+endif()
+if (TBB AND OPENMP)
+ message(FATAL_ERROR "Cannot activate both OPENMP and TBB")
+endif()
+
+# make sure debug settings match...
+IF(NOT DEBUG)
+ IF(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
+ SET(DEBUG 1)
+ ENDIF()
+ENDIF()
+IF(DEBUG)
+ SET(CMAKE_BUILD_TYPE "Debug")
+ add_definitions ( -DDEBUG )
+ENDIF()
+
+MESSAGE(STATUS "")
+MESSAGE(STATUS "Options - "
+ " -DDEBUG='${DEBUG}' "
+ " -DGUI='${GUI}' "
+ " -DTBB='${TBB}' "
+ " -DOPENMP='${OPENMP}' "
+ " -DPREPDEBUG='${PREPDEBUG}' "
+ " -DCUDA='${CUDA}' "
+ " -DDOUBLEPRECISION='${DOUBLEPRECISION}' "
+ )
+MESSAGE(STATUS "Multithreading type : ${MT_TYPE}")
+MESSAGE(STATUS "")
+
+#******************************************************************************
+# Pre-processor
+
+# compile prep
+SET(SOURCES
+ source/preprocessor/main.cpp
+ source/preprocessor/code.cpp
+ source/preprocessor/tokenize.cpp
+ source/preprocessor/parse.cpp
+ source/preprocessor/util.cpp
+ source/preprocessor/merge.cpp
+ source/preprocessor/codegen_python.cpp
+ source/preprocessor/codegen_kernel.cpp
+)
+add_executable(prep ${SOURCES})
+if (NOT WIN32)
+#PR commented
+# set_target_properties(prep PROPERTIES COMPILE_FLAGS "-Wall -O2")
+endif()
+
+#******************************************************************************
+# Setup main project
+
+SET(F_LIBS "" )
+SET(F_LIB_PATHS)
+SET(F_LINKADD "") # additional linker flags, not a list
+set(PP_PATH "pp")
+SET(SILENT_SOURCES)
+
+# need pre-processing
+SET(PP_SOURCES
+ source/fluidsolver.cpp
+ source/conjugategrad.cpp
+ source/grid.cpp
+ source/levelset.cpp
+ source/fastmarch.cpp
+ source/shapes.cpp
+ source/mesh.cpp
+ source/general.cpp
+ source/particle.cpp
+ source/flip.cpp
+ source/movingobs.cpp
+ source/fileio.cpp
+ source/noisefield.cpp
+ source/kernel.cpp
+ source/vortexsheet.cpp
+ #source/vortexfilament.cpp
+ source/vortexpart.cpp
+ source/turbulencepart.cpp
+ source/edgecollapse.cpp
+
+ source/plugin/pressure.cpp
+ source/plugin/initplugins.cpp
+ #PR changed
+ source/plugin/advection.cpp
+ source/plugin/extforces.cpp
+ source/plugin/kepsilon.cpp
+ source/plugin/meshplugins.cpp
+ source/plugin/vortexplugins.cpp
+ source/plugin/waveletturbulence.cpp
+ source/python/defines.py
+ source/test.cpp
+)
+
+SET(PP_HEADERS
+ source/commonkernels.h
+ source/conjugategrad.h
+ source/fastmarch.h
+ source/fluidsolver.h
+ source/grid.h
+ source/mesh.h
+ source/particle.h
+ source/levelset.h
+ source/shapes.h
+ source/noisefield.h
+ source/vortexsheet.h
+ #source/vortexfilament.h
+ source/general.h
+ source/kernel.h
+ source/flip.h
+ source/movingobs.h
+ source/fileio.h
+ source/edgecollapse.h
+ source/vortexpart.h
+ source/turbulencepart.h
+ #source/test.h
+ #PR changed
+# source/advection.h
+)
+
+# no pre-processing needed
+set(NOPP_SOURCES
+ source/pwrapper/pymain.cpp
+ source/pwrapper/pclass.cpp
+ source/pwrapper/pvec3.cpp
+ source/pwrapper/pconvert.cpp
+ source/pwrapper/registry.cpp
+ source/util/vectorbase.cpp
+ source/pwrapper/manta_api.cpp
+)
+
+SET(NOPP_HEADERS
+ source/pwrapper/pythonInclude.h
+ source/pwrapper/pclass.h
+ source/pwrapper/registry.h
+ source/pwrapper/pconvert.h
+ source/util/integrator.h
+ source/util/vectorbase.h
+ source/util/quaternion.h
+ source/util/interpol.h
+ source/util/mcubes.h
+ source/util/randomstream.h
+ source/util/solvana.h
+ source/pwrapper/manta_api.h
+)
+
+if (GUI)
+ # need QT preprocessor
+ set(QT_HEADERS
+ source/gui/mainwindow.h
+ source/gui/glwidget.h
+ source/gui/painter.h
+ source/gui/meshpainter.h
+ source/gui/qtmain.h
+ source/gui/customctrl.h
+ source/gui/particlepainter.h
+ )
+ set(QT_SOURCES
+ source/gui/customctrl.cpp
+ source/gui/mainwindow.cpp
+ source/gui/glwidget.cpp
+ source/gui/customctrl.cpp
+ source/gui/painter.cpp
+ source/gui/meshpainter.cpp
+ source/gui/particlepainter.cpp
+ source/gui/qtmain.cpp
+ )
+ list(APPEND PP_SOURCES ${QT_SOURCES})
+ list(APPEND PP_HEADERS ${QT_HEADERS})
+endif()
+
+# CUDA sources
+if (CUDA)
+ list(APPEND PP_SOURCES
+ source/cuda/meshtools.cu
+ source/cuda/buoyancy.cu
+ source/cuda/particle.cu
+ )
+endif()
+
+# include dirs
+message("PRincluding _ ${CMAKE_CURRENT_BINARY_DIR}/${PP_PATH}/source")
+SET(INCLUDE_PATHS
+ source/pwrapper
+ source/cuda
+ source/util
+ ${CMAKE_CURRENT_BINARY_DIR}/${PP_PATH}/source
+ #PR added
+ ${CMAKE_CURRENT_BINARY_DIR}/${PP_PATH}/source/plugin
+)
+
+# Multithreading
+if(MT)
+ add_definitions( -DMT)
+ if(TBB)
+ # Intel TBB
+ add_definitions( -DTBB)
+
+ if (DEBUG)
+ add_definitions( -DTBB_USE_DEBUG=1 )
+ list(APPEND F_LIBS tbb)
+ else()
+ list(APPEND F_LIBS tbb)
+ endif()
+ if (WIN32)
+ find_package(TBB REQUIRED)
+ list(APPEND INCLUDE_PATHS ${TBB_INCLUDE_DIRS})
+ list(APPEND F_LIB_PATHS ${TBB_LIBRARY_DIRS})
+ elseif(APPLE)
+ find_package(TBB REQUIRED)
+ list(APPEND INCLUDE_PATHS ${TBB_INCLUDE_DIRS})
+ list(APPEND F_LIB_PATHS ${TBB_LIBRARY_DIRS})
+ endif()
+ else()
+ # OpenMP
+ add_definitions( -DOPENMP )
+
+ if (WIN32)
+ add_definitions( /openmp)
+ else()
+ add_definitions(-fopenmp)
+ SET(F_LINKADD "${F_LINKADD} -fopenmp ")
+ endif()
+ endif()
+endif()
+
+#******************************************************************************
+# add a target to generate API documentation with Doxygen
+
+find_package(Doxygen)
+if(DOXYGEN_FOUND)
+ set(DX_PATH "doxy")
+ foreach(it ${PP_SOURCES} ${PP_HEADERS} ${NOPP_SOURCES} ${NOPP_HEADERS})
+ get_filename_component(CURPATH ${it} PATH)
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${DX_PATH}/${CURPATH}")
+ set(CURDX "${DX_PATH}/${it}")
+ string(REPLACE "/" "_" TGT ${CURDX})
+ string(REPLACE "source/" "" INFILE ${it})
+ add_custom_command(OUTPUT ${TGT}
+ COMMAND prep docgen "0" ${MT_TYPE} "${CMAKE_CURRENT_SOURCE_DIR}/source/" "${INFILE}" "${CURDX}"
+ DEPENDS prep
+ IMPLICIT_DEPENDS CXX ${it}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ list(APPEND TGLIST ${TGT})
+ endforeach(it)
+
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
+ add_custom_target(doc
+ ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${TGLIST}
+ COMMENT "Generating API documentation with Doxygen" VERBATIM
+ )
+endif(DOXYGEN_FOUND)
+
+
+
+#******************************************************************************
+# Link libraries
+
+# Python
+#find_package(PythonLibs QUIET)
+#if((NOT PYTHONLIBS_FOUND) AND WIN32)
+# set(PYTHON_INCLUDE_DIR "${WIN_PYTHON_PATH}/include")
+# set(PYTHON_LIBRARY "${WIN_PYTHON_PATH}/libs/python${WIN_PYTHON_VERSION}.lib")
+#endif()
+#find_package(PythonLibs REQUIRED)
+#list(APPEND INCLUDE_PATHS ${PYTHON_INCLUDE_DIRS})
+#list(APPEND F_LIBS ${PYTHON_LIBRARIES})
+
+#PR PYTHON
+set(PYTHON_VERSION 3.4)
+set(PYTHON_INCLUDE_DIR "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/include/python${PYTHON_VERSION}m")
+set(PYTHON_BINARY "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/bin/python${PYTHON_VERSION}")
+#set(PYTHON_LIBRARY python${PYTHON_VERSION})
+set(PYTHON_LIBPATH "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/lib/python${PYTHON_VERSION}/config-${PYTHON_VERSION}m")
+#set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework Python") # won't build with this enabled
+find_package(PythonLibs REQUIRED)
+list(APPEND INCLUDE_PATHS ${PYTHON_INCLUDE_DIR})
+list(APPEND F_LIBS ${PYTHON_LIBRARIES})
+
+# Z compression
+if (1)
+ # default: build from source
+ set(ZLIB_SRC adler32.c compress.c crc32.c deflate.c gzclose.c gzlib.c gzread.c gzwrite.c
+ inflate.c infback.c inftrees.c inffast.c trees.c uncompr.c zutil.c)
+ foreach(it ${ZLIB_SRC})
+ list(APPEND SILENT_SOURCES dependencies/zlib-1.2.8/${it})
+
+ set(ZLIB_ADDFLAGS "")
+ if(NOT WIN32)
+ set(ZLIB_ADDFLAGS "-Wno-implicit-function-declaration")
+ endif()
+ endforeach(it)
+ set_source_files_properties(${SILENT_SOURCES} PROPERTIES COMPILE_FLAGS "${ZLIB_ADDFLAGS}")
+
+ list(APPEND INCLUDE_PATHS dependencies/zlib-1.2.8)
+else()
+ include(FindZLIB)
+ list(APPEND INCLUDE_PATHS ${ZLIB_INCLUDE_DIR})
+ list(APPEND F_LIBS ${ZLIB_LIBRARIES})
+endif()
+
+# CUDA
+if(CUDA)
+ add_definitions( -DCUDA=1 )
+ find_package(CUDA QUIET REQUIRED)
+ set(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE OFF)
+ # ? if (USE64) set(CUDA_64_BIT_DEVICE_CODE ON) endif()
+ if(WIN32)
+ if(DEBUG)
+ set(CUDA_NVCC_FLAGS -DDEBUG;--compiler-options;-Wall)
+ else()
+ set(CUDA_NVCC_FLAGS --use_fast_math;-DNDEBUG;--compiler-options;-Wall;-O2)
+ endif()
+ else()
+ # CUDA does not support gcc > 4.5 yet
+ if(DEBUG)
+ set(CUDA_NVCC_FLAGS --pre-include;/usr/local/include/undef_atomics_int128.h;-g;-DDEBUG;-keep;--maxrregcount=31;--compiler-options;-Wall)
+ else()
+ #set(CUDA_NVCC_FLAGS -ccbin;gcc-4.5;--use_fast_math;-arch=sm_20;-DNDEBUG;--compiler-options;-Wall;-O3)
+ set(CUDA_NVCC_FLAGS --pre-include;/usr/local/include/undef_atomics_int128.h;--use_fast_math;-DNDEBUG;--compiler-options;-Wall;-O3)
+ endif()
+ endif()
+endif()
+
+# increase FP precision?
+if(DOUBLEPRECISION)
+ add_definitions(-DFLOATINGPOINT_PRECISION=2)
+endif()
+
+
+#******************************************************************************
+# generate repository info
+
+# TEST! NT_DEBUG
+set(HGINFO "${CMAKE_CURRENT_BINARY_DIR}/${PP_PATH}/source/hginfo.h")
+MESSAGE(STATUS "Hg info target header ${HGINFO}")
+add_custom_command(OUTPUT ${HGINFO}
+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/tools/makeHgVersion.py" "${HGINFO}"
+ DEPENDS ${PP_SOURCES} ${PP_HEADERS} ${NOPP_SOURCES} ${NOPP_HEADERS} ${QT_SOURCES} ${QT_HEADERS}
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} )
+
+#******************************************************************************
+# apply preprocessor
+
+set(SOURCES ${NOPP_SOURCES} ${SILENT_SOURCES})
+set(HEADERS ${NOPP_HEADERS})
+set(PP_REGCPP)
+set(PP_REGS)
+set(PP_PREPD "0")
+MESSAGE("PRPRPRPRPR_prepdebug")
+
+if (PREPDEBUG)
+ set(PP_PREPD "1")
+endif()
+#MESSAGE("PR_prepdebug_1 BEFORE ${SOURCES}")
+foreach(it ${PP_HEADERS} ${PP_SOURCES})
+ get_filename_component(CURPATH ${it} PATH)
+ get_filename_component(CUREXT ${it} EXT)
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${PP_PATH}/${CURPATH}")
+ set(CURPP "${CMAKE_CURRENT_BINARY_DIR}/${PP_PATH}/${it}")
+ string(REPLACE "source/" "" INFILE ${it})
+ # preprocessor ${CMAKE_BINARY_DIR}/bin/
+ add_custom_command(OUTPUT ${CURPP}
+ COMMAND echo Workingdir
+ COMMAND pwd
+ COMMAND prep generate ${PP_PREPD} ${MT_TYPE} "${CMAKE_CURRENT_SOURCE_DIR}/source/" "${INFILE}" "${CURPP}"
+ DEPENDS prep
+ IMPLICIT_DEPENDS CXX ${it}
+# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ )
+ if ("${CUREXT}" STREQUAL ".h" OR "${CUREXT}" STREQUAL ".py")
+ list(APPEND PP_REGS "${CURPP}.reg")
+ list(APPEND PP_REGCPP "${CURPP}.reg.cpp")
+ set_source_files_properties("${CURPP}.reg.cpp" OBJECT_DEPENDS "${CURPP}")
+ endif()
+ list(APPEND SOURCES ${CURPP})
+endforeach(it)
+
+
+# link reg files
+add_custom_command(OUTPUT ${PP_REGCPP}
+ COMMAND prep link ${PP_REGS}
+ DEPENDS prep ${PP_REGS}
+# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Linking reg files")
+set_source_files_properties(${PP_REGS} ${PP_REGCPP} PROPERTIES GENERATED 1)
+MESSAGE("PR_prepdebug2")
+
+list(APPEND SOURCES ${PP_REGCPP})
+#MESSAGE("\nPR_prepdebug_1 AFTER REGCPP ${SOURCES}")
+
+#add_custom_target(run ALL
+# DEPENDS SOURCES)
+
+MESSAGE("PR_prepdebug3")
+
+#******************************************************************************
+#PR finding what is so special about GUI
+#list(APPEND INCLUDE_PATHS ${CMAKE_CURRENT_BINARY_DIR}
+# ${CMAKE_CURRENT_BINARY_DIR}/${PP_PATH}/source/gui source/gui)
+#SET(F_LINKADD "${F_LINKADD} -framework OpenGL ")
+
+#******************************************************************************
+# QT for GUI
+
+if(GUI)
+ # remap
+ set(QT_REMAP)
+ foreach(it ${QT_HEADERS})
+ list(APPEND QT_REMAP "${CMAKE_CURRENT_BINARY_DIR}/${PP_PATH}/${it}")
+ endforeach(it)
+ add_definitions(-DGUI=1)
+ list(APPEND INCLUDE_PATHS ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/${PP_PATH}/source/gui source/gui)
+
+ cmake_policy(SET CMP0020 NEW)
+ find_package(Qt5Core QUIET)
+ if (Qt5Core_FOUND)
+ message("Using Qt5")
+ find_package(Qt5Widgets REQUIRED)
+ find_package(Qt5OpenGL REQUIRED)
+
+ qt5_wrap_cpp(MOC_OUTFILES ${QT_REMAP} )
+ qt5_add_resources(QT_RES resources/res.qrc )
+ add_definitions(-DGUI=1)
+ add_definitions(${Qt5Widgets_DEFINITIONS})
+ list(APPEND INCLUDE_PATHS ${Qt5Widgets_INCLUDE_DIRS} ${Qt5OpenGL_INCLUDE_DIRS})
+ list(APPEND F_LIBS ${Qt5Widgets_LIBRARIES} ${Qt5OpenGL_LIBRARIES})
+ list(APPEND SOURCES ${MOC_OUTFILES} ${QT_RES})
+ else()
+ message("Using Qt4")
+# set(QT_QMAKE_EXECUTABLE /usr/bin/qmake-4.8)
+ find_package(Qt4 REQUIRED)
+ set(QT_USE_QTOPENGL TRUE)
+
+ qt4_wrap_cpp(MOC_OUTFILES ${QT_REMAP} )
+ qt4_add_resources(QT_RES resources/res.qrc )
+ include(${QT_USE_FILE})
+ add_definitions(${QT_DEFINITIONS})
+ list(APPEND F_LIBS ${QT_LIBRARIES})
+ list(APPEND SOURCES ${MOC_OUTFILES} ${QT_RES})
+ endif()
+
+ if (APPLE)
+ # mac opengl framework
+ SET(F_LINKADD "${F_LINKADD} -framework OpenGL ")
+ else()
+ find_package(OpenGL REQUIRED)
+ list(APPEND F_LIBS ${OPENGL_LIBRARIES})
+ endif()
+endif()
+
+#******************************************************************************
+# setup executable
+#MESSAGE("\nSETTINGS EXEC ${SOURCES}")
+
+# compiler flags
+IF(NOT WIN32)
+ IF(DEBUG)
+ add_definitions( -DDEBUG )
+ add_definitions( -O0 -fno-inline )
+ # additional c++ warning
+ SET(CMAKE_CXX_FLAGS_DEBUG " -ggdb -Wall")
+
+ # stricter: no optimizations and inlining, comment out if needed...
+ #SET(CMAKE_CXX_FLAGS_DEBUG " -O0 -fno-inline ${CMAKE_CXX_FLAGS_DEBUG} ")
+ ELSE()
+ # non-debug, optimized version
+ add_definitions( -O3 -Wall)
+ ENDIF()
+ELSE()
+ # get rid of some MSVC warnings
+ add_definitions( /wd4018 /wd4146 /wd4800 )
+
+ # for zlib
+ add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
+ add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
+
+ # unsigned to signed conversions
+ add_definitions( /wd4267 )
+ # double <> single precision
+ add_definitions( /wd4244 /wd4305 )
+ # disable warnings for unsecure functions
+ add_definitions( /D "_CRT_SECURE_NO_WARNINGS" )
+ENDIF()
+MESSAGE("PR_11")
+#SET(EXECCMD manta)
+SET(EXECCMD bf_python_manta)
+MESSAGE("PR_12")
+
+SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${F_LINKADD} ")
+SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${F_LINKADD} ")
+MESSAGE("PR_13 including parths: ${INCLUDE_PATHS}")
+
+include_directories( ${INCLUDE_PATHS})
+
+link_directories( ${F_LIB_PATHS} )
+MESSAGE("PR_14")
+#list(REMOVE_DUPLICATES SOURCES)
+if(CUDA)
+ #cuda_include_directories(pp/source/cuda)
+ cuda_add_executable( ${EXECCMD} ${SOURCES} ${PP_REGISTRY})
+ target_link_libraries( ${EXECCMD} ${F_LIBS} )
+ cuda_build_clean_target()
+else()
+ if (WIN32)
+ # make nice folders for Visual Studio
+ set_source_files_properties(${PP_SOURCES} ${PP_HEADERS} ${NOPP_HEADERS} PROPERTIES HEADER_FILE_ONLY TRUE)
+# add_executable(${EXECCMD} ${SOURCES} ${PP_REGISTRY} ${PP_SOURCES} ${PP_HEADERS})
+ blender_add_lib(${EXECCMD} "${SOURCES}" "${INCLUDE_PATHS}" "${INC_SYS}")
+ source_group(Generated FILES ${SOURCES} ${PP_REGISTRY} ${HEADERS})
+ else()
+ # add_executable(${EXECCMD} ${SOURCES} ${PP_REGISTRY} ${HGINFO})
+# list(SORT SOURCES)
+ list(REMOVE_DUPLICATES SOURCES) #CMAKE GUI says there are duplicates, though there are none
+ blender_add_lib(${EXECCMD} "${SOURCES}" "${INCLUDE_PATHS}" "${INC_SYS}")
+ endif()
+ target_link_libraries( ${EXECCMD} ${F_LIBS} )
+endif()
+MESSAGE("PR_15")
+
+
+if(WIN32)
+ # add no-build target to create nice MSVC folder
+ add_custom_target(SourceFiles SOURCES ${PP_SOURCES} ${PP_HEADERS} ${QT_SOURCES} ${QT_HEADERS} ${NOPP_HEADERS} ${NOPP_SOURCES})
+ source_group(Headers FILES ${PP_HEADERS} ${NOPP_HEADERS} ${QT_HEADERS})
+ source_group(Sources FILES ${PP_SOURCES} ${NOPP_SOURCES} ${QT_SOURCES})
+endif()
+
+# debug
+MESSAGE(STATUS "DEBUG Flag-Summary - Includes: '${INCLUDE_PATHS}' | Libs: '${F_LIBS}' | LibPaths: '${F_LIB_PATHS}' ") \ No newline at end of file
diff --git a/source/blender/python/manta_full/COPYING b/source/blender/python/manta_full/COPYING
new file mode 100644
index 00000000000..94a9ed024d3
--- /dev/null
+++ b/source/blender/python/manta_full/COPYING
@@ -0,0 +1,674 @@
+ 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/source/blender/python/manta_full/Doxyfile.in b/source/blender/python/manta_full/Doxyfile.in
new file mode 100644
index 00000000000..19c9ebf2440
--- /dev/null
+++ b/source/blender/python/manta_full/Doxyfile.in
@@ -0,0 +1,1719 @@
+# Doxyfile 1.7.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = mantaflow
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 0.5
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "A framework for fluid simulation"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @CMAKE_CURRENT_SOURCE_DIR@/doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = @CMAKE_CURRENT_BINARY_DIR@/doxy/source
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS = *.cpp *.h *.cu
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is adviced to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the
+# mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH = @CMAKE_CURRENT_BINARY_DIR@/doxy/source \
+ @CMAKE_CURRENT_BINARY_DIR@/doxy/source/python \
+ @CMAKE_CURRENT_BINARY_DIR@/doxy/source/gui \
+ @CMAKE_CURRENT_BINARY_DIR@/doxy/source/util
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = DOXYGEN=1
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will write a font called Helvetica to the output
+# directory and reference it in all dot files that doxygen generates.
+# When you want a differently looking font you can specify the font name
+# using DOT_FONTNAME. You need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/source/blender/python/manta_full/INSTALLING b/source/blender/python/manta_full/INSTALLING
new file mode 100644
index 00000000000..2be30ee98fc
--- /dev/null
+++ b/source/blender/python/manta_full/INSTALLING
@@ -0,0 +1,2 @@
+Detailed instructions on how to compile and run mantaflow can be found at:
+http://mantaflow.ethz.ch/quickstart.html
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/adler32.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/adler32.c
new file mode 100644
index 00000000000..a868f073d8a
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/adler32.c
@@ -0,0 +1,179 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2011 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#define local static
+
+local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
+
+#define BASE 65521 /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware --
+ try it both ways to see which is faster */
+#ifdef NO_DIVIDE
+/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
+ (thank you to John Reiser for pointing this out) */
+# define CHOP(a) \
+ do { \
+ unsigned long tmp = a >> 16; \
+ a &= 0xffffUL; \
+ a += (tmp << 4) - tmp; \
+ } while (0)
+# define MOD28(a) \
+ do { \
+ CHOP(a); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD(a) \
+ do { \
+ CHOP(a); \
+ MOD28(a); \
+ } while (0)
+# define MOD63(a) \
+ do { /* this assumes a is not negative */ \
+ z_off64_t tmp = a >> 32; \
+ a &= 0xffffffffL; \
+ a += (tmp << 8) - (tmp << 5) + tmp; \
+ tmp = a >> 16; \
+ a &= 0xffffL; \
+ a += (tmp << 4) - tmp; \
+ tmp = a >> 16; \
+ a &= 0xffffL; \
+ a += (tmp << 4) - tmp; \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD28(a) a %= BASE
+# define MOD63(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD28(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+local uLong adler32_combine_(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off64_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* for negative len, return invalid adler32 as a clue for debugging */
+ if (len2 < 0)
+ return 0xffffffffUL;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ MOD63(len2); /* assumes len2 >= 0 */
+ rem = (unsigned)len2;
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 >= BASE) sum1 -= BASE;
+ if (sum1 >= BASE) sum1 -= BASE;
+ if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 >= BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ return adler32_combine_(adler1, adler2, len2);
+}
+
+uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off64_t len2;
+{
+ return adler32_combine_(adler1, adler2, len2);
+}
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/compress.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/compress.c
new file mode 100644
index 00000000000..6e9762676a0
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/compress.c
@@ -0,0 +1,80 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+ int level;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (z_const Bytef *)source;
+ stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, level);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+ If the default memLevel or windowBits for deflateInit() is changed, then
+ this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+ uLong sourceLen;
+{
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+ (sourceLen >> 25) + 13;
+}
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/crc32.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/crc32.c
new file mode 100644
index 00000000000..979a7190a3c
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/crc32.c
@@ -0,0 +1,425 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+ Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+ protection on the static variables used to control the first-use generation
+ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+ first call get_crc_table() to initialize the tables before allowing more than
+ one thread to use crc32().
+
+ DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h.
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Definitions for doing the crc four data bytes at a time. */
+#if !defined(NOBYFOUR) && defined(Z_U4)
+# define BYFOUR
+#endif
+#ifdef BYFOUR
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+ unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2));
+
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local z_crc_t FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const z_crc_t FAR *));
+#endif /* MAKECRCH */
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ z_crc_t c;
+ int n, k;
+ z_crc_t poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static volatile int first = 1; /* flag to limit concurrent making */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* See if another task is already doing this (not thread-safe, but better
+ than nothing -- significantly reduces duration of vulnerability in
+ case the advice about DYNAMIC_CRC_TABLE is ignored) */
+ if (first) {
+ first = 0;
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0;
+ for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)
+ poly |= (z_crc_t)1 << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (z_crc_t)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros,
+ and then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = ZSWAP32(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = ZSWAP32(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+ }
+ else { /* not first */
+ /* wait for the other guy to finish (not efficient, but rare) */
+ while (crc_table_empty)
+ ;
+ }
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const z_crc_t FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const z_crc_t FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ",
+ (unsigned long)(table[n]),
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const z_crc_t FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const z_crc_t FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ uInt len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ z_crc_t endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register z_crc_t c;
+ register const z_crc_t FAR *buf4;
+
+ c = (z_crc_t)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register z_crc_t c;
+ register const z_crc_t FAR *buf4;
+
+ c = ZSWAP32((z_crc_t)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(ZSWAP32(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+ unsigned long *mat;
+ unsigned long vec;
+{
+ unsigned long sum;
+
+ sum = 0;
+ while (vec) {
+ if (vec & 1)
+ sum ^= *mat;
+ vec >>= 1;
+ mat++;
+ }
+ return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+ unsigned long *square;
+ unsigned long *mat;
+{
+ int n;
+
+ for (n = 0; n < GF2_DIM; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+local uLong crc32_combine_(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off64_t len2;
+{
+ int n;
+ unsigned long row;
+ unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
+ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
+
+ /* degenerate case (also disallow negative lengths) */
+ if (len2 <= 0)
+ return crc1;
+
+ /* put operator for one zero bit in odd */
+ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */
+ row = 1;
+ for (n = 1; n < GF2_DIM; n++) {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ /* put operator for two zero bits in even */
+ gf2_matrix_square(even, odd);
+
+ /* put operator for four zero bits in odd */
+ gf2_matrix_square(odd, even);
+
+ /* apply len2 zeros to crc1 (first square will put the operator for one
+ zero byte, eight zero bits, in even) */
+ do {
+ /* apply zeros operator for this bit of len2 */
+ gf2_matrix_square(even, odd);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ if (len2 == 0)
+ break;
+
+ /* another iteration of the loop with odd and even swapped */
+ gf2_matrix_square(odd, even);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ } while (len2 != 0);
+
+ /* return combined crc */
+ crc1 ^= crc2;
+ return crc1;
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ return crc32_combine_(crc1, crc2, len2);
+}
+
+uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off64_t len2;
+{
+ return crc32_combine_(crc1, crc2, len2);
+}
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/crc32.h b/source/blender/python/manta_full/dependencies/zlib-1.2.8/crc32.h
new file mode 100644
index 00000000000..9e0c7781025
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const z_crc_t FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/deflate.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/deflate.c
new file mode 100644
index 00000000000..696957705b7
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/deflate.c
@@ -0,0 +1,1967 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in http://tools.ietf.org/html/rfc1951
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow OF((deflate_state *s, int flush));
+#endif
+local block_state deflate_rle OF((deflate_state *s, int flush));
+local block_state deflate_huff OF((deflate_state *s, int flush));
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */
+#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0))
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int wrap = 1;
+ static const char my_version[] = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == (alloc_func)0) {
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+#endif
+ }
+ if (strm->zfree == (free_func)0)
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zfree = zcfree;
+#endif
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+ if (windowBits < 0) { /* suppress zlib wrapper */
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+#ifdef GZIP
+ else if (windowBits > 15) {
+ wrap = 2; /* write gzip wrapper instead */
+ windowBits -= 16;
+ }
+#endif
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->wrap = wrap;
+ s->gzhead = Z_NULL;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->high_water = 0; /* nothing written to s->window yet */
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ s->status = FINISH_STATE;
+ strm->msg = ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt str, n;
+ int wrap;
+ unsigned avail;
+ z_const unsigned char *next;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
+ return Z_STREAM_ERROR;
+ s = strm->state;
+ wrap = s->wrap;
+ if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead)
+ return Z_STREAM_ERROR;
+
+ /* when using zlib wrappers, compute Adler-32 for provided dictionary */
+ if (wrap == 1)
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+ s->wrap = 0; /* avoid computing Adler-32 in read_buf */
+
+ /* if dictionary would fill window, just replace the history */
+ if (dictLength >= s->w_size) {
+ if (wrap == 0) { /* already empty otherwise */
+ CLEAR_HASH(s);
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->insert = 0;
+ }
+ dictionary += dictLength - s->w_size; /* use the tail */
+ dictLength = s->w_size;
+ }
+
+ /* insert dictionary into window and hash */
+ avail = strm->avail_in;
+ next = strm->next_in;
+ strm->avail_in = dictLength;
+ strm->next_in = (z_const Bytef *)dictionary;
+ fill_window(s);
+ while (s->lookahead >= MIN_MATCH) {
+ str = s->strstart;
+ n = s->lookahead - (MIN_MATCH-1);
+ do {
+ UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
+#ifndef FASTEST
+ s->prev[str & s->w_mask] = s->head[s->ins_h];
+#endif
+ s->head[s->ins_h] = (Pos)str;
+ str++;
+ } while (--n);
+ s->strstart = str;
+ s->lookahead = MIN_MATCH-1;
+ fill_window(s);
+ }
+ s->strstart += s->lookahead;
+ s->block_start = (long)s->strstart;
+ s->insert = s->lookahead;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ strm->next_in = next;
+ strm->avail_in = avail;
+ s->wrap = wrap;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateResetKeep (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+ }
+ s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ strm->adler =
+#ifdef GZIP
+ s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+ adler32(0L, Z_NULL, 0);
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ int ret;
+
+ ret = deflateResetKeep(strm);
+ if (ret == Z_OK)
+ lm_init(strm->state);
+ return ret;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+ z_streamp strm;
+ gz_headerp head;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+ strm->state->gzhead = head;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePending (strm, pending, bits)
+ unsigned *pending;
+ int *bits;
+ z_streamp strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (pending != Z_NULL)
+ *pending = strm->state->pending;
+ if (bits != Z_NULL)
+ *bits = strm->state->bi_valid;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+ z_streamp strm;
+ int bits;
+ int value;
+{
+ deflate_state *s;
+ int put;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))
+ return Z_BUF_ERROR;
+ do {
+ put = Buf_size - s->bi_valid;
+ if (put > bits)
+ put = bits;
+ s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);
+ s->bi_valid += put;
+ _tr_flush_bits(s);
+ value >>= put;
+ bits -= put;
+ } while (bits);
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if ((strategy != s->strategy || func != configuration_table[level].func) &&
+ strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_BLOCK);
+ if (err == Z_BUF_ERROR && s->pending == 0)
+ err = Z_OK;
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+ z_streamp strm;
+ int good_length;
+ int max_lazy;
+ int nice_length;
+ int max_chain;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ s->good_match = good_length;
+ s->max_lazy_match = max_lazy;
+ s->nice_match = nice_length;
+ s->max_chain_length = max_chain;
+ return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well. The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds for
+ * every combination of windowBits and memLevel. But even the conservative
+ * upper bound of about 14% expansion does not seem onerous for output buffer
+ * allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+ z_streamp strm;
+ uLong sourceLen;
+{
+ deflate_state *s;
+ uLong complen, wraplen;
+ Bytef *str;
+
+ /* conservative upper bound for compressed data */
+ complen = sourceLen +
+ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;
+
+ /* if can't get parameters, return conservative bound plus zlib wrapper */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return complen + 6;
+
+ /* compute wrapper length */
+ s = strm->state;
+ switch (s->wrap) {
+ case 0: /* raw deflate */
+ wraplen = 0;
+ break;
+ case 1: /* zlib wrapper */
+ wraplen = 6 + (s->strstart ? 4 : 0);
+ break;
+ case 2: /* gzip wrapper */
+ wraplen = 18;
+ if (s->gzhead != Z_NULL) { /* user-supplied gzip header */
+ if (s->gzhead->extra != Z_NULL)
+ wraplen += 2 + s->gzhead->extra_len;
+ str = s->gzhead->name;
+ if (str != Z_NULL)
+ do {
+ wraplen++;
+ } while (*str++);
+ str = s->gzhead->comment;
+ if (str != Z_NULL)
+ do {
+ wraplen++;
+ } while (*str++);
+ if (s->gzhead->hcrc)
+ wraplen += 2;
+ }
+ break;
+ default: /* for compiler happiness */
+ wraplen = 6;
+ }
+
+ /* if not default parameters, return conservative bound */
+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+ return complen + wraplen;
+
+ /* default settings: return tight bound for that case */
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+ (sourceLen >> 25) + 13 - 6 + wraplen;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len;
+ deflate_state *s = strm->state;
+
+ _tr_flush_bits(s);
+ len = s->pending;
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, s->pending_out, len);
+ strm->next_out += len;
+ s->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ s->pending -= len;
+ if (s->pending == 0) {
+ s->pending_out = s->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_BLOCK || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the header */
+ if (s->status == INIT_STATE) {
+#ifdef GZIP
+ if (s->wrap == 2) {
+ strm->adler = crc32(0L, Z_NULL, 0);
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ if (s->gzhead == Z_NULL) {
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, OS_CODE);
+ s->status = BUSY_STATE;
+ }
+ else {
+ put_byte(s, (s->gzhead->text ? 1 : 0) +
+ (s->gzhead->hcrc ? 2 : 0) +
+ (s->gzhead->extra == Z_NULL ? 0 : 4) +
+ (s->gzhead->name == Z_NULL ? 0 : 8) +
+ (s->gzhead->comment == Z_NULL ? 0 : 16)
+ );
+ put_byte(s, (Byte)(s->gzhead->time & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, s->gzhead->os & 0xff);
+ if (s->gzhead->extra != Z_NULL) {
+ put_byte(s, s->gzhead->extra_len & 0xff);
+ put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+ }
+ if (s->gzhead->hcrc)
+ strm->adler = crc32(strm->adler, s->pending_buf,
+ s->pending);
+ s->gzindex = 0;
+ s->status = EXTRA_STATE;
+ }
+ }
+ else
+#endif
+ {
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
+ else
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ }
+ }
+#ifdef GZIP
+ if (s->status == EXTRA_STATE) {
+ if (s->gzhead->extra != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+
+ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size)
+ break;
+ }
+ put_byte(s, s->gzhead->extra[s->gzindex]);
+ s->gzindex++;
+ }
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (s->gzindex == s->gzhead->extra_len) {
+ s->gzindex = 0;
+ s->status = NAME_STATE;
+ }
+ }
+ else
+ s->status = NAME_STATE;
+ }
+ if (s->status == NAME_STATE) {
+ if (s->gzhead->name != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->name[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0) {
+ s->gzindex = 0;
+ s->status = COMMENT_STATE;
+ }
+ }
+ else
+ s->status = COMMENT_STATE;
+ }
+ if (s->status == COMMENT_STATE) {
+ if (s->gzhead->comment != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->comment[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0)
+ s->status = HCRC_STATE;
+ }
+ else
+ s->status = HCRC_STATE;
+ }
+ if (s->status == HCRC_STATE) {
+ if (s->gzhead->hcrc) {
+ if (s->pending + 2 > s->pending_buf_size)
+ flush_pending(strm);
+ if (s->pending + 2 <= s->pending_buf_size) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ strm->adler = crc32(0L, Z_NULL, 0);
+ s->status = BUSY_STATE;
+ }
+ }
+ else
+ s->status = BUSY_STATE;
+ }
+#endif
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
+ (s->strategy == Z_RLE ? deflate_rle(s, flush) :
+ (*(configuration_table[s->level].func))(s, flush));
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ if (s->lookahead == 0) {
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->insert = 0;
+ }
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->wrap <= 0) return Z_STREAM_END;
+
+ /* Write the trailer */
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+ put_byte(s, (Byte)(strm->total_in & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+ }
+ else
+#endif
+ {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE &&
+ status != EXTRA_STATE &&
+ status != NAME_STATE &&
+ status != COMMENT_STATE &&
+ status != HCRC_STATE &&
+ status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ zmemcpy(buf, strm->next_in, len);
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, buf, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, buf, len);
+ }
+#endif
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->insert = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2. Note that the checks below
+ * for insufficient lookahead only occur occasionally for performance
+ * reasons. Therefore uninitialized memory will be accessed, and
+ * conditional jumps will be made that depend on those values.
+ * However the length of the match is limited to the lookahead, so
+ * the output of deflate is not affected by the uninitialized values.
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+
+#else /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for FASTEST only
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#endif /* FASTEST */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) break;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead + s->insert >= MIN_MATCH) {
+ uInt str = s->strstart - s->insert;
+ s->ins_h = s->window[str];
+ UPDATE_HASH(s, s->ins_h, s->window[str + 1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ while (s->insert) {
+ UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
+#ifndef FASTEST
+ s->prev[str & s->w_mask] = s->head[s->ins_h];
+#endif
+ s->head[s->ins_h] = (Pos)str;
+ str++;
+ s->insert--;
+ if (s->lookahead + s->insert < MIN_MATCH)
+ break;
+ }
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+
+ /* If the WIN_INIT bytes after the end of the current data have never been
+ * written, then zero those bytes in order to avoid memory check reports of
+ * the use of uninitialized (or uninitialised as Julian writes) bytes by
+ * the longest match routines. Update the high water mark for the next
+ * time through here. WIN_INIT is set to MAX_MATCH since the longest match
+ * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
+ */
+ if (s->high_water < s->window_size) {
+ ulg curr = s->strstart + (ulg)(s->lookahead);
+ ulg init;
+
+ if (s->high_water < curr) {
+ /* Previous high water mark below current data -- zero WIN_INIT
+ * bytes or up to end of window, whichever is less.
+ */
+ init = s->window_size - curr;
+ if (init > WIN_INIT)
+ init = WIN_INIT;
+ zmemzero(s->window + curr, (unsigned)init);
+ s->high_water = curr + init;
+ }
+ else if (s->high_water < (ulg)curr + WIN_INIT) {
+ /* High water mark at or above current data, but below current data
+ * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
+ * to end of window, whichever is less.
+ */
+ init = (ulg)curr + WIN_INIT - s->high_water;
+ if (init > s->window_size - s->high_water)
+ init = s->window_size - s->high_water;
+ zmemzero(s->window + s->high_water, (unsigned)init);
+ s->high_water += init;
+ }
+ }
+
+ Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
+ "not enough room for search");
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, last) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (last)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, last) { \
+ FLUSH_BLOCK_ONLY(s, last); \
+ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ s->insert = 0;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if ((long)s->strstart > s->block_start)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ hash_head = NIL;
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ s->match_length = longest_match (s, hash_head);
+ /* longest_match() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if (s->last_lit)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ hash_head = NIL;
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ s->match_length = longest_match (s, hash_head);
+ /* longest_match() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+ || (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR)
+#endif
+ )) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if (s->last_lit)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
+#endif /* FASTEST */
+
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one. Do not maintain a hash table. (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+ uInt prev; /* byte at distance one to match */
+ Bytef *scan, *strend; /* scan goes up to strend for length of run */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the longest run, plus one for the unrolled loop.
+ */
+ if (s->lookahead <= MAX_MATCH) {
+ fill_window(s);
+ if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* See how many times the previous byte repeats */
+ s->match_length = 0;
+ if (s->lookahead >= MIN_MATCH && s->strstart > 0) {
+ scan = s->window + s->strstart - 1;
+ prev = *scan;
+ if (prev == *++scan && prev == *++scan && prev == *++scan) {
+ strend = s->window + s->strstart + MAX_MATCH;
+ do {
+ } while (prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ scan < strend);
+ s->match_length = MAX_MATCH - (int)(strend - scan);
+ if (s->match_length > s->lookahead)
+ s->match_length = s->lookahead;
+ }
+ Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
+ }
+
+ /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->strstart - 1, s->match_length);
+
+ _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ s->insert = 0;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if (s->last_lit)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
+
+/* ===========================================================================
+ * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
+ * (It will be regenerated if this run of deflate switches away from Huffman.)
+ */
+local block_state deflate_huff(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we have a literal to write. */
+ if (s->lookahead == 0) {
+ fill_window(s);
+ if (s->lookahead == 0) {
+ if (flush == Z_NO_FLUSH)
+ return need_more;
+ break; /* flush the current block */
+ }
+ }
+
+ /* Output a literal byte */
+ s->match_length = 0;
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ s->insert = 0;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if (s->last_lit)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/deflate.h b/source/blender/python/manta_full/dependencies/zlib-1.2.8/deflate.h
new file mode 100644
index 00000000000..ce0299edd19
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/deflate.h
@@ -0,0 +1,346 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2012 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer creation by deflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip encoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define Buf_size 16
+/* size of bit buffer in bi_buf */
+
+#define INIT_STATE 42
+#define EXTRA_STATE 69
+#define NAME_STATE 73
+#define COMMENT_STATE 91
+#define HCRC_STATE 103
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ uInt pending; /* nb of bytes in the pending buffer */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ gz_headerp gzhead; /* gzip header information to write */
+ uInt gzindex; /* where in extra, name, or comment */
+ Byte method; /* can only be DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to suppress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ uInt insert; /* bytes at end of window left to insert */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+ ulg high_water;
+ /* High water mark offset in window for initialized bytes -- bytes above
+ * this are set to zero in order to avoid memory check warnings when
+ * longest match routines access bytes past the input. This is then
+ * updated to the new high water mark.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+#define WIN_INIT MAX_MATCH
+/* Number of bytes after end of data in window to initialize in order to avoid
+ memory checker errors from longest match routines */
+
+ /* in trees.c */
+void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
+int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
+ ulg stored_len, int last));
+void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
+ ulg stored_len, int last));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch ZLIB_INTERNAL _length_code[];
+ extern uch ZLIB_INTERNAL _dist_code[];
+#else
+ extern const uch ZLIB_INTERNAL _length_code[];
+ extern const uch ZLIB_INTERNAL _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzclose.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzclose.c
new file mode 100644
index 00000000000..caeb99a3177
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzclose.c
@@ -0,0 +1,25 @@
+/* gzclose.c -- zlib gzclose() function
+ * Copyright (C) 2004, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* gzclose() is in a separate file so that it is linked in only if it is used.
+ That way the other gzclose functions can be used instead to avoid linking in
+ unneeded compression or decompression routines. */
+int ZEXPORT gzclose(file)
+ gzFile file;
+{
+#ifndef NO_GZCOMPRESS
+ gz_statep state;
+
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+
+ return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file);
+#else
+ return gzclose_r(file);
+#endif
+}
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzguts.h b/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzguts.h
new file mode 100644
index 00000000000..d87659d0319
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzguts.h
@@ -0,0 +1,209 @@
+/* gzguts.h -- zlib internal header definitions for gz* operations
+ * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#ifdef _LARGEFILE64_SOURCE
+# ifndef _LARGEFILE_SOURCE
+# define _LARGEFILE_SOURCE 1
+# endif
+# ifdef _FILE_OFFSET_BITS
+# undef _FILE_OFFSET_BITS
+# endif
+#endif
+
+#ifdef HAVE_HIDDEN
+# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+#else
+# define ZLIB_INTERNAL
+#endif
+
+#include <stdio.h>
+#include "zlib.h"
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+# include <limits.h>
+#endif
+#include <fcntl.h>
+
+#ifdef _WIN32
+# include <stddef.h>
+#endif
+
+#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)
+# include <io.h>
+#endif
+
+#ifdef WINAPI_FAMILY
+# define open _open
+# define read _read
+# define write _write
+# define close _close
+#endif
+
+#ifdef NO_DEFLATE /* for compatibility with old definition */
+# define NO_GZCOMPRESS
+#endif
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+
+#if defined(__CYGWIN__)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+
+#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+
+#ifndef HAVE_VSNPRINTF
+# ifdef MSDOS
+/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+ but for now we just assume it doesn't. */
+# define NO_vsnprintf
+# endif
+# ifdef __TURBOC__
+# define NO_vsnprintf
+# endif
+# ifdef WIN32
+/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+# if !defined(vsnprintf) && !defined(NO_vsnprintf)
+# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
+# define vsnprintf _vsnprintf
+# endif
+# endif
+# endif
+# ifdef __SASC
+# define NO_vsnprintf
+# endif
+# ifdef VMS
+# define NO_vsnprintf
+# endif
+# ifdef __OS400__
+# define NO_vsnprintf
+# endif
+# ifdef __MVS__
+# define NO_vsnprintf
+# endif
+#endif
+
+/* unlike snprintf (which is required in C99, yet still not supported by
+ Microsoft more than a decade later!), _snprintf does not guarantee null
+ termination of the result -- however this is only used in gzlib.c where
+ the result is assured to fit in the space provided */
+#ifdef _MSC_VER
+# define snprintf _snprintf
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+/* gz* functions always use library allocation functions */
+#ifndef STDC
+ extern voidp malloc OF((uInt size));
+ extern void free OF((voidpf ptr));
+#endif
+
+/* get errno and strerror definition */
+#if defined UNDER_CE
+# include <windows.h>
+# define zstrerror() gz_strwinerror((DWORD)GetLastError())
+#else
+# ifndef NO_STRERROR
+# include <errno.h>
+# define zstrerror() strerror(errno)
+# else
+# define zstrerror() "stdio error (consult errno)"
+# endif
+#endif
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+ ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+#endif
+
+/* default memLevel */
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+
+/* default i/o buffer size -- double this for output when reading (this and
+ twice this must be able to fit in an unsigned type) */
+#define GZBUFSIZE 8192
+
+/* gzip modes, also provide a little integrity check on the passed structure */
+#define GZ_NONE 0
+#define GZ_READ 7247
+#define GZ_WRITE 31153
+#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */
+
+/* values for gz_state how */
+#define LOOK 0 /* look for a gzip header */
+#define COPY 1 /* copy input directly */
+#define GZIP 2 /* decompress a gzip stream */
+
+/* internal gzip file state data structure */
+typedef struct {
+ /* exposed contents for gzgetc() macro */
+ struct gzFile_s x; /* "x" for exposed */
+ /* x.have: number of bytes available at x.next */
+ /* x.next: next output data to deliver or write */
+ /* x.pos: current position in uncompressed data */
+ /* used for both reading and writing */
+ int mode; /* see gzip modes above */
+ int fd; /* file descriptor */
+ char *path; /* path or fd for error messages */
+ unsigned size; /* buffer size, zero if not allocated yet */
+ unsigned want; /* requested buffer size, default is GZBUFSIZE */
+ unsigned char *in; /* input buffer */
+ unsigned char *out; /* output buffer (double-sized when reading) */
+ int direct; /* 0 if processing gzip, 1 if transparent */
+ /* just for reading */
+ int how; /* 0: get header, 1: copy, 2: decompress */
+ z_off64_t start; /* where the gzip data started, for rewinding */
+ int eof; /* true if end of input file reached */
+ int past; /* true if read requested past end */
+ /* just for writing */
+ int level; /* compression level */
+ int strategy; /* compression strategy */
+ /* seek request */
+ z_off64_t skip; /* amount to skip (already rewound if backwards) */
+ int seek; /* true if seek request pending */
+ /* error information */
+ int err; /* error code */
+ char *msg; /* error message */
+ /* zlib inflate or deflate stream */
+ z_stream strm; /* stream structure in-place (not a pointer) */
+} gz_state;
+typedef gz_state FAR *gz_statep;
+
+/* shared functions */
+void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));
+#if defined UNDER_CE
+char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));
+#endif
+
+/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
+ value -- needed when comparing unsigned to z_off64_t, which is signed
+ (possible z_off64_t types off_t, off64_t, and long are all signed) */
+#ifdef INT_MAX
+# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
+#else
+unsigned ZLIB_INTERNAL gz_intmax OF((void));
+# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
+#endif
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzlib.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzlib.c
new file mode 100644
index 00000000000..fae202ef890
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzlib.c
@@ -0,0 +1,634 @@
+/* gzlib.c -- zlib functions common to reading and writing gzip files
+ * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+#if defined(_WIN32) && !defined(__BORLANDC__)
+# define LSEEK _lseeki64
+#else
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+# define LSEEK lseek64
+#else
+# define LSEEK lseek
+#endif
+#endif
+
+/* Local functions */
+local void gz_reset OF((gz_statep));
+local gzFile gz_open OF((const void *, int, const char *));
+
+#if defined UNDER_CE
+
+/* Map the Windows error number in ERROR to a locale-dependent error message
+ string and return a pointer to it. Typically, the values for ERROR come
+ from GetLastError.
+
+ The string pointed to shall not be modified by the application, but may be
+ overwritten by a subsequent call to gz_strwinerror
+
+ The gz_strwinerror function does not change the current setting of
+ GetLastError. */
+char ZLIB_INTERNAL *gz_strwinerror (error)
+ DWORD error;
+{
+ static char buf[1024];
+
+ wchar_t *msgbuf;
+ DWORD lasterr = GetLastError();
+ DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL,
+ error,
+ 0, /* Default language */
+ (LPVOID)&msgbuf,
+ 0,
+ NULL);
+ if (chars != 0) {
+ /* If there is an \r\n appended, zap it. */
+ if (chars >= 2
+ && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
+ chars -= 2;
+ msgbuf[chars] = 0;
+ }
+
+ if (chars > sizeof (buf) - 1) {
+ chars = sizeof (buf) - 1;
+ msgbuf[chars] = 0;
+ }
+
+ wcstombs(buf, msgbuf, chars + 1);
+ LocalFree(msgbuf);
+ }
+ else {
+ sprintf(buf, "unknown win32 error (%ld)", error);
+ }
+
+ SetLastError(lasterr);
+ return buf;
+}
+
+#endif /* UNDER_CE */
+
+/* Reset gzip file state */
+local void gz_reset(state)
+ gz_statep state;
+{
+ state->x.have = 0; /* no output data available */
+ if (state->mode == GZ_READ) { /* for reading ... */
+ state->eof = 0; /* not at end of file */
+ state->past = 0; /* have not read past end yet */
+ state->how = LOOK; /* look for gzip header */
+ }
+ state->seek = 0; /* no seek request pending */
+ gz_error(state, Z_OK, NULL); /* clear error */
+ state->x.pos = 0; /* no uncompressed data yet */
+ state->strm.avail_in = 0; /* no input data yet */
+}
+
+/* Open a gzip file either by name or file descriptor. */
+local gzFile gz_open(path, fd, mode)
+ const void *path;
+ int fd;
+ const char *mode;
+{
+ gz_statep state;
+ size_t len;
+ int oflag;
+#ifdef O_CLOEXEC
+ int cloexec = 0;
+#endif
+#ifdef O_EXCL
+ int exclusive = 0;
+#endif
+
+ /* check input */
+ if (path == NULL)
+ return NULL;
+
+ /* allocate gzFile structure to return */
+ state = (gz_statep)malloc(sizeof(gz_state));
+ if (state == NULL)
+ return NULL;
+ state->size = 0; /* no buffers allocated yet */
+ state->want = GZBUFSIZE; /* requested buffer size */
+ state->msg = NULL; /* no error message yet */
+
+ /* interpret mode */
+ state->mode = GZ_NONE;
+ state->level = Z_DEFAULT_COMPRESSION;
+ state->strategy = Z_DEFAULT_STRATEGY;
+ state->direct = 0;
+ while (*mode) {
+ if (*mode >= '0' && *mode <= '9')
+ state->level = *mode - '0';
+ else
+ switch (*mode) {
+ case 'r':
+ state->mode = GZ_READ;
+ break;
+#ifndef NO_GZCOMPRESS
+ case 'w':
+ state->mode = GZ_WRITE;
+ break;
+ case 'a':
+ state->mode = GZ_APPEND;
+ break;
+#endif
+ case '+': /* can't read and write at the same time */
+ free(state);
+ return NULL;
+ case 'b': /* ignore -- will request binary anyway */
+ break;
+#ifdef O_CLOEXEC
+ case 'e':
+ cloexec = 1;
+ break;
+#endif
+#ifdef O_EXCL
+ case 'x':
+ exclusive = 1;
+ break;
+#endif
+ case 'f':
+ state->strategy = Z_FILTERED;
+ break;
+ case 'h':
+ state->strategy = Z_HUFFMAN_ONLY;
+ break;
+ case 'R':
+ state->strategy = Z_RLE;
+ break;
+ case 'F':
+ state->strategy = Z_FIXED;
+ break;
+ case 'T':
+ state->direct = 1;
+ break;
+ default: /* could consider as an error, but just ignore */
+ ;
+ }
+ mode++;
+ }
+
+ /* must provide an "r", "w", or "a" */
+ if (state->mode == GZ_NONE) {
+ free(state);
+ return NULL;
+ }
+
+ /* can't force transparent read */
+ if (state->mode == GZ_READ) {
+ if (state->direct) {
+ free(state);
+ return NULL;
+ }
+ state->direct = 1; /* for empty file */
+ }
+
+ /* save the path name for error messages */
+#ifdef _WIN32
+ if (fd == -2) {
+ len = wcstombs(NULL, path, 0);
+ if (len == (size_t)-1)
+ len = 0;
+ }
+ else
+#endif
+ len = strlen((const char *)path);
+ state->path = (char *)malloc(len + 1);
+ if (state->path == NULL) {
+ free(state);
+ return NULL;
+ }
+#ifdef _WIN32
+ if (fd == -2)
+ if (len)
+ wcstombs(state->path, path, len + 1);
+ else
+ *(state->path) = 0;
+ else
+#endif
+#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
+ snprintf(state->path, len + 1, "%s", (const char *)path);
+#else
+ strcpy(state->path, path);
+#endif
+
+ /* compute the flags for open() */
+ oflag =
+#ifdef O_LARGEFILE
+ O_LARGEFILE |
+#endif
+#ifdef O_BINARY
+ O_BINARY |
+#endif
+#ifdef O_CLOEXEC
+ (cloexec ? O_CLOEXEC : 0) |
+#endif
+ (state->mode == GZ_READ ?
+ O_RDONLY :
+ (O_WRONLY | O_CREAT |
+#ifdef O_EXCL
+ (exclusive ? O_EXCL : 0) |
+#endif
+ (state->mode == GZ_WRITE ?
+ O_TRUNC :
+ O_APPEND)));
+
+ /* open the file with the appropriate flags (or just use fd) */
+ state->fd = fd > -1 ? fd : (
+#ifdef _WIN32
+ fd == -2 ? _wopen(path, oflag, 0666) :
+#endif
+ open((const char *)path, oflag, 0666));
+ if (state->fd == -1) {
+ free(state->path);
+ free(state);
+ return NULL;
+ }
+ if (state->mode == GZ_APPEND)
+ state->mode = GZ_WRITE; /* simplify later checks */
+
+ /* save the current position for rewinding (only if reading) */
+ if (state->mode == GZ_READ) {
+ state->start = LSEEK(state->fd, 0, SEEK_CUR);
+ if (state->start == -1) state->start = 0;
+ }
+
+ /* initialize stream */
+ gz_reset(state);
+
+ /* return stream */
+ return (gzFile)state;
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzopen(path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open(path, -1, mode);
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzopen64(path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open(path, -1, mode);
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzdopen(fd, mode)
+ int fd;
+ const char *mode;
+{
+ char *path; /* identifier for error messages */
+ gzFile gz;
+
+ if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
+ return NULL;
+#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
+ snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); /* for debugging */
+#else
+ sprintf(path, "<fd:%d>", fd); /* for debugging */
+#endif
+ gz = gz_open(path, fd, mode);
+ free(path);
+ return gz;
+}
+
+/* -- see zlib.h -- */
+#ifdef _WIN32
+gzFile ZEXPORT gzopen_w(path, mode)
+ const wchar_t *path;
+ const char *mode;
+{
+ return gz_open(path, -2, mode);
+}
+#endif
+
+/* -- see zlib.h -- */
+int ZEXPORT gzbuffer(file, size)
+ gzFile file;
+ unsigned size;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* make sure we haven't already allocated memory */
+ if (state->size != 0)
+ return -1;
+
+ /* check and set requested size */
+ if (size < 2)
+ size = 2; /* need two bytes to check magic header */
+ state->want = size;
+ return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzrewind(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ /* check that we're reading and that there's no error */
+ if (state->mode != GZ_READ ||
+ (state->err != Z_OK && state->err != Z_BUF_ERROR))
+ return -1;
+
+ /* back up and start over */
+ if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
+ return -1;
+ gz_reset(state);
+ return 0;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gzseek64(file, offset, whence)
+ gzFile file;
+ z_off64_t offset;
+ int whence;
+{
+ unsigned n;
+ z_off64_t ret;
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* check that there's no error */
+ if (state->err != Z_OK && state->err != Z_BUF_ERROR)
+ return -1;
+
+ /* can only seek from start or relative to current position */
+ if (whence != SEEK_SET && whence != SEEK_CUR)
+ return -1;
+
+ /* normalize offset to a SEEK_CUR specification */
+ if (whence == SEEK_SET)
+ offset -= state->x.pos;
+ else if (state->seek)
+ offset += state->skip;
+ state->seek = 0;
+
+ /* if within raw area while reading, just go there */
+ if (state->mode == GZ_READ && state->how == COPY &&
+ state->x.pos + offset >= 0) {
+ ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
+ if (ret == -1)
+ return -1;
+ state->x.have = 0;
+ state->eof = 0;
+ state->past = 0;
+ state->seek = 0;
+ gz_error(state, Z_OK, NULL);
+ state->strm.avail_in = 0;
+ state->x.pos += offset;
+ return state->x.pos;
+ }
+
+ /* calculate skip amount, rewinding if needed for back seek when reading */
+ if (offset < 0) {
+ if (state->mode != GZ_READ) /* writing -- can't go backwards */
+ return -1;
+ offset += state->x.pos;
+ if (offset < 0) /* before start of file! */
+ return -1;
+ if (gzrewind(file) == -1) /* rewind, then skip to offset */
+ return -1;
+ }
+
+ /* if reading, skip what's in output buffer (one less gzgetc() check) */
+ if (state->mode == GZ_READ) {
+ n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
+ (unsigned)offset : state->x.have;
+ state->x.have -= n;
+ state->x.next += n;
+ state->x.pos += n;
+ offset -= n;
+ }
+
+ /* request skip (if not zero) */
+ if (offset) {
+ state->seek = 1;
+ state->skip = offset;
+ }
+ return state->x.pos + offset;
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gzseek(file, offset, whence)
+ gzFile file;
+ z_off_t offset;
+ int whence;
+{
+ z_off64_t ret;
+
+ ret = gzseek64(file, (z_off64_t)offset, whence);
+ return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gztell64(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* return position */
+ return state->x.pos + (state->seek ? state->skip : 0);
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gztell(file)
+ gzFile file;
+{
+ z_off64_t ret;
+
+ ret = gztell64(file);
+ return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gzoffset64(file)
+ gzFile file;
+{
+ z_off64_t offset;
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* compute and return effective offset in file */
+ offset = LSEEK(state->fd, 0, SEEK_CUR);
+ if (offset == -1)
+ return -1;
+ if (state->mode == GZ_READ) /* reading */
+ offset -= state->strm.avail_in; /* don't count buffered input */
+ return offset;
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gzoffset(file)
+ gzFile file;
+{
+ z_off64_t ret;
+
+ ret = gzoffset64(file);
+ return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzeof(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return 0;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return 0;
+
+ /* return end-of-file state */
+ return state->mode == GZ_READ ? state->past : 0;
+}
+
+/* -- see zlib.h -- */
+const char * ZEXPORT gzerror(file, errnum)
+ gzFile file;
+ int *errnum;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return NULL;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return NULL;
+
+ /* return error information */
+ if (errnum != NULL)
+ *errnum = state->err;
+ return state->err == Z_MEM_ERROR ? "out of memory" :
+ (state->msg == NULL ? "" : state->msg);
+}
+
+/* -- see zlib.h -- */
+void ZEXPORT gzclearerr(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return;
+
+ /* clear error and end-of-file */
+ if (state->mode == GZ_READ) {
+ state->eof = 0;
+ state->past = 0;
+ }
+ gz_error(state, Z_OK, NULL);
+}
+
+/* Create an error message in allocated memory and set state->err and
+ state->msg accordingly. Free any previous error message already there. Do
+ not try to free or allocate space if the error is Z_MEM_ERROR (out of
+ memory). Simply save the error message as a static string. If there is an
+ allocation failure constructing the error message, then convert the error to
+ out of memory. */
+void ZLIB_INTERNAL gz_error(state, err, msg)
+ gz_statep state;
+ int err;
+ const char *msg;
+{
+ /* free previously allocated message and clear */
+ if (state->msg != NULL) {
+ if (state->err != Z_MEM_ERROR)
+ free(state->msg);
+ state->msg = NULL;
+ }
+
+ /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
+ if (err != Z_OK && err != Z_BUF_ERROR)
+ state->x.have = 0;
+
+ /* set error code, and if no message, then done */
+ state->err = err;
+ if (msg == NULL)
+ return;
+
+ /* for an out of memory error, return literal string when requested */
+ if (err == Z_MEM_ERROR)
+ return;
+
+ /* construct error message with path */
+ if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
+ NULL) {
+ state->err = Z_MEM_ERROR;
+ return;
+ }
+#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
+ snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
+ "%s%s%s", state->path, ": ", msg);
+#else
+ strcpy(state->msg, state->path);
+ strcat(state->msg, ": ");
+ strcat(state->msg, msg);
+#endif
+ return;
+}
+
+#ifndef INT_MAX
+/* portably return maximum value for an int (when limits.h presumed not
+ available) -- we need to do this to cover cases where 2's complement not
+ used, since C standard permits 1's complement and sign-bit representations,
+ otherwise we could just use ((unsigned)-1) >> 1 */
+unsigned ZLIB_INTERNAL gz_intmax()
+{
+ unsigned p, q;
+
+ p = 1;
+ do {
+ q = p;
+ p <<= 1;
+ p++;
+ } while (p > q);
+ return q >> 1;
+}
+#endif
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzread.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzread.c
new file mode 100644
index 00000000000..bf4538eb274
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzread.c
@@ -0,0 +1,594 @@
+/* gzread.c -- zlib functions for reading gzip files
+ * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* Local functions */
+local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
+local int gz_avail OF((gz_statep));
+local int gz_look OF((gz_statep));
+local int gz_decomp OF((gz_statep));
+local int gz_fetch OF((gz_statep));
+local int gz_skip OF((gz_statep, z_off64_t));
+
+/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
+ state->fd, and update state->eof, state->err, and state->msg as appropriate.
+ This function needs to loop on read(), since read() is not guaranteed to
+ read the number of bytes requested, depending on the type of descriptor. */
+local int gz_load(state, buf, len, have)
+ gz_statep state;
+ unsigned char *buf;
+ unsigned len;
+ unsigned *have;
+{
+ int ret;
+
+ *have = 0;
+ do {
+ ret = read(state->fd, buf + *have, len - *have);
+ if (ret <= 0)
+ break;
+ *have += ret;
+ } while (*have < len);
+ if (ret < 0) {
+ gz_error(state, Z_ERRNO, zstrerror());
+ return -1;
+ }
+ if (ret == 0)
+ state->eof = 1;
+ return 0;
+}
+
+/* Load up input buffer and set eof flag if last data loaded -- return -1 on
+ error, 0 otherwise. Note that the eof flag is set when the end of the input
+ file is reached, even though there may be unused data in the buffer. Once
+ that data has been used, no more attempts will be made to read the file.
+ If strm->avail_in != 0, then the current data is moved to the beginning of
+ the input buffer, and then the remainder of the buffer is loaded with the
+ available data from the input file. */
+local int gz_avail(state)
+ gz_statep state;
+{
+ unsigned got;
+ z_streamp strm = &(state->strm);
+
+ if (state->err != Z_OK && state->err != Z_BUF_ERROR)
+ return -1;
+ if (state->eof == 0) {
+ if (strm->avail_in) { /* copy what's there to the start */
+ unsigned char *p = state->in;
+ unsigned const char *q = strm->next_in;
+ unsigned n = strm->avail_in;
+ do {
+ *p++ = *q++;
+ } while (--n);
+ }
+ if (gz_load(state, state->in + strm->avail_in,
+ state->size - strm->avail_in, &got) == -1)
+ return -1;
+ strm->avail_in += got;
+ strm->next_in = state->in;
+ }
+ return 0;
+}
+
+/* Look for gzip header, set up for inflate or copy. state->x.have must be 0.
+ If this is the first time in, allocate required memory. state->how will be
+ left unchanged if there is no more input data available, will be set to COPY
+ if there is no gzip header and direct copying will be performed, or it will
+ be set to GZIP for decompression. If direct copying, then leftover input
+ data from the input buffer will be copied to the output buffer. In that
+ case, all further file reads will be directly to either the output buffer or
+ a user buffer. If decompressing, the inflate state will be initialized.
+ gz_look() will return 0 on success or -1 on failure. */
+local int gz_look(state)
+ gz_statep state;
+{
+ z_streamp strm = &(state->strm);
+
+ /* allocate read buffers and inflate memory */
+ if (state->size == 0) {
+ /* allocate buffers */
+ state->in = (unsigned char *)malloc(state->want);
+ state->out = (unsigned char *)malloc(state->want << 1);
+ if (state->in == NULL || state->out == NULL) {
+ if (state->out != NULL)
+ free(state->out);
+ if (state->in != NULL)
+ free(state->in);
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+ state->size = state->want;
+
+ /* allocate inflate memory */
+ state->strm.zalloc = Z_NULL;
+ state->strm.zfree = Z_NULL;
+ state->strm.opaque = Z_NULL;
+ state->strm.avail_in = 0;
+ state->strm.next_in = Z_NULL;
+ if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */
+ free(state->out);
+ free(state->in);
+ state->size = 0;
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+ }
+
+ /* get at least the magic bytes in the input buffer */
+ if (strm->avail_in < 2) {
+ if (gz_avail(state) == -1)
+ return -1;
+ if (strm->avail_in == 0)
+ return 0;
+ }
+
+ /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
+ a logical dilemma here when considering the case of a partially written
+ gzip file, to wit, if a single 31 byte is written, then we cannot tell
+ whether this is a single-byte file, or just a partially written gzip
+ file -- for here we assume that if a gzip file is being written, then
+ the header will be written in a single operation, so that reading a
+ single byte is sufficient indication that it is not a gzip file) */
+ if (strm->avail_in > 1 &&
+ strm->next_in[0] == 31 && strm->next_in[1] == 139) {
+ inflateReset(strm);
+ state->how = GZIP;
+ state->direct = 0;
+ return 0;
+ }
+
+ /* no gzip header -- if we were decoding gzip before, then this is trailing
+ garbage. Ignore the trailing garbage and finish. */
+ if (state->direct == 0) {
+ strm->avail_in = 0;
+ state->eof = 1;
+ state->x.have = 0;
+ return 0;
+ }
+
+ /* doing raw i/o, copy any leftover input to output -- this assumes that
+ the output buffer is larger than the input buffer, which also assures
+ space for gzungetc() */
+ state->x.next = state->out;
+ if (strm->avail_in) {
+ memcpy(state->x.next, strm->next_in, strm->avail_in);
+ state->x.have = strm->avail_in;
+ strm->avail_in = 0;
+ }
+ state->how = COPY;
+ state->direct = 1;
+ return 0;
+}
+
+/* Decompress from input to the provided next_out and avail_out in the state.
+ On return, state->x.have and state->x.next point to the just decompressed
+ data. If the gzip stream completes, state->how is reset to LOOK to look for
+ the next gzip stream or raw data, once state->x.have is depleted. Returns 0
+ on success, -1 on failure. */
+local int gz_decomp(state)
+ gz_statep state;
+{
+ int ret = Z_OK;
+ unsigned had;
+ z_streamp strm = &(state->strm);
+
+ /* fill output buffer up to end of deflate stream */
+ had = strm->avail_out;
+ do {
+ /* get more input for inflate() */
+ if (strm->avail_in == 0 && gz_avail(state) == -1)
+ return -1;
+ if (strm->avail_in == 0) {
+ gz_error(state, Z_BUF_ERROR, "unexpected end of file");
+ break;
+ }
+
+ /* decompress and handle errors */
+ ret = inflate(strm, Z_NO_FLUSH);
+ if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
+ gz_error(state, Z_STREAM_ERROR,
+ "internal error: inflate stream corrupt");
+ return -1;
+ }
+ if (ret == Z_MEM_ERROR) {
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+ if (ret == Z_DATA_ERROR) { /* deflate stream invalid */
+ gz_error(state, Z_DATA_ERROR,
+ strm->msg == NULL ? "compressed data error" : strm->msg);
+ return -1;
+ }
+ } while (strm->avail_out && ret != Z_STREAM_END);
+
+ /* update available output */
+ state->x.have = had - strm->avail_out;
+ state->x.next = strm->next_out - state->x.have;
+
+ /* if the gzip stream completed successfully, look for another */
+ if (ret == Z_STREAM_END)
+ state->how = LOOK;
+
+ /* good decompression */
+ return 0;
+}
+
+/* Fetch data and put it in the output buffer. Assumes state->x.have is 0.
+ Data is either copied from the input file or decompressed from the input
+ file depending on state->how. If state->how is LOOK, then a gzip header is
+ looked for to determine whether to copy or decompress. Returns -1 on error,
+ otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the
+ end of the input file has been reached and all data has been processed. */
+local int gz_fetch(state)
+ gz_statep state;
+{
+ z_streamp strm = &(state->strm);
+
+ do {
+ switch(state->how) {
+ case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */
+ if (gz_look(state) == -1)
+ return -1;
+ if (state->how == LOOK)
+ return 0;
+ break;
+ case COPY: /* -> COPY */
+ if (gz_load(state, state->out, state->size << 1, &(state->x.have))
+ == -1)
+ return -1;
+ state->x.next = state->out;
+ return 0;
+ case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */
+ strm->avail_out = state->size << 1;
+ strm->next_out = state->out;
+ if (gz_decomp(state) == -1)
+ return -1;
+ }
+ } while (state->x.have == 0 && (!state->eof || strm->avail_in));
+ return 0;
+}
+
+/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
+local int gz_skip(state, len)
+ gz_statep state;
+ z_off64_t len;
+{
+ unsigned n;
+
+ /* skip over len bytes or reach end-of-file, whichever comes first */
+ while (len)
+ /* skip over whatever is in output buffer */
+ if (state->x.have) {
+ n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
+ (unsigned)len : state->x.have;
+ state->x.have -= n;
+ state->x.next += n;
+ state->x.pos += n;
+ len -= n;
+ }
+
+ /* output buffer empty -- return if we're at the end of the input */
+ else if (state->eof && state->strm.avail_in == 0)
+ break;
+
+ /* need more data to skip -- load up output buffer */
+ else {
+ /* get more output, looking for header if required */
+ if (gz_fetch(state) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzread(file, buf, len)
+ gzFile file;
+ voidp buf;
+ unsigned len;
+{
+ unsigned got, n;
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're reading and that there's no (serious) error */
+ if (state->mode != GZ_READ ||
+ (state->err != Z_OK && state->err != Z_BUF_ERROR))
+ return -1;
+
+ /* since an int is returned, make sure len fits in one, otherwise return
+ with an error (this avoids the flaw in the interface) */
+ if ((int)len < 0) {
+ gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
+ return -1;
+ }
+
+ /* if len is zero, avoid unnecessary operations */
+ if (len == 0)
+ return 0;
+
+ /* process a skip request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_skip(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* get len bytes to buf, or less than len if at the end */
+ got = 0;
+ do {
+ /* first just try copying data from the output buffer */
+ if (state->x.have) {
+ n = state->x.have > len ? len : state->x.have;
+ memcpy(buf, state->x.next, n);
+ state->x.next += n;
+ state->x.have -= n;
+ }
+
+ /* output buffer empty -- return if we're at the end of the input */
+ else if (state->eof && strm->avail_in == 0) {
+ state->past = 1; /* tried to read past end */
+ break;
+ }
+
+ /* need output data -- for small len or new stream load up our output
+ buffer */
+ else if (state->how == LOOK || len < (state->size << 1)) {
+ /* get more output, looking for header if required */
+ if (gz_fetch(state) == -1)
+ return -1;
+ continue; /* no progress yet -- go back to copy above */
+ /* the copy above assures that we will leave with space in the
+ output buffer, allowing at least one gzungetc() to succeed */
+ }
+
+ /* large len -- read directly into user buffer */
+ else if (state->how == COPY) { /* read directly */
+ if (gz_load(state, (unsigned char *)buf, len, &n) == -1)
+ return -1;
+ }
+
+ /* large len -- decompress directly into user buffer */
+ else { /* state->how == GZIP */
+ strm->avail_out = len;
+ strm->next_out = (unsigned char *)buf;
+ if (gz_decomp(state) == -1)
+ return -1;
+ n = state->x.have;
+ state->x.have = 0;
+ }
+
+ /* update progress */
+ len -= n;
+ buf = (char *)buf + n;
+ got += n;
+ state->x.pos += n;
+ } while (len);
+
+ /* return number of bytes read into user buffer (will fit in int) */
+ return (int)got;
+}
+
+/* -- see zlib.h -- */
+#ifdef Z_PREFIX_SET
+# undef z_gzgetc
+#else
+# undef gzgetc
+#endif
+int ZEXPORT gzgetc(file)
+ gzFile file;
+{
+ int ret;
+ unsigned char buf[1];
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ /* check that we're reading and that there's no (serious) error */
+ if (state->mode != GZ_READ ||
+ (state->err != Z_OK && state->err != Z_BUF_ERROR))
+ return -1;
+
+ /* try output buffer (no need to check for skip request) */
+ if (state->x.have) {
+ state->x.have--;
+ state->x.pos++;
+ return *(state->x.next)++;
+ }
+
+ /* nothing there -- try gzread() */
+ ret = gzread(file, buf, 1);
+ return ret < 1 ? -1 : buf[0];
+}
+
+int ZEXPORT gzgetc_(file)
+gzFile file;
+{
+ return gzgetc(file);
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzungetc(c, file)
+ int c;
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ /* check that we're reading and that there's no (serious) error */
+ if (state->mode != GZ_READ ||
+ (state->err != Z_OK && state->err != Z_BUF_ERROR))
+ return -1;
+
+ /* process a skip request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_skip(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* can't push EOF */
+ if (c < 0)
+ return -1;
+
+ /* if output buffer empty, put byte at end (allows more pushing) */
+ if (state->x.have == 0) {
+ state->x.have = 1;
+ state->x.next = state->out + (state->size << 1) - 1;
+ state->x.next[0] = c;
+ state->x.pos--;
+ state->past = 0;
+ return c;
+ }
+
+ /* if no room, give up (must have already done a gzungetc()) */
+ if (state->x.have == (state->size << 1)) {
+ gz_error(state, Z_DATA_ERROR, "out of room to push characters");
+ return -1;
+ }
+
+ /* slide output data if needed and insert byte before existing data */
+ if (state->x.next == state->out) {
+ unsigned char *src = state->out + state->x.have;
+ unsigned char *dest = state->out + (state->size << 1);
+ while (src > state->out)
+ *--dest = *--src;
+ state->x.next = dest;
+ }
+ state->x.have++;
+ state->x.next--;
+ state->x.next[0] = c;
+ state->x.pos--;
+ state->past = 0;
+ return c;
+}
+
+/* -- see zlib.h -- */
+char * ZEXPORT gzgets(file, buf, len)
+ gzFile file;
+ char *buf;
+ int len;
+{
+ unsigned left, n;
+ char *str;
+ unsigned char *eol;
+ gz_statep state;
+
+ /* check parameters and get internal structure */
+ if (file == NULL || buf == NULL || len < 1)
+ return NULL;
+ state = (gz_statep)file;
+
+ /* check that we're reading and that there's no (serious) error */
+ if (state->mode != GZ_READ ||
+ (state->err != Z_OK && state->err != Z_BUF_ERROR))
+ return NULL;
+
+ /* process a skip request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_skip(state, state->skip) == -1)
+ return NULL;
+ }
+
+ /* copy output bytes up to new line or len - 1, whichever comes first --
+ append a terminating zero to the string (we don't check for a zero in
+ the contents, let the user worry about that) */
+ str = buf;
+ left = (unsigned)len - 1;
+ if (left) do {
+ /* assure that something is in the output buffer */
+ if (state->x.have == 0 && gz_fetch(state) == -1)
+ return NULL; /* error */
+ if (state->x.have == 0) { /* end of file */
+ state->past = 1; /* read past end */
+ break; /* return what we have */
+ }
+
+ /* look for end-of-line in current output buffer */
+ n = state->x.have > left ? left : state->x.have;
+ eol = (unsigned char *)memchr(state->x.next, '\n', n);
+ if (eol != NULL)
+ n = (unsigned)(eol - state->x.next) + 1;
+
+ /* copy through end-of-line, or remainder if not found */
+ memcpy(buf, state->x.next, n);
+ state->x.have -= n;
+ state->x.next += n;
+ state->x.pos += n;
+ left -= n;
+ buf += n;
+ } while (left && eol == NULL);
+
+ /* return terminated string, or if nothing, end of file */
+ if (buf == str)
+ return NULL;
+ buf[0] = 0;
+ return str;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzdirect(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return 0;
+ state = (gz_statep)file;
+
+ /* if the state is not known, but we can find out, then do so (this is
+ mainly for right after a gzopen() or gzdopen()) */
+ if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
+ (void)gz_look(state);
+
+ /* return 1 if transparent, 0 if processing a gzip stream */
+ return state->direct;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzclose_r(file)
+ gzFile file;
+{
+ int ret, err;
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+
+ /* check that we're reading */
+ if (state->mode != GZ_READ)
+ return Z_STREAM_ERROR;
+
+ /* free memory and close file */
+ if (state->size) {
+ inflateEnd(&(state->strm));
+ free(state->out);
+ free(state->in);
+ }
+ err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
+ gz_error(state, Z_OK, NULL);
+ free(state->path);
+ ret = close(state->fd);
+ free(state);
+ return ret ? Z_ERRNO : err;
+}
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzwrite.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzwrite.c
new file mode 100644
index 00000000000..aa767fbf63e
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/gzwrite.c
@@ -0,0 +1,577 @@
+/* gzwrite.c -- zlib functions for writing gzip files
+ * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* Local functions */
+local int gz_init OF((gz_statep));
+local int gz_comp OF((gz_statep, int));
+local int gz_zero OF((gz_statep, z_off64_t));
+
+/* Initialize state for writing a gzip file. Mark initialization by setting
+ state->size to non-zero. Return -1 on failure or 0 on success. */
+local int gz_init(state)
+ gz_statep state;
+{
+ int ret;
+ z_streamp strm = &(state->strm);
+
+ /* allocate input buffer */
+ state->in = (unsigned char *)malloc(state->want);
+ if (state->in == NULL) {
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+
+ /* only need output buffer and deflate state if compressing */
+ if (!state->direct) {
+ /* allocate output buffer */
+ state->out = (unsigned char *)malloc(state->want);
+ if (state->out == NULL) {
+ free(state->in);
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+
+ /* allocate deflate memory, set up for gzip compression */
+ strm->zalloc = Z_NULL;
+ strm->zfree = Z_NULL;
+ strm->opaque = Z_NULL;
+ ret = deflateInit2(strm, state->level, Z_DEFLATED,
+ MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);
+ if (ret != Z_OK) {
+ free(state->out);
+ free(state->in);
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+ }
+
+ /* mark state as initialized */
+ state->size = state->want;
+
+ /* initialize write buffer if compressing */
+ if (!state->direct) {
+ strm->avail_out = state->size;
+ strm->next_out = state->out;
+ state->x.next = strm->next_out;
+ }
+ return 0;
+}
+
+/* Compress whatever is at avail_in and next_in and write to the output file.
+ Return -1 if there is an error writing to the output file, otherwise 0.
+ flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH,
+ then the deflate() state is reset to start a new gzip stream. If gz->direct
+ is true, then simply write to the output file without compressing, and
+ ignore flush. */
+local int gz_comp(state, flush)
+ gz_statep state;
+ int flush;
+{
+ int ret, got;
+ unsigned have;
+ z_streamp strm = &(state->strm);
+
+ /* allocate memory if this is the first time through */
+ if (state->size == 0 && gz_init(state) == -1)
+ return -1;
+
+ /* write directly if requested */
+ if (state->direct) {
+ got = write(state->fd, strm->next_in, strm->avail_in);
+ if (got < 0 || (unsigned)got != strm->avail_in) {
+ gz_error(state, Z_ERRNO, zstrerror());
+ return -1;
+ }
+ strm->avail_in = 0;
+ return 0;
+ }
+
+ /* run deflate() on provided input until it produces no more output */
+ ret = Z_OK;
+ do {
+ /* write out current buffer contents if full, or if flushing, but if
+ doing Z_FINISH then don't write until we get to Z_STREAM_END */
+ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
+ (flush != Z_FINISH || ret == Z_STREAM_END))) {
+ have = (unsigned)(strm->next_out - state->x.next);
+ if (have && ((got = write(state->fd, state->x.next, have)) < 0 ||
+ (unsigned)got != have)) {
+ gz_error(state, Z_ERRNO, zstrerror());
+ return -1;
+ }
+ if (strm->avail_out == 0) {
+ strm->avail_out = state->size;
+ strm->next_out = state->out;
+ }
+ state->x.next = strm->next_out;
+ }
+
+ /* compress */
+ have = strm->avail_out;
+ ret = deflate(strm, flush);
+ if (ret == Z_STREAM_ERROR) {
+ gz_error(state, Z_STREAM_ERROR,
+ "internal error: deflate stream corrupt");
+ return -1;
+ }
+ have -= strm->avail_out;
+ } while (have);
+
+ /* if that completed a deflate stream, allow another to start */
+ if (flush == Z_FINISH)
+ deflateReset(strm);
+
+ /* all done, no errors */
+ return 0;
+}
+
+/* Compress len zeros to output. Return -1 on error, 0 on success. */
+local int gz_zero(state, len)
+ gz_statep state;
+ z_off64_t len;
+{
+ int first;
+ unsigned n;
+ z_streamp strm = &(state->strm);
+
+ /* consume whatever's left in the input buffer */
+ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+ return -1;
+
+ /* compress len zeros (len guaranteed > 0) */
+ first = 1;
+ while (len) {
+ n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
+ (unsigned)len : state->size;
+ if (first) {
+ memset(state->in, 0, n);
+ first = 0;
+ }
+ strm->avail_in = n;
+ strm->next_in = state->in;
+ state->x.pos += n;
+ if (gz_comp(state, Z_NO_FLUSH) == -1)
+ return -1;
+ len -= n;
+ }
+ return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzwrite(file, buf, len)
+ gzFile file;
+ voidpc buf;
+ unsigned len;
+{
+ unsigned put = len;
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return 0;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return 0;
+
+ /* since an int is returned, make sure len fits in one, otherwise return
+ with an error (this avoids the flaw in the interface) */
+ if ((int)len < 0) {
+ gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
+ return 0;
+ }
+
+ /* if len is zero, avoid unnecessary operations */
+ if (len == 0)
+ return 0;
+
+ /* allocate memory if this is the first time through */
+ if (state->size == 0 && gz_init(state) == -1)
+ return 0;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return 0;
+ }
+
+ /* for small len, copy to input buffer, otherwise compress directly */
+ if (len < state->size) {
+ /* copy to input buffer, compress when full */
+ do {
+ unsigned have, copy;
+
+ if (strm->avail_in == 0)
+ strm->next_in = state->in;
+ have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
+ copy = state->size - have;
+ if (copy > len)
+ copy = len;
+ memcpy(state->in + have, buf, copy);
+ strm->avail_in += copy;
+ state->x.pos += copy;
+ buf = (const char *)buf + copy;
+ len -= copy;
+ if (len && gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+ } while (len);
+ }
+ else {
+ /* consume whatever's left in the input buffer */
+ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+
+ /* directly compress user buffer to file */
+ strm->avail_in = len;
+ strm->next_in = (z_const Bytef *)buf;
+ state->x.pos += len;
+ if (gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+ }
+
+ /* input was all buffered or compressed (put will fit in int) */
+ return (int)put;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzputc(file, c)
+ gzFile file;
+ int c;
+{
+ unsigned have;
+ unsigned char buf[1];
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return -1;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* try writing to input buffer for speed (state->size == 0 if buffer not
+ initialized) */
+ if (state->size) {
+ if (strm->avail_in == 0)
+ strm->next_in = state->in;
+ have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
+ if (have < state->size) {
+ state->in[have] = c;
+ strm->avail_in++;
+ state->x.pos++;
+ return c & 0xff;
+ }
+ }
+
+ /* no room in buffer or not initialized, use gz_write() */
+ buf[0] = c;
+ if (gzwrite(file, buf, 1) != 1)
+ return -1;
+ return c & 0xff;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzputs(file, str)
+ gzFile file;
+ const char *str;
+{
+ int ret;
+ unsigned len;
+
+ /* write string */
+ len = (unsigned)strlen(str);
+ ret = gzwrite(file, str, len);
+ return ret == 0 && len != 0 ? -1 : ret;
+}
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#include <stdarg.h>
+
+/* -- see zlib.h -- */
+int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
+{
+ int size, len;
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return 0;
+
+ /* make sure we have some buffer space */
+ if (state->size == 0 && gz_init(state) == -1)
+ return 0;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return 0;
+ }
+
+ /* consume whatever's left in the input buffer */
+ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+
+ /* do the printf() into the input buffer, put length in len */
+ size = (int)(state->size);
+ state->in[size - 1] = 0;
+#ifdef NO_vsnprintf
+# ifdef HAS_vsprintf_void
+ (void)vsprintf((char *)(state->in), format, va);
+ for (len = 0; len < size; len++)
+ if (state->in[len] == 0) break;
+# else
+ len = vsprintf((char *)(state->in), format, va);
+# endif
+#else
+# ifdef HAS_vsnprintf_void
+ (void)vsnprintf((char *)(state->in), size, format, va);
+ len = strlen((char *)(state->in));
+# else
+ len = vsnprintf((char *)(state->in), size, format, va);
+# endif
+#endif
+
+ /* check that printf() results fit in buffer */
+ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
+ return 0;
+
+ /* update buffer and position, defer compression until needed */
+ strm->avail_in = (unsigned)len;
+ strm->next_in = state->in;
+ state->x.pos += len;
+ return len;
+}
+
+int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
+{
+ va_list va;
+ int ret;
+
+ va_start(va, format);
+ ret = gzvprintf(file, format, va);
+ va_end(va);
+ return ret;
+}
+
+#else /* !STDC && !Z_HAVE_STDARG_H */
+
+/* -- see zlib.h -- */
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+ gzFile file;
+ const char *format;
+ int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+ int size, len;
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that can really pass pointer in ints */
+ if (sizeof(int) != sizeof(void *))
+ return 0;
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return 0;
+
+ /* make sure we have some buffer space */
+ if (state->size == 0 && gz_init(state) == -1)
+ return 0;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return 0;
+ }
+
+ /* consume whatever's left in the input buffer */
+ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+
+ /* do the printf() into the input buffer, put length in len */
+ size = (int)(state->size);
+ state->in[size - 1] = 0;
+#ifdef NO_snprintf
+# ifdef HAS_sprintf_void
+ sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ for (len = 0; len < size; len++)
+ if (state->in[len] == 0) break;
+# else
+ len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#else
+# ifdef HAS_snprintf_void
+ snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ len = strlen((char *)(state->in));
+# else
+ len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6,
+ a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18,
+ a19, a20);
+# endif
+#endif
+
+ /* check that printf() results fit in buffer */
+ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
+ return 0;
+
+ /* update buffer and position, defer compression until needed */
+ strm->avail_in = (unsigned)len;
+ strm->next_in = state->in;
+ state->x.pos += len;
+ return len;
+}
+
+#endif
+
+/* -- see zlib.h -- */
+int ZEXPORT gzflush(file, flush)
+ gzFile file;
+ int flush;
+{
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return Z_STREAM_ERROR;
+
+ /* check flush parameter */
+ if (flush < 0 || flush > Z_FINISH)
+ return Z_STREAM_ERROR;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* compress remaining data with requested flush */
+ gz_comp(state, flush);
+ return state->err;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzsetparams(file, level, strategy)
+ gzFile file;
+ int level;
+ int strategy;
+{
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return Z_STREAM_ERROR;
+
+ /* if no change is requested, then do nothing */
+ if (level == state->level && strategy == state->strategy)
+ return Z_OK;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* change compression parameters for subsequent input */
+ if (state->size) {
+ /* flush previous input with previous parameters before changing */
+ if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1)
+ return state->err;
+ deflateParams(strm, level, strategy);
+ }
+ state->level = level;
+ state->strategy = strategy;
+ return Z_OK;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzclose_w(file)
+ gzFile file;
+{
+ int ret = Z_OK;
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+
+ /* check that we're writing */
+ if (state->mode != GZ_WRITE)
+ return Z_STREAM_ERROR;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ ret = state->err;
+ }
+
+ /* flush, free memory, and close file */
+ if (gz_comp(state, Z_FINISH) == -1)
+ ret = state->err;
+ if (state->size) {
+ if (!state->direct) {
+ (void)deflateEnd(&(state->strm));
+ free(state->out);
+ }
+ free(state->in);
+ }
+ gz_error(state, Z_OK, NULL);
+ free(state->path);
+ if (close(state->fd) == -1)
+ ret = Z_ERRNO;
+ free(state);
+ return ret;
+}
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/infback.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/infback.c
new file mode 100644
index 00000000000..f3833c2e434
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/infback.c
@@ -0,0 +1,640 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2011 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ This code is largely copied from inflate.c. Normally either infback.o or
+ inflate.o would be linked into an application--not both. The interface
+ with inffast.c is retained so that optimized assembler-coded versions of
+ inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+ strm provides memory allocation functions in zalloc and zfree, or
+ Z_NULL to use the library memory allocation functions.
+
+ windowBits is in the range 8..15, and window is a user-supplied
+ window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL || window == Z_NULL ||
+ windowBits < 8 || windowBits > 15)
+ return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+#endif
+ }
+ if (strm->zfree == (free_func)0)
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zfree = zcfree;
+#endif
+ state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+ sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->dmax = 32768U;
+ state->wbits = windowBits;
+ state->wsize = 1U << windowBits;
+ state->window = window;
+ state->wnext = 0;
+ state->whave = 0;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Assure that some input is available. If input is requested, but denied,
+ then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+ do { \
+ if (have == 0) { \
+ have = in(in_desc, &next); \
+ if (have == 0) { \
+ next = Z_NULL; \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+ with an error if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ PULL(); \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflateBack() with
+ an error. */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Assure that some output space is available, by writing out the window
+ if it's full. If the write fails, return from inflateBack() with a
+ Z_BUF_ERROR. */
+#define ROOM() \
+ do { \
+ if (left == 0) { \
+ put = state->window; \
+ left = state->wsize; \
+ state->whave = left; \
+ if (out(out_desc, put, left)) { \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/*
+ strm provides the memory allocation functions and window buffer on input,
+ and provides information on the unused input on return. For Z_DATA_ERROR
+ returns, strm will also provide an error message.
+
+ in() and out() are the call-back input and output functions. When
+ inflateBack() needs more input, it calls in(). When inflateBack() has
+ filled the window with output, or when it completes with data in the
+ window, it calls out() to write out the data. The application must not
+ change the provided input until in() is called again or inflateBack()
+ returns. The application must not change the window/output buffer until
+ inflateBack() returns.
+
+ in() and out() are called with a descriptor parameter provided in the
+ inflateBack() call. This parameter can be a structure that provides the
+ information required to do the read or write, as well as accumulated
+ information on the input and output such as totals and check values.
+
+ in() should return zero on failure. out() should return non-zero on
+ failure. If either in() or out() fails, than inflateBack() returns a
+ Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
+ was in() or out() that caused in the error. Otherwise, inflateBack()
+ returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+ error, or Z_MEM_ERROR if it could not allocate memory for the state.
+ inflateBack() can also return Z_STREAM_ERROR if the input parameters
+ are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+ struct inflate_state FAR *state;
+ z_const unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code here; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* Check that the strm exists and that the state was initialized */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* Reset the state */
+ strm->msg = Z_NULL;
+ state->mode = TYPE;
+ state->last = 0;
+ state->whave = 0;
+ next = strm->next_in;
+ have = next != Z_NULL ? strm->avail_in : 0;
+ hold = 0;
+ bits = 0;
+ put = state->window;
+ left = state->wsize;
+
+ /* Inflate until end of block marked as last */
+ for (;;)
+ switch (state->mode) {
+ case TYPE:
+ /* determine and dispatch block type */
+ if (state->last) {
+ BYTEBITS();
+ state->mode = DONE;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+
+ case STORED:
+ /* get and verify stored block length */
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+
+ /* copy stored block from input to output */
+ while (state->length != 0) {
+ copy = state->length;
+ PULL();
+ ROOM();
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+
+ case TABLE:
+ /* get dynamic table entries descriptor */
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+
+ /* get code length code lengths (not a typo) */
+ state->have = 0;
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+
+ /* get length and distance code code lengths */
+ state->have = 0;
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.val < 16) {
+ DROPBITS(here.bits);
+ state->lens[state->have++] = here.val;
+ }
+ else {
+ if (here.val == 16) {
+ NEEDBITS(here.bits + 2);
+ DROPBITS(here.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = (unsigned)(state->lens[state->have - 1]);
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (here.val == 17) {
+ NEEDBITS(here.bits + 3);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(here.bits + 7);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* check for end-of-block code (better have one) */
+ if (state->lens[256] == 0) {
+ strm->msg = (char *)"invalid code -- missing end-of-block";
+ state->mode = BAD;
+ break;
+ }
+
+ /* build code tables -- note: do not change the lenbits or distbits
+ values here (9 and 6) without reading the comments in inftrees.h
+ concerning the ENOUGH constants, which depend on those values */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+
+ case LEN:
+ /* use inflate_fast() if we have enough input and output */
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ if (state->whave < state->wsize)
+ state->whave = state->wsize - left;
+ inflate_fast(strm, state->wsize);
+ LOAD();
+ break;
+ }
+
+ /* get a literal, length, or end-of-block code */
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.op && (here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(here.bits);
+ state->length = (unsigned)here.val;
+
+ /* process literal */
+ if (here.op == 0) {
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ ROOM();
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ }
+
+ /* process end of block */
+ if (here.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+
+ /* invalid code */
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+
+ /* length code -- get extra bits, if any */
+ state->extra = (unsigned)(here.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+
+ /* get distance code */
+ for (;;) {
+ here = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(here.bits);
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)here.val;
+
+ /* get distance extra bits, if any */
+ state->extra = (unsigned)(here.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ if (state->offset > state->wsize - (state->whave < state->wsize ?
+ left : 0)) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+
+ /* copy match from window to output */
+ do {
+ ROOM();
+ copy = state->wsize - state->offset;
+ if (copy < left) {
+ from = put + copy;
+ copy = left - copy;
+ }
+ else {
+ from = put - state->offset;
+ copy = left;
+ }
+ if (copy > state->length) copy = state->length;
+ state->length -= copy;
+ left -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ } while (state->length != 0);
+ break;
+
+ case DONE:
+ /* inflate stream terminated properly -- write leftover output */
+ ret = Z_STREAM_END;
+ if (left < state->wsize) {
+ if (out(out_desc, state->window, state->wsize - left))
+ ret = Z_BUF_ERROR;
+ }
+ goto inf_leave;
+
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+
+ default: /* can't happen, but makes compilers happy */
+ ret = Z_STREAM_ERROR;
+ goto inf_leave;
+ }
+
+ /* Return unused input */
+ inf_leave:
+ strm->next_in = next;
+ strm->avail_in = have;
+ return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/inffast.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inffast.c
new file mode 100644
index 00000000000..bda59ceb6a1
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inffast.c
@@ -0,0 +1,340 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2008, 2010, 2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void ZLIB_INTERNAL inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ z_const unsigned char FAR *in; /* local strm->next_in */
+ z_const unsigned char FAR *last; /* have enough input while in < last */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned wnext; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code here; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ wnext = state->wnext;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ here = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(here.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(here.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ PUP(out) = (unsigned char)(here.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(here.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ here = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(here.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(here.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(here.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ if (state->sane) {
+ strm->msg =
+ (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ if (len <= op - whave) {
+ do {
+ PUP(out) = 0;
+ } while (--len);
+ continue;
+ }
+ len -= op - whave;
+ do {
+ PUP(out) = 0;
+ } while (--op > whave);
+ if (op == 0) {
+ from = out - dist;
+ do {
+ PUP(out) = PUP(from);
+ } while (--len);
+ continue;
+ }
+#endif
+ }
+ from = window - OFF;
+ if (wnext == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (wnext < op) { /* wrap around window */
+ from += wsize + wnext - op;
+ op -= wnext;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (wnext < len) { /* some from start of window */
+ op = wnext;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += wnext - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ here = dcode[here.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ here = lcode[here.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and wnext == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/inffast.h b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inffast.h
new file mode 100644
index 00000000000..e5c1aa4ca8c
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/inffixed.h b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inffixed.h
new file mode 100644
index 00000000000..d6283277694
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inffixed.h
@@ -0,0 +1,94 @@
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications.
+ It is part of the implementation of this library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/inflate.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inflate.c
new file mode 100644
index 00000000000..870f89bb4d3
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inflate.c
@@ -0,0 +1,1512 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2012 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common wnext == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,
+ unsigned copy));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateResetKeep(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ if (state->wrap) /* to support ill-conceived Java test suite */
+ strm->adler = state->wrap & 1;
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->head = Z_NULL;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ state->sane = 1;
+ state->back = -1;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ state->wsize = 0;
+ state->whave = 0;
+ state->wnext = 0;
+ return inflateResetKeep(strm);
+}
+
+int ZEXPORT inflateReset2(strm, windowBits)
+z_streamp strm;
+int windowBits;
+{
+ int wrap;
+ struct inflate_state FAR *state;
+
+ /* get the state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* extract wrap request from windowBits parameter */
+ if (windowBits < 0) {
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48)
+ windowBits &= 15;
+#endif
+ }
+
+ /* set number of window bits, free window if different */
+ if (windowBits && (windowBits < 8 || windowBits > 15))
+ return Z_STREAM_ERROR;
+ if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
+ ZFREE(strm, state->window);
+ state->window = Z_NULL;
+ }
+
+ /* update state and reset the rest of it */
+ state->wrap = wrap;
+ state->wbits = (unsigned)windowBits;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ int ret;
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+#endif
+ }
+ if (strm->zfree == (free_func)0)
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zfree = zcfree;
+#endif
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->window = Z_NULL;
+ ret = inflateReset2(strm, windowBits);
+ if (ret != Z_OK) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ }
+ return ret;
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (bits < 0) {
+ state->hold = 0;
+ state->bits = 0;
+ return Z_OK;
+ }
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
+ state.lencode[low].bits, state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, end, copy)
+z_streamp strm;
+const Bytef *end;
+unsigned copy;
+{
+ struct inflate_state FAR *state;
+ unsigned dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->wnext = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, end - state->wsize, state->wsize);
+ state->wnext = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->wnext;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->wnext, end - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, end - copy, copy);
+ state->wnext = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->wnext += dist;
+ if (state->wnext == state->wsize) state->wnext = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ z_const unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code here; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (state->head != Z_NULL)
+ state->head->done = -1;
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (state->wbits == 0)
+ state->wbits = len;
+ else if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->head != Z_NULL)
+ state->head->text = (int)((hold >> 8) & 1);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->head != Z_NULL)
+ state->head->time = hold;
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->head != Z_NULL) {
+ state->head->xflags = (int)(hold & 0xff);
+ state->head->os = (int)(hold >> 8);
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->head != Z_NULL)
+ state->head->extra_len = (unsigned)hold;
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ else if (state->head != Z_NULL)
+ state->head->extra = Z_NULL;
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->head != Z_NULL &&
+ state->head->extra != Z_NULL) {
+ len = state->head->extra_len - state->length;
+ zmemcpy(state->head->extra + len, next,
+ len + copy > state->head->extra_max ?
+ state->head->extra_max - len : copy);
+ }
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->length = 0;
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->name != Z_NULL &&
+ state->length < state->head->name_max)
+ state->head->name[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->name = Z_NULL;
+ state->length = 0;
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->comment != Z_NULL &&
+ state->length < state->head->comm_max)
+ state->head->comment[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->comment = Z_NULL;
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ if (state->head != Z_NULL) {
+ state->head->hcrc = (int)((state->flags >> 9) & 1);
+ state->head->done = 1;
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = ZSWAP32(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN_; /* decode codes */
+ if (flush == Z_TREES) {
+ DROPBITS(2);
+ goto inf_leave;
+ }
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY_;
+ if (flush == Z_TREES) goto inf_leave;
+ case COPY_:
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (const code FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.val < 16) {
+ DROPBITS(here.bits);
+ state->lens[state->have++] = here.val;
+ }
+ else {
+ if (here.val == 16) {
+ NEEDBITS(here.bits + 2);
+ DROPBITS(here.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (here.val == 17) {
+ NEEDBITS(here.bits + 3);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(here.bits + 7);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* check for end-of-block code (better have one) */
+ if (state->lens[256] == 0) {
+ strm->msg = (char *)"invalid code -- missing end-of-block";
+ state->mode = BAD;
+ break;
+ }
+
+ /* build code tables -- note: do not change the lenbits or distbits
+ values here (9 and 6) without reading the comments in inftrees.h
+ concerning the ENOUGH constants, which depend on those values */
+ state->next = state->codes;
+ state->lencode = (const code FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (const code FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN_;
+ if (flush == Z_TREES) goto inf_leave;
+ case LEN_:
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ if (state->mode == TYPE)
+ state->back = -1;
+ break;
+ }
+ state->back = 0;
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.op && (here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ state->back += last.bits;
+ }
+ DROPBITS(here.bits);
+ state->back += here.bits;
+ state->length = (unsigned)here.val;
+ if ((int)(here.op) == 0) {
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ state->mode = LIT;
+ break;
+ }
+ if (here.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->back = -1;
+ state->mode = TYPE;
+ break;
+ }
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(here.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ state->back += state->extra;
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->was = state->length;
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ here = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ state->back += last.bits;
+ }
+ DROPBITS(here.bits);
+ state->back += here.bits;
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)here.val;
+ state->extra = (unsigned)(here.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ state->back += state->extra;
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->whave) {
+ if (state->sane) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ Trace((stderr, "inflate.c too far\n"));
+ copy -= state->whave;
+ if (copy > state->length) copy = state->length;
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = 0;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+#endif
+ }
+ if (copy > state->wnext) {
+ copy -= state->wnext;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->wnext - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ ZSWAP32(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
+ (state->mode < CHECK || flush != Z_FINISH)))
+ if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0) +
+ (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+Bytef *dictionary;
+uInt *dictLength;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* copy dictionary */
+ if (state->whave && dictionary != Z_NULL) {
+ zmemcpy(dictionary, state->window + state->wnext,
+ state->whave - state->wnext);
+ zmemcpy(dictionary + state->whave - state->wnext,
+ state->window, state->wnext);
+ }
+ if (dictLength != Z_NULL)
+ *dictLength = state->whave;
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long dictid;
+ int ret;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary identifier */
+ if (state->mode == DICT) {
+ dictid = adler32(0L, Z_NULL, 0);
+ dictid = adler32(dictid, dictionary, dictLength);
+ if (dictid != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window using updatewindow(), which will amend the
+ existing dictionary if appropriate */
+ ret = updatewindow(strm, dictionary + dictLength, dictLength);
+ if (ret) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+ /* save header structure */
+ state->head = head;
+ head->done = 0;
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+const unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+ unsigned wsize;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
+ zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
+ if (state->lencode >= state->codes &&
+ state->lencode <= state->codes + ENOUGH - 1) {
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ }
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL) {
+ wsize = 1U << state->wbits;
+ zmemcpy(window, state->window, wsize);
+ }
+ copy->window = window;
+ dest->state = (struct internal_state FAR *)copy;
+ return Z_OK;
+}
+
+int ZEXPORT inflateUndermine(strm, subvert)
+z_streamp strm;
+int subvert;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ state->sane = !subvert;
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ return Z_OK;
+#else
+ state->sane = 1;
+ return Z_DATA_ERROR;
+#endif
+}
+
+long ZEXPORT inflateMark(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16;
+ state = (struct inflate_state FAR *)strm->state;
+ return ((long)(state->back) << 16) +
+ (state->mode == COPY ? state->length :
+ (state->mode == MATCH ? state->was - state->length : 0));
+}
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/inflate.h b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inflate.h
new file mode 100644
index 00000000000..95f4986d400
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inflate.h
@@ -0,0 +1,122 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2009 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY_, /* i/o: same as COPY below, but only first time in */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN_, /* i: same as LEN below, but only first time in */
+ LEN, /* i: waiting for length/lit/eob code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to BAD or MEM on error -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib) or (raw)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
+ HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ (raw) -> TYPEDO
+ Read deflate blocks:
+ TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
+ STORED -> COPY_ -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN_
+ LEN_ -> LEN
+ Read deflate codes in fixed or dynamic block:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 10K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ gz_headerp head; /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned wnext; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+ int sane; /* if false, allow invalid distance too far */
+ int back; /* bits back of last unprocessed length/lit */
+ unsigned was; /* initial length of match */
+};
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/inftrees.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inftrees.c
new file mode 100644
index 00000000000..44d89cf24e1
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inftrees.c
@@ -0,0 +1,306 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.8 Copyright 1995-2013 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code here; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ here.op = (unsigned char)64; /* invalid code marker */
+ here.bits = (unsigned char)1;
+ here.val = (unsigned short)0;
+ *(*table)++ = here; /* make a table to force an error */
+ *(*table)++ = here;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min < max; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked for LENS and DIST tables against
+ the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
+ the initial root table size constants. See the comments in inftrees.h
+ for more information.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if ((type == LENS && used > ENOUGH_LENS) ||
+ (type == DISTS && used > ENOUGH_DISTS))
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ here.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ here.op = (unsigned char)0;
+ here.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ here.op = (unsigned char)(extra[work[sym]]);
+ here.val = base[work[sym]];
+ }
+ else {
+ here.op = (unsigned char)(32 + 64); /* end of block */
+ here.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = here;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if ((type == LENS && used > ENOUGH_LENS) ||
+ (type == DISTS && used > ENOUGH_DISTS))
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /* fill in remaining table entry if code is incomplete (guaranteed to have
+ at most one remaining entry, since if the code is incomplete, the
+ maximum code length that was allowed to get this far is one bit) */
+ if (huff != 0) {
+ here.op = (unsigned char)64; /* invalid code marker */
+ here.bits = (unsigned char)(len - drop);
+ here.val = (unsigned short)0;
+ next[huff] = here;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/inftrees.h b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inftrees.h
new file mode 100644
index 00000000000..baa53a0b1a1
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/inftrees.h
@@ -0,0 +1,62 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of the dynamic table. The maximum number of code structures is
+ 1444, which is the sum of 852 for literal/length codes and 592 for distance
+ codes. These values were found by exhaustive searches using the program
+ examples/enough.c found in the zlib distribtution. The arguments to that
+ program are the number of symbols, the initial root table size, and the
+ maximum bit length of a code. "enough 286 9 15" for literal/length codes
+ returns returns 852, and "enough 30 6 15" for distance codes returns 592.
+ The initial root table size (9 or 6) is found in the fifth argument of the
+ inflate_table() calls in inflate.c and infback.c. If the root table size is
+ changed, then these maximum sizes would be need to be recalculated and
+ updated. */
+#define ENOUGH_LENS 852
+#define ENOUGH_DISTS 592
+#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
+
+/* Type of code to build for inflate_table() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/trees.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/trees.c
new file mode 100644
index 00000000000..1fd7759ef00
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/trees.c
@@ -0,0 +1,1226 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2012 Jean-loup Gailly
+ * detect_data_type() function provided freely by Cosmin Truta, 2006
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, const ct_data *ltree,
+ const ct_data *dtree));
+local int detect_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (ush)value << s->bi_valid;
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= (ush)value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (ush)val << s->bi_valid;\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (ush)(value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+#ifdef NO_INIT_GLOBAL_POINTERS
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+#endif
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header,
+ "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void ZLIB_INTERNAL _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if ((unsigned) tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+ s->depth[n] : s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int last; /* one if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Flush the bits in the bit buffer to pending output (leaves at most 7 bits)
+ */
+void ZLIB_INTERNAL _tr_flush_bits(s)
+ deflate_state *s;
+{
+ bi_flush(s);
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ */
+void ZLIB_INTERNAL _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int last; /* one if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is binary or text */
+ if (s->strm->data_type == Z_UNKNOWN)
+ s->strm->data_type = detect_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute the block lengths in bytes. */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, last);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+last, 3);
+ compress_block(s, (const ct_data *)static_ltree,
+ (const ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+last, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (const ct_data *)s->dyn_ltree,
+ (const ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (last) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*last));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ZLIB_INTERNAL _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ const ct_data *ltree; /* literal tree */
+ const ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+ "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Check if the data type is TEXT or BINARY, using the following algorithm:
+ * - TEXT if the two conditions below are satisfied:
+ * a) There are no non-portable control characters belonging to the
+ * "black list" (0..6, 14..25, 28..31).
+ * b) There is at least one printable character belonging to the
+ * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ * - The following partially-portable control characters form a
+ * "gray list" that is ignored in this detection algorithm:
+ * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local int detect_data_type(s)
+ deflate_state *s;
+{
+ /* black_mask is the bit mask of black-listed bytes
+ * set bits 0..6, 14..25, and 28..31
+ * 0xf3ffc07f = binary 11110011111111111100000001111111
+ */
+ unsigned long black_mask = 0xf3ffc07fUL;
+ int n;
+
+ /* Check for non-textual ("black-listed") bytes. */
+ for (n = 0; n <= 31; n++, black_mask >>= 1)
+ if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))
+ return Z_BINARY;
+
+ /* Check for textual ("white-listed") bytes. */
+ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
+ || s->dyn_ltree[13].Freq != 0)
+ return Z_TEXT;
+ for (n = 32; n < LITERALS; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ return Z_TEXT;
+
+ /* There are no "black-listed" or "white-listed" bytes:
+ * this stream either is empty or has tolerated ("gray-listed") bytes only.
+ */
+ return Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/trees.h b/source/blender/python/manta_full/dependencies/zlib-1.2.8/trees.h
new file mode 100644
index 00000000000..d35639d82a2
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/trees.h
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/uncompr.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/uncompr.c
new file mode 100644
index 00000000000..242e9493dff
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/uncompr.c
@@ -0,0 +1,59 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003, 2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (z_const Bytef *)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/zconf.h b/source/blender/python/manta_full/dependencies/zlib-1.2.8/zconf.h
new file mode 100644
index 00000000000..9987a775530
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/zconf.h
@@ -0,0 +1,511 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ * Even better than compiling with -DZ_PREFIX would be to use configure to set
+ * this permanently in zconf.h using "./configure --zprefix".
+ */
+#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
+# define Z_PREFIX_SET
+
+/* all linked symbols */
+# define _dist_code z__dist_code
+# define _length_code z__length_code
+# define _tr_align z__tr_align
+# define _tr_flush_bits z__tr_flush_bits
+# define _tr_flush_block z__tr_flush_block
+# define _tr_init z__tr_init
+# define _tr_stored_block z__tr_stored_block
+# define _tr_tally z__tr_tally
+# define adler32 z_adler32
+# define adler32_combine z_adler32_combine
+# define adler32_combine64 z_adler32_combine64
+# ifndef Z_SOLO
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# endif
+# define crc32 z_crc32
+# define crc32_combine z_crc32_combine
+# define crc32_combine64 z_crc32_combine64
+# define deflate z_deflate
+# define deflateBound z_deflateBound
+# define deflateCopy z_deflateCopy
+# define deflateEnd z_deflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateInit_ z_deflateInit_
+# define deflateParams z_deflateParams
+# define deflatePending z_deflatePending
+# define deflatePrime z_deflatePrime
+# define deflateReset z_deflateReset
+# define deflateResetKeep z_deflateResetKeep
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateSetHeader z_deflateSetHeader
+# define deflateTune z_deflateTune
+# define deflate_copyright z_deflate_copyright
+# define get_crc_table z_get_crc_table
+# ifndef Z_SOLO
+# define gz_error z_gz_error
+# define gz_intmax z_gz_intmax
+# define gz_strwinerror z_gz_strwinerror
+# define gzbuffer z_gzbuffer
+# define gzclearerr z_gzclearerr
+# define gzclose z_gzclose
+# define gzclose_r z_gzclose_r
+# define gzclose_w z_gzclose_w
+# define gzdirect z_gzdirect
+# define gzdopen z_gzdopen
+# define gzeof z_gzeof
+# define gzerror z_gzerror
+# define gzflush z_gzflush
+# define gzgetc z_gzgetc
+# define gzgetc_ z_gzgetc_
+# define gzgets z_gzgets
+# define gzoffset z_gzoffset
+# define gzoffset64 z_gzoffset64
+# define gzopen z_gzopen
+# define gzopen64 z_gzopen64
+# ifdef _WIN32
+# define gzopen_w z_gzopen_w
+# endif
+# define gzprintf z_gzprintf
+# define gzvprintf z_gzvprintf
+# define gzputc z_gzputc
+# define gzputs z_gzputs
+# define gzread z_gzread
+# define gzrewind z_gzrewind
+# define gzseek z_gzseek
+# define gzseek64 z_gzseek64
+# define gzsetparams z_gzsetparams
+# define gztell z_gztell
+# define gztell64 z_gztell64
+# define gzungetc z_gzungetc
+# define gzwrite z_gzwrite
+# endif
+# define inflate z_inflate
+# define inflateBack z_inflateBack
+# define inflateBackEnd z_inflateBackEnd
+# define inflateBackInit_ z_inflateBackInit_
+# define inflateCopy z_inflateCopy
+# define inflateEnd z_inflateEnd
+# define inflateGetHeader z_inflateGetHeader
+# define inflateInit2_ z_inflateInit2_
+# define inflateInit_ z_inflateInit_
+# define inflateMark z_inflateMark
+# define inflatePrime z_inflatePrime
+# define inflateReset z_inflateReset
+# define inflateReset2 z_inflateReset2
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateGetDictionary z_inflateGetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateUndermine z_inflateUndermine
+# define inflateResetKeep z_inflateResetKeep
+# define inflate_copyright z_inflate_copyright
+# define inflate_fast z_inflate_fast
+# define inflate_table z_inflate_table
+# ifndef Z_SOLO
+# define uncompress z_uncompress
+# endif
+# define zError z_zError
+# ifndef Z_SOLO
+# define zcalloc z_zcalloc
+# define zcfree z_zcfree
+# endif
+# define zlibCompileFlags z_zlibCompileFlags
+# define zlibVersion z_zlibVersion
+
+/* all zlib typedefs in zlib.h and zconf.h */
+# define Byte z_Byte
+# define Bytef z_Bytef
+# define alloc_func z_alloc_func
+# define charf z_charf
+# define free_func z_free_func
+# ifndef Z_SOLO
+# define gzFile z_gzFile
+# endif
+# define gz_header z_gz_header
+# define gz_headerp z_gz_headerp
+# define in_func z_in_func
+# define intf z_intf
+# define out_func z_out_func
+# define uInt z_uInt
+# define uIntf z_uIntf
+# define uLong z_uLong
+# define uLongf z_uLongf
+# define voidp z_voidp
+# define voidpc z_voidpc
+# define voidpf z_voidpf
+
+/* all zlib structs in zlib.h and zconf.h */
+# define gz_header_s z_gz_header_s
+# define internal_state z_internal_state
+
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+#if defined(ZLIB_CONST) && !defined(z_const)
+# define z_const const
+#else
+# define z_const
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+#ifndef Z_ARG /* function prototypes for stdarg */
+# if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# define Z_ARG(args) args
+# else
+# define Z_ARG(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
+# include <limits.h>
+# if (UINT_MAX == 0xffffffffUL)
+# define Z_U4 unsigned
+# elif (ULONG_MAX == 0xffffffffUL)
+# define Z_U4 unsigned long
+# elif (USHRT_MAX == 0xffffffffUL)
+# define Z_U4 unsigned short
+# endif
+#endif
+
+#ifdef Z_U4
+ typedef Z_U4 z_crc_t;
+#else
+ typedef unsigned long z_crc_t;
+#endif
+
+#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
+# define Z_HAVE_UNISTD_H
+#endif
+
+#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
+# define Z_HAVE_STDARG_H
+#endif
+
+#ifdef STDC
+# ifndef Z_SOLO
+# include <sys/types.h> /* for off_t */
+# endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# ifndef Z_SOLO
+# include <stdarg.h> /* for va_list */
+# endif
+#endif
+
+#ifdef _WIN32
+# ifndef Z_SOLO
+# include <stddef.h> /* for wchar_t */
+# endif
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
+# undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+# define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# ifndef z_off_t
+# define z_off_t off_t
+# endif
+# endif
+#endif
+
+#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
+# define Z_LFS64
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
+# define Z_LARGE64
+#endif
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
+# define Z_WANT64
+#endif
+
+#if !defined(SEEK_SET) && !defined(Z_SOLO)
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if !defined(_WIN32) && defined(Z_LARGE64)
+# define z_off64_t off64_t
+#else
+# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
+# define z_off64_t __int64
+# else
+# define z_off64_t z_off_t
+# endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+ #pragma map(deflateInit_,"DEIN")
+ #pragma map(deflateInit2_,"DEIN2")
+ #pragma map(deflateEnd,"DEEND")
+ #pragma map(deflateBound,"DEBND")
+ #pragma map(inflateInit_,"ININ")
+ #pragma map(inflateInit2_,"ININ2")
+ #pragma map(inflateEnd,"INEND")
+ #pragma map(inflateSync,"INSY")
+ #pragma map(inflateSetDictionary,"INSEDI")
+ #pragma map(compressBound,"CMBND")
+ #pragma map(inflate_table,"INTABL")
+ #pragma map(inflate_fast,"INFA")
+ #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/zlib.h b/source/blender/python/manta_full/dependencies/zlib-1.2.8/zlib.h
new file mode 100644
index 00000000000..3e0c7672ac5
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/zlib.h
@@ -0,0 +1,1768 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.8, April 28th, 2013
+
+ Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
+ (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.8"
+#define ZLIB_VERNUM 0x1280
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 8
+#define ZLIB_VER_SUBREVISION 0
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed data.
+ This version of the library supports only one compression method (deflation)
+ but other algorithms will be added later and will have the same stream
+ interface.
+
+ Compression can be done in a single step if the buffers are large enough,
+ or can be done by repeated calls of the compression function. In the latter
+ case, the application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never crash
+ even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ z_const Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total number of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total number of bytes output so far */
+
+ z_const char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has dropped
+ to zero. It must update next_out and avail_out when avail_out has dropped
+ to zero. The application must initialize zalloc, zfree and opaque before
+ calling the init function. All other fields are set by the compression
+ library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this if
+ the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers
+ returned by zalloc for objects of exactly 65536 bytes *must* have their
+ offset normalized to zero. The default allocation function provided by this
+ library ensures this (see zutil.c). To reduce memory requirements and avoid
+ any allocation of 64K objects, at the expense of compression ratio, compile
+ the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or progress
+ reports. After compression, total_in holds the total size of the
+ uncompressed data and may be saved for use in the decompressor (particularly
+ if the decompressor wants to decompress everything in a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+#define Z_TREES 6
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is not
+ compatible with the zlib.h header file used by the application. This check
+ is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller. If
+ zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+ allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at all
+ (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION
+ requests a default compromise between speed and compression (currently
+ equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if level is not a valid compression level, or
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION). msg is set to null
+ if there is no error message. deflateInit does not perform any compression:
+ this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications). Some
+ output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming more
+ output, and updating avail_in or avail_out accordingly; avail_out should
+ never be zero before the call. The application can consume the compressed
+ output when it wants, for example when the output buffer is full (avail_out
+ == 0), or after each call of deflate(). If deflate returns Z_OK and with
+ zero avail_out, it must be called again after making room in the output
+ buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumulate before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In
+ particular avail_in is zero after the call if enough output space has been
+ provided before the call.) Flushing may degrade compression for some
+ compression algorithms and so it should be used only when necessary. This
+ completes the current deflate block and follows it with an empty stored block
+ that is three bits plus filler bits to the next byte, followed by four bytes
+ (00 00 ff ff).
+
+ If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
+ output buffer, but the output is not aligned to a byte boundary. All of the
+ input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
+ This completes the current deflate block and follows it with an empty fixed
+ codes block that is 10 bits long. This assures that enough bytes are output
+ in order for the decompressor to finish the block before the empty fixed code
+ block.
+
+ If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
+ for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
+ seven bits of the current block are held to be written as the next byte after
+ the next deflate block is completed. In this case, the decompressor may not
+ be provided enough bits at this point in order to complete decompression of
+ the data provided so far to the compressor. It may need to wait for the next
+ block to be emitted. This is for advanced applications that need to control
+ the emission of deflate blocks.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there was
+ enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the stream
+ are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least the
+ value returned by deflateBound (see below). Then deflate is guaranteed to
+ return Z_STREAM_END. If not enough output space is provided, deflate will
+ not return Z_STREAM_END, and it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect the
+ compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any pending
+ output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case, msg
+ may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the
+ exact value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+ invalid, such as a null pointer to the structure. msg is set to null if
+ there is no error message. inflateInit does not perform any decompression
+ apart from possibly reading the zlib header if present: actual decompression
+ will be done by inflate(). (So next_in and avail_in may be modified, but
+ next_out and avail_out are unused and unchanged.) The current implementation
+ of inflateInit() does not process any header information -- that is deferred
+ until inflate() is called.
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing will
+ resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there is
+ no more input data or no more space in the output buffer (see below about
+ the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming more
+ output, and updating the next_* and avail_* values accordingly. The
+ application can consume the uncompressed output when it wants, for example
+ when the output buffer is full (avail_out == 0), or after each call of
+ inflate(). If inflate returns Z_OK and with zero avail_out, it must be
+ called again after making room in the output buffer because there might be
+ more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
+ Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate()
+ stop if and when it gets to the next deflate block boundary. When decoding
+ the zlib or gzip format, this will cause inflate() to return immediately
+ after the header and before the first block. When doing a raw inflate,
+ inflate() will go ahead and process the first block, and will return when it
+ gets to the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64 if
+ inflate() is currently decoding the last block in the deflate stream, plus
+ 128 if inflate() returned immediately after decoding an end-of-block code or
+ decoding the complete header up to just before the first byte of the deflate
+ stream. The end-of-block will not be indicated until all of the uncompressed
+ data from that block has been written to strm->next_out. The number of
+ unused bits may in general be greater than seven, except when bit 7 of
+ data_type is set, in which case the number of unused bits will be less than
+ eight. data_type is set as noted here every time inflate() returns for all
+ flush options, and so can be used to determine the amount of currently
+ consumed input in bits.
+
+ The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
+ end of each deflate block header is reached, before any actual data in that
+ block is decoded. This allows the caller to determine the length of the
+ deflate block header for later use in random access within a deflate block.
+ 256 is added to the value of strm->data_type when inflate() returns
+ immediately after reaching the end of the deflate block header.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step (a
+ single call of inflate), the parameter flush should be set to Z_FINISH. In
+ this case all pending input is processed and all pending output is flushed;
+ avail_out must be large enough to hold all of the uncompressed data for the
+ operation to complete. (The size of the uncompressed data may have been
+ saved by the compressor for this purpose.) The use of Z_FINISH is not
+ required to perform an inflation in one step. However it may be used to
+ inform inflate that a faster approach can be used for the single inflate()
+ call. Z_FINISH also informs inflate to not maintain a sliding window if the
+ stream completes, which reduces inflate's memory footprint. If the stream
+ does not complete, either because not all of the stream is provided or not
+ enough output space is provided, then a sliding window will be allocated and
+ inflate() can be called again to continue the operation as if Z_NO_FLUSH had
+ been used.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the effects of the flush parameter in this implementation are
+ on the return value of inflate() as noted below, when inflate() returns early
+ when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of
+ memory for a sliding window when Z_FINISH is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the Adler-32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the Adler-32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() can decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically, if requested when
+ initializing with inflateInit2(). Any information contained in the gzip
+ header is not retained, so applications that need that information should
+ instead use raw inflate, see inflateInit2() below, or inflateBack() and
+ perform their own processing of the gzip header and trailer. When processing
+ gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
+ producted so far. The CRC-32 is checked against the gzip trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may
+ then call inflateSync() to look for a good compression block if a partial
+ recovery of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any pending
+ output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by the
+ caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero), no
+ header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but is
+ slow and reduces compression ratio; memLevel=9 uses maximum memory for
+ optimal speed. The default value is 8. See zconf.h for total memory usage
+ as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as
+ fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The
+ strategy parameter only affects the compression ratio but not the
+ correctness of the compressed output even if it is not set appropriately.
+ Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
+ decoder for special applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
+ method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
+ incompatible with the version assumed by the caller (ZLIB_VERSION). msg is
+ set to null if there is no error message. deflateInit2 does not perform any
+ compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. When using the zlib format, this
+ function must be called immediately after deflateInit, deflateInit2 or
+ deflateReset, and before any call of deflate. When doing raw deflate, this
+ function must be called either before any call of deflate, or immediately
+ after the completion of a deflate block, i.e. after all input has been
+ consumed and all output has been delivered when using any of the flush
+ options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The
+ compressor and decompressor must use exactly the same dictionary (see
+ inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size
+ provided in deflateInit or deflateInit2. Thus the strings most likely to be
+ useful should be put at the end of the dictionary, not at the front. In
+ addition, the current implementation of deflate will use at most the window
+ size minus 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if not at a block boundary for raw deflate). deflateSetDictionary does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and can
+ consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being Z_NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state. The
+ stream will keep the same compression level and any other attributes that
+ may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different strategy.
+ If the compression level is changed, the input available so far is
+ compressed with the old level (and may be flushed); the new level will take
+ effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to be
+ compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+ strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit() or
+ deflateInit2(), and after deflateSetHeader(), if used. This would be used
+ to allocate an output buffer for deflation in a single pass, and so would be
+ called before deflate(). If that first deflate() call is provided the
+ sourceLen input bytes, an output buffer allocated to the size returned by
+ deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
+ to return Z_STREAM_END. Note that it is possible for the compressed size to
+ be larger than the value returned by deflateBound() if flush options other
+ than Z_FINISH or Z_NO_FLUSH are used.
+*/
+
+ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
+ unsigned *pending,
+ int *bits));
+/*
+ deflatePending() returns the number of bytes and bits of output that have
+ been generated, but not yet provided in the available output. The bytes not
+ provided would be due to the available output space having being consumed.
+ The number of bits of output not provided are between 0 and 7, where they
+ await more bits to join them in order to fill out a full byte. If pending
+ or bits are Z_NULL, then those values are not set.
+
+ deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+ */
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the bits
+ leftover from a previous deflate stream when appending to it. As such, this
+ function can only be used for raw deflate, and must be used before the first
+ deflate() call after a deflateInit2() or deflateReset(). bits must be less
+ than or equal to 16, and that many of the least significant bits of value
+ will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
+ room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
+ source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be zero to request that inflate use the window size in
+ the zlib header of the compressed stream.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a
+ crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+ invalid, such as a null pointer to the structure. msg is set to null if
+ there is no error message. inflateInit2 does not perform any decompression
+ apart from possibly reading the zlib header if present: actual decompression
+ will be done by inflate(). (So next_in and avail_in may be modified, but
+ next_out and avail_out are unused and unchanged.) The current implementation
+ of inflateInit2() does not process any header information -- that is
+ deferred until inflate() is called.
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called at any
+ time to set the dictionary. If the provided dictionary is smaller than the
+ window and there is already data in the window, then the provided dictionary
+ will amend what's there. The application must insure that the dictionary
+ that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
+ Bytef *dictionary,
+ uInt *dictLength));
+/*
+ Returns the sliding dictionary being maintained by inflate. dictLength is
+ set to the number of bytes in the dictionary, and that many bytes are copied
+ to dictionary. dictionary must have enough space, where 32768 bytes is
+ always enough. If inflateGetDictionary() is called with dictionary equal to
+ Z_NULL, then only the dictionary length is returned, and nothing is copied.
+ Similary, if dictLength is Z_NULL, then it is not set.
+
+ inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
+ stream state is inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a possible full flush point (see above
+ for the description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync searches for a 00 00 FF FF pattern in the compressed data.
+ All full flush points have this pattern, but not all occurrences of this
+ pattern are full flush points.
+
+ inflateSync returns Z_OK if a possible full flush point has been found,
+ Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
+ has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
+ In the success case, the application may save the current current value of
+ total_in which indicates where valid compressed data was found. In the
+ error case, the application may repeatedly call inflateSync, providing more
+ input each time, until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being Z_NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state. The
+ stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
+ int windowBits));
+/*
+ This function is the same as inflateReset, but it also permits changing
+ the wrap and window size requests. The windowBits parameter is interpreted
+ the same as it is for inflateInit2.
+
+ inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL), or if
+ the windowBits parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ If bits is negative, then the input stream bit buffer is emptied. Then
+ inflatePrime() can be called again to put bits in the buffer. This is used
+ to clear out bits leftover after feeding inflate a block description prior
+ to feeding inflate codes.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+/*
+ This function returns two values, one in the lower 16 bits of the return
+ value, and the other in the remaining upper bits, obtained by shifting the
+ return value down 16 bits. If the upper value is -1 and the lower value is
+ zero, then inflate() is currently decoding information outside of a block.
+ If the upper value is -1 and the lower value is non-zero, then inflate is in
+ the middle of a stored block, with the lower value equaling the number of
+ bytes from the input remaining to copy. If the upper value is not -1, then
+ it is the number of bits back from the current bit position in the input of
+ the code (literal or length/distance pair) currently being processed. In
+ that case the lower value is the number of bytes already emitted for that
+ code.
+
+ A code is being processed if inflate is waiting for more input to complete
+ decoding of the code, or if it has completed decoding but is waiting for
+ more output space to write the literal or match data.
+
+ inflateMark() is used to mark locations in the input data for random
+ access, which may be at bit positions, and to note those cases where the
+ output of a code may span boundaries of random access blocks. The current
+ location in the input stream can be determined from avail_in and data_type
+ as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+ inflateMark returns the value noted above or -1 << 16 if the provided
+ source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be
+ used to force inflate() to return immediately after header processing is
+ complete and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When any
+ of extra, name, or comment are not Z_NULL and the respective field is not
+ present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the parameters are invalid, Z_MEM_ERROR if the internal state could not be
+ allocated, or Z_VERSION_ERROR if the version of the library does not match
+ the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *,
+ z_const unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is potentially more efficient than
+ inflate() for file i/o applications, in that it avoids copying between the
+ output and the sliding window by simply making the window itself the output
+ buffer. inflate() can be faster on modern CPUs when used with large
+ buffers. inflateBack() trusts the application to not change the output
+ buffer passed by the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free the
+ allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects only
+ the raw deflate stream to decompress. This is different from the normal
+ behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format error
+ in the deflate stream (in which case strm->msg is set to indicate the nature
+ of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
+ In the case of Z_BUF_ERROR, an input or output error can be distinguished
+ using strm->next_in which will be Z_NULL only if in() returned an error. If
+ strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
+ non-zero. (in() will always be called before out(), so strm->next_in is
+ assured to be defined if out() returns non-zero.) Note that inflateBack()
+ cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+#ifndef Z_SOLO
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the basic
+ stream-oriented functions. To simplify the interface, some default options
+ are assumed (compression level and memory usage, standard memory allocation
+ functions). The source code of these utility functions can be modified if
+ you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total size
+ of the destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before a
+ compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total size
+ of the destination buffer, which must be large enough to hold the entire
+ uncompressed data. (The size of the uncompressed data must have been saved
+ previously by the compressor and transmitted to the decompressor by some
+ mechanism outside the scope of this compression library.) Upon exit, destLen
+ is the actual size of the uncompressed buffer.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In
+ the case where there is not enough room, uncompress() will fill the output
+ buffer with the uncompressed data up to that point.
+*/
+
+ /* gzip file access functions */
+
+/*
+ This library supports reading and writing files in gzip (.gz) format with
+ an interface similar to that of stdio, using the functions that start with
+ "gz". The gzip format is different from the zlib format. gzip is a gzip
+ wrapper, documented in RFC 1952, wrapped around a deflate stream.
+*/
+
+typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */
+
+/*
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+
+ Opens a gzip (.gz) file for reading or writing. The mode parameter is as
+ in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
+ a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
+ compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
+ for fixed code compression as in "wb9F". (See the description of
+ deflateInit2 for more information about the strategy parameter.) 'T' will
+ request transparent writing or appending with no compression and not using
+ the gzip format.
+
+ "a" can be used instead of "w" to request that the gzip stream that will
+ be written be appended to the file. "+" will result in an error, since
+ reading and writing to the same gzip file is not supported. The addition of
+ "x" when writing will create the file exclusively, which fails if the file
+ already exists. On systems that support it, the addition of "e" when
+ reading or writing will set the flag to close the file on an execve() call.
+
+ These functions, as well as gzip, will read and decode a sequence of gzip
+ streams in a file. The append function of gzopen() can be used to create
+ such a file. (Also see gzflush() for another way to do this.) When
+ appending, gzopen does not test whether the file begins with a gzip stream,
+ nor does it look for the end of the gzip streams to begin appending. gzopen
+ will simply append a gzip stream to the existing file.
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression. When
+ reading, this will be detected automatically by looking for the magic two-
+ byte gzip header.
+
+ gzopen returns NULL if the file could not be opened, if there was
+ insufficient memory to allocate the gzFile state, or if an invalid mode was
+ specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
+ errno can be checked to determine if the reason gzopen failed was that the
+ file could not be opened.
+*/
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen associates a gzFile with the file descriptor fd. File descriptors
+ are obtained from calls like open, dup, creat, pipe or fileno (if the file
+ has been previously opened with fopen). The mode parameter is as in gzopen.
+
+ The next call of gzclose on the returned gzFile will also close the file
+ descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
+ fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
+ mode);. The duplicated descriptor should be saved to avoid a leak, since
+ gzdopen does not close fd if it fails. If you are using fileno() to get the
+ file descriptor from a FILE *, then you will have to use dup() to avoid
+ double-close()ing the file descriptor. Both gzclose() and fclose() will
+ close the associated file descriptor, so they need to have different file
+ descriptors.
+
+ gzdopen returns NULL if there was insufficient memory to allocate the
+ gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
+ provided, or '+' was provided), or if fd is -1. The file descriptor is not
+ used until the next gz* read, write, seek, or close operation, so gzdopen
+ will not detect if fd is invalid (unless fd is -1).
+*/
+
+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+/*
+ Set the internal buffer size used by this library's functions. The
+ default buffer size is 8192 bytes. This function must be called after
+ gzopen() or gzdopen(), and before any other calls that read or write the
+ file. The buffer memory allocation is always deferred to the first read or
+ write. Two buffers are allocated, either both of the specified size when
+ writing, or one of the specified size and the other twice that size when
+ reading. A larger buffer size of, for example, 64K or 128K bytes will
+ noticeably increase the speed of decompression (reading).
+
+ The new buffer size also affects the maximum length for gzprintf().
+
+ gzbuffer() returns 0 on success, or -1 on failure, such as being called
+ too late.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file. If
+ the input file is not in gzip format, gzread copies the given number of
+ bytes into the buffer directly from the file.
+
+ After reaching the end of a gzip stream in the input, gzread will continue
+ to read, looking for another gzip stream. Any number of gzip streams may be
+ concatenated in the input file, and will all be decompressed by gzread().
+ If something other than a gzip stream is encountered after a gzip stream,
+ that remaining trailing garbage is ignored (and no error is returned).
+
+ gzread can be used to read a gzip file that is being concurrently written.
+ Upon reaching the end of the input, gzread will return with the available
+ data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then
+ gzclearerr can be used to clear the end of file indicator in order to permit
+ gzread to be tried again. Z_OK indicates that a gzip stream was completed
+ on the last gzread. Z_BUF_ERROR indicates that the input file ended in the
+ middle of a gzip stream. Note that gzread does not return -1 in the event
+ of an incomplete gzip stream. This error is deferred until gzclose(), which
+ will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip
+ stream. Alternatively, gzerror can be used before gzclose to detect this
+ case.
+
+ gzread returns the number of uncompressed bytes actually read, less than
+ len for end of file, or -1 for error.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes written or 0 in case of
+ error.
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the arguments to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written, or 0 in case of error. The number of
+ uncompressed bytes written is limited to 8191, or one less than the buffer
+ size given to gzbuffer(). The caller should assure that this limit is not
+ exceeded. If it is exceeded, then gzprintf() will return an error (0) with
+ nothing written. In this case, there may also be a buffer overflow with
+ unpredictable consequences, which is possible only if zlib was compiled with
+ the insecure functions sprintf() or vsprintf() because the secure snprintf()
+ or vsnprintf() functions were not available. This can be determined using
+ zlibCompileFlags().
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or a
+ newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. If any characters are read or if len == 1, the
+ string is terminated with a null character. If no characters are read due
+ to an end-of-file or len < 1, then the buffer is left untouched.
+
+ gzgets returns buf which is a null-terminated string, or it returns NULL
+ for end-of-file or in case of error. If there was an error, the contents at
+ buf are indeterminate.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file. gzputc
+ returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte or -1
+ in case of end of file or error. This is implemented as a macro for speed.
+ As such, it does not do all of the checking the other functions do. I.e.
+ it does not check to see if file is NULL, nor whether the structure file
+ points to has been clobbered or not.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read as the first character
+ on the next read. At least one character of push-back is allowed.
+ gzungetc() returns the character pushed, or -1 on failure. gzungetc() will
+ fail if c is -1, and may fail if a character has been pushed but not read
+ yet. If gzungetc is used immediately after gzopen or gzdopen, at least the
+ output buffer size of pushed characters is allowed. (See gzbuffer above.)
+ The pushed character will be discarded if the stream is repositioned with
+ gzseek() or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter flush
+ is as in the deflate() function. The return value is the zlib error number
+ (see function gzerror below). gzflush is only permitted when writing.
+
+ If the flush parameter is Z_FINISH, the remaining data is written and the
+ gzip stream is completed in the output. If gzwrite() is called again, a new
+ gzip stream will be started in the output. gzread() is able to read such
+ concatented gzip streams.
+
+ gzflush should be called only when strictly necessary because it will
+ degrade compression if called too often.
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+
+ Returns the starting position for the next gzread or gzwrite on the given
+ compressed file. This position represents a number of bytes in the
+ uncompressed data stream, and is zero when starting, even if appending or
+ reading a gzip stream from the middle of a file using gzdopen().
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+
+ Returns the current offset in the file being read or written. This offset
+ includes the count of bytes that precede the gzip stream, for example when
+ appending or when using gzdopen() for reading. When reading, the offset
+ does not include as yet unused buffered input. This information can be used
+ for a progress indicator. On error, gzoffset() returns -1.
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns true (1) if the end-of-file indicator has been set while reading,
+ false (0) otherwise. Note that the end-of-file indicator is set only if the
+ read tried to go past the end of the input, but came up short. Therefore,
+ just like feof(), gzeof() may return false even if there is no more data to
+ read, in the event that the last read request was for the exact number of
+ bytes remaining in the input file. This will happen if the input file size
+ is an exact multiple of the buffer size.
+
+ If gzeof() returns true, then the read functions will return no more data,
+ unless the end-of-file indicator is reset by gzclearerr() and the input file
+ has grown since the previous end of file was detected.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns true (1) if file is being copied directly while reading, or false
+ (0) if file is a gzip stream being decompressed.
+
+ If the input file is empty, gzdirect() will return true, since the input
+ does not contain a gzip stream.
+
+ If gzdirect() is used immediately after gzopen() or gzdopen() it will
+ cause buffers to be allocated to allow reading the file to determine if it
+ is a gzip file. Therefore if gzbuffer() is used, it should be called before
+ gzdirect().
+
+ When writing, gzdirect() returns true (1) if transparent writing was
+ requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note:
+ gzdirect() is not needed when writing. Transparent writing must be
+ explicitly requested, so the application already knows the answer. When
+ linking statically, using gzdirect() will include all of the zlib code for
+ gzip file reading and decompression, which may not be desired.)
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file and
+ deallocates the (de)compression state. Note that once file is closed, you
+ cannot call gzerror with file, since its structures have been deallocated.
+ gzclose must not be called more than once on the same file, just as free
+ must not be called more than once on the same allocation.
+
+ gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
+ file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
+ last read ended in the middle of a gzip stream, or Z_OK on success.
+*/
+
+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+/*
+ Same as gzclose(), but gzclose_r() is only for use when reading, and
+ gzclose_w() is only for use when writing or appending. The advantage to
+ using these instead of gzclose() is that they avoid linking in zlib
+ compression or decompression code that is not used when only reading or only
+ writing respectively. If gzclose() is used, then both compression and
+ decompression code will be included the application when linking to a static
+ zlib library.
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the given
+ compressed file. errnum is set to zlib error number. If an error occurred
+ in the file system and not in the compression library, errnum is set to
+ Z_ERRNO and the application may consult errno to get the exact error code.
+
+ The application must not modify the returned string. Future calls to
+ this function may invalidate the previously returned string. If file is
+ closed, then the string previously returned by gzerror will no longer be
+ available.
+
+ gzerror() should be used to distinguish errors from end-of-file for those
+ functions above that do not distinguish those cases in their return values.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+#endif /* !Z_SOLO */
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the compression
+ library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is Z_NULL, this function returns the
+ required initial value for the checksum.
+
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster.
+
+ Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note
+ that the z_off_t type (like off_t) is a signed integer. If len2 is
+ negative, the result has no meaning or utility.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is Z_NULL, this function returns the required
+ initial value for the crc. Pre- and post-conditioning (one's complement) is
+ performed within this function so it shouldn't be done by the application.
+
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
+ (int)sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, (int)sizeof(z_stream))
+
+#ifndef Z_SOLO
+
+/* gzgetc() macro and its supporting function and exposed data structure. Note
+ * that the real internal state is much larger than the exposed structure.
+ * This abbreviated structure exposes just enough for the gzgetc() macro. The
+ * user should not mess with these exposed elements, since their names or
+ * behavior could change in the future, perhaps even capriciously. They can
+ * only be used by the gzgetc() macro. You have been warned.
+ */
+struct gzFile_s {
+ unsigned have;
+ unsigned char *next;
+ z_off64_t pos;
+};
+ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */
+#ifdef Z_PREFIX_SET
+# undef z_gzgetc
+# define z_gzgetc(g) \
+ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#else
+# define gzgetc(g) \
+ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#endif
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#ifdef Z_LARGE64
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+ ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
+#endif
+
+#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
+# ifdef Z_PREFIX_SET
+# define z_gzopen z_gzopen64
+# define z_gzseek z_gzseek64
+# define z_gztell z_gztell64
+# define z_gzoffset z_gzoffset64
+# define z_adler32_combine z_adler32_combine64
+# define z_crc32_combine z_crc32_combine64
+# else
+# define gzopen gzopen64
+# define gzseek gzseek64
+# define gztell gztell64
+# define gzoffset gzoffset64
+# define adler32_combine adler32_combine64
+# define crc32_combine crc32_combine64
+# endif
+# ifndef Z_LARGE64
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+# endif
+#else
+ ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+#endif
+
+#else /* Z_SOLO */
+
+ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+
+#endif /* !Z_SOLO */
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));
+ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void));
+ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));
+ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp));
+ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp));
+#if defined(_WIN32) && !defined(Z_SOLO)
+ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path,
+ const char *mode));
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# ifndef Z_SOLO
+ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file,
+ const char *format,
+ va_list va));
+# endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/zutil.c b/source/blender/python/manta_full/dependencies/zlib-1.2.8/zutil.c
new file mode 100644
index 00000000000..23d2ebef008
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/zutil.c
@@ -0,0 +1,324 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+#ifndef Z_SOLO
+# include "gzguts.h"
+#endif
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+z_const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch ((int)(sizeof(uInt))) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch ((int)(sizeof(uLong))) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch ((int)(sizeof(voidpf))) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch ((int)(sizeof(z_off_t))) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1L << 20;
+#endif
+#ifdef FASTEST
+ flags += 1L << 21;
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# ifdef NO_vsnprintf
+ flags += 1L << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#else
+ flags += 1L << 24;
+# ifdef NO_snprintf
+ flags += 1L << 25;
+# ifdef HAS_sprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int ZLIB_INTERNAL z_verbose = verbose;
+
+void ZLIB_INTERNAL z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used.
+ */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void ZLIB_INTERNAL zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int ZLIB_INTERNAL zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void ZLIB_INTERNAL zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+#ifndef Z_SOLO
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void ZLIB_INTERNAL zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
+
+#endif /* !Z_SOLO */
diff --git a/source/blender/python/manta_full/dependencies/zlib-1.2.8/zutil.h b/source/blender/python/manta_full/dependencies/zlib-1.2.8/zutil.h
new file mode 100644
index 00000000000..24ab06b1cf6
--- /dev/null
+++ b/source/blender/python/manta_full/dependencies/zlib-1.2.8/zutil.h
@@ -0,0 +1,253 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#ifdef HAVE_HIDDEN
+# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+#else
+# define ZLIB_INTERNAL
+#endif
+
+#include "zlib.h"
+
+#if defined(STDC) && !defined(Z_SOLO)
+# if !(defined(_WIN32_WCE) && defined(_MSC_VER))
+# include <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#ifdef Z_SOLO
+ typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+# define OS_CODE 0x00
+# ifndef Z_SOLO
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+# endif
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+# if defined(M_I86) && !defined(Z_SOLO)
+# include <malloc.h>
+# endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# ifndef Z_SOLO
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+# endif
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifdef WIN32
+# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
+# define OS_CODE 0x0b
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
+# if defined(_WIN32_WCE)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# ifndef _PTRDIFF_T_DEFINED
+ typedef int ptrdiff_t;
+# define _PTRDIFF_T_DEFINED
+# endif
+# else
+# define fdopen(fd,type) _fdopen(fd,type)
+# endif
+#endif
+
+#if defined(__BORLANDC__) && !defined(MSDOS)
+ #pragma warn -8004
+ #pragma warn -8008
+ #pragma warn -8066
+#endif
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_WIN32) && \
+ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#endif
+
+ /* common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#if defined(pyr) || defined(Z_SOLO)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int ZLIB_INTERNAL z_verbose;
+ extern void ZLIB_INTERNAL z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+#ifndef Z_SOLO
+ voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
+ unsigned size));
+ void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
+#endif
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+/* Reverse the bytes in a 32-bit value */
+#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+#endif /* ZUTIL_H */
diff --git a/source/blender/python/manta_full/resources/pause.png b/source/blender/python/manta_full/resources/pause.png
new file mode 100644
index 00000000000..53e0a0c4ca0
--- /dev/null
+++ b/source/blender/python/manta_full/resources/pause.png
Binary files differ
diff --git a/source/blender/python/manta_full/resources/play.png b/source/blender/python/manta_full/resources/play.png
new file mode 100644
index 00000000000..1383312473b
--- /dev/null
+++ b/source/blender/python/manta_full/resources/play.png
Binary files differ
diff --git a/source/blender/python/manta_full/resources/res.qrc b/source/blender/python/manta_full/resources/res.qrc
new file mode 100644
index 00000000000..e39ebc0d6e2
--- /dev/null
+++ b/source/blender/python/manta_full/resources/res.qrc
@@ -0,0 +1,7 @@
+ <!DOCTYPE RCC><RCC version="1.0">
+ <qresource>
+ <file>pause.png</file>
+ <file>stop.png</file>
+ <file>play.png</file>
+ </qresource>
+ </RCC> \ No newline at end of file
diff --git a/source/blender/python/manta_full/resources/stop.png b/source/blender/python/manta_full/resources/stop.png
new file mode 100644
index 00000000000..efab55e1b91
--- /dev/null
+++ b/source/blender/python/manta_full/resources/stop.png
Binary files differ
diff --git a/source/blender/python/manta_full/scenes/simpleplume.py b/source/blender/python/manta_full/scenes/simpleplume.py
new file mode 100644
index 00000000000..459af24c074
--- /dev/null
+++ b/source/blender/python/manta_full/scenes/simpleplume.py
@@ -0,0 +1,61 @@
+#
+# Simple example scene (hello world)
+# Simulation of a buoyant smoke density plume
+
+#import pdb; pdb.set_trace()
+
+from manta import *
+
+# solver params
+res = 64
+gs = vec3(res,1.5*res,res)
+s = FluidSolver(name='main', gridSize = gs)
+s.timestep = 1.0
+
+# prepare grids
+flags = s.create(FlagGrid)
+vel = s.create(MACGrid)
+density = s.create(RealGrid)
+pressure = s.create(RealGrid)
+
+# noise field
+noise = s.create(NoiseField, loadFromFile=True)
+noise.posScale = vec3(45)
+noise.clamp = True
+noise.clampNeg = 0
+noise.clampPos = 1
+noise.valScale = 1
+noise.valOffset = 0.75
+noise.timeAnim = 0.2
+
+flags.initDomain()
+flags.fillGrid()
+
+if (GUI):
+ gui = Gui()
+ gui.show()
+
+source = s.create(Cylinder, center=gs*vec3(0.5,0.1,0.5), radius=res*0.14, z=gs*vec3(0, 0.02, 0))
+
+#main loop
+for t in range(250):
+ if t<100:
+ densityInflow(flags=flags, density=density, noise=noise, shape=source, scale=1, sigma=0.5)
+
+ # optionally, enforce inflow velocity
+ #source.applyToGrid(grid=vel, value=velInflow)
+
+ advectSemiLagrange(flags=flags, vel=vel, grid=density, order=2)
+ advectSemiLagrange(flags=flags, vel=vel, grid=vel , order=2, strength=1.0)
+
+ setWallBcs(flags=flags, vel=vel)
+ addBuoyancy(density=density, vel=vel, gravity=vec3(0,-6e-4,0), flags=flags)
+
+ solvePressure(flags=flags, vel=vel, pressure=pressure, useResNorm=True)
+ setWallBcs(flags=flags, vel=vel)
+ #density.save('den%04d.uni' % t)
+
+ s.printTimings()
+ s.step()
+
+
diff --git a/source/blender/python/manta_full/source/cmake/FindTBB.cmake b/source/blender/python/manta_full/source/cmake/FindTBB.cmake
new file mode 100644
index 00000000000..f8bb2cebca5
--- /dev/null
+++ b/source/blender/python/manta_full/source/cmake/FindTBB.cmake
@@ -0,0 +1,267 @@
+# Locate Intel Threading Building Blocks include paths and libraries
+# FindTBB.cmake can be found at https://code.google.com/p/findtbb/
+# Written by Hannes Hofmann <hannes.hofmann _at_ informatik.uni-erlangen.de>
+# Improvements by Gino van den Bergen <gino _at_ dtecta.com>,
+# Florian Uhlig <F.Uhlig _at_ gsi.de>,
+# Jiri Marsik <jiri.marsik89 _at_ gmail.com>
+# Tobias Pfaff <tpfaff _at_ inf.ethz.ch>
+
+
+# The MIT License
+#
+# Copyright (c) 2011 Hannes Hofmann
+#
+# 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.
+
+# GvdB: This module uses the environment variable TBB_ARCH_PLATFORM which defines architecture and compiler.
+# e.g. "ia32/vc8" or "em64t/cc4.1.0_libc2.4_kernel2.6.16.21"
+# TBB_ARCH_PLATFORM is set by the build script tbbvars[.bat|.sh|.csh], which can be found
+# in the TBB installation directory (TBB_INSTALL_DIR).
+#
+# GvdB: Mac OS X distribution places libraries directly in lib directory.
+#
+# For backwards compatibility, you may explicitely set the CMake variables TBB_ARCHITECTURE and TBB_COMPILER.
+# TBB_ARCHITECTURE [ ia32 | em64t | itanium ]
+# which architecture to use
+# TBB_COMPILER e.g. vc9 or cc3.2.3_libc2.3.2_kernel2.4.21 or cc4.0.1_os10.4.9
+# which compiler to use (detected automatically on Windows)
+
+# This module respects
+# TBB_INSTALL_DIR or $ENV{TBB21_INSTALL_DIR} or $ENV{TBB_INSTALL_DIR}
+
+# This module defines
+# TBB_INCLUDE_DIRS, where to find task_scheduler_init.h, etc.
+# TBB_LIBRARY_DIRS, where to find libtbb, libtbbmalloc
+# TBB_DEBUG_LIBRARY_DIRS, where to find libtbb_debug, libtbbmalloc_debug
+# TBB_INSTALL_DIR, the base TBB install directory
+# TBB_LIBRARIES, the libraries to link against to use TBB.
+# TBB_DEBUG_LIBRARIES, the libraries to link against to use TBB with debug symbols.
+# TBB_FOUND, If false, don't try to use TBB.
+# TBB_INTERFACE_VERSION, as defined in tbb/tbb_stddef.h
+
+
+if (WIN32)
+ # has em64t/vc8 em64t/vc9
+ # has ia32/vc7.1 ia32/vc8 ia32/vc9
+ set(_TBB_DEFAULT_INSTALL_DIR "C:/Program Files/Intel/TBB")
+ set(_TBB_LIB_NAME "tbb")
+ set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+ set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+ set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+ if (MSVC71)
+ set (_TBB_COMPILER "vc7.1")
+ endif(MSVC71)
+ if (MSVC80)
+ set(_TBB_COMPILER "vc8")
+ endif(MSVC80)
+ if (MSVC90)
+ set(_TBB_COMPILER "vc9")
+ endif(MSVC90)
+ if(MSVC10)
+ set(_TBB_COMPILER "vc10")
+ endif(MSVC10)
+ # Todo: add other Windows compilers such as ICL.
+ if (NOT TBB_ARCHITECTURE)
+ set(TBB_ARCHITECTURE "ia32")
+ endif()
+ set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+endif (WIN32)
+
+if (UNIX)
+ if (APPLE)
+ # MAC
+ set(_TBB_DEFAULT_INSTALL_DIR "/Library/Frameworks/Intel_TBB.framework/Versions")
+ # libs: libtbb.dylib, libtbbmalloc.dylib, *_debug
+ set(_TBB_LIB_NAME "tbb")
+ set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+ set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+ set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+ # default flavor on apple: ia32/cc4.0.1_os10.4.9
+ # Jiri: There is no reason to presume there is only one flavor and
+ # that user's setting of variables should be ignored.
+ if(NOT TBB_COMPILER)
+ set(_TBB_COMPILER "cc4.0.1_os10.4.9")
+ elseif (NOT TBB_COMPILER)
+ set(_TBB_COMPILER ${TBB_COMPILER})
+ endif(NOT TBB_COMPILER)
+ if(NOT TBB_ARCHITECTURE)
+ set(_TBB_ARCHITECTURE "ia32")
+ elseif(NOT TBB_ARCHITECTURE)
+ set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+ endif(NOT TBB_ARCHITECTURE)
+ else (APPLE)
+ # LINUX
+ set(_TBB_DEFAULT_INSTALL_DIR "/opt/intel/tbb" "/usr/local/include" "/usr/include")
+ set(_TBB_LIB_NAME "tbb")
+ set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc")
+ set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug")
+ set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug")
+ # has em64t/cc3.2.3_libc2.3.2_kernel2.4.21 em64t/cc3.3.3_libc2.3.3_kernel2.6.5 em64t/cc3.4.3_libc2.3.4_kernel2.6.9 em64t/cc4.1.0_libc2.4_kernel2.6.16.21
+ # has ia32/*
+ # has itanium/*
+ set(_TBB_COMPILER ${TBB_COMPILER})
+ set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE})
+ endif (APPLE)
+endif (UNIX)
+
+if (CMAKE_SYSTEM MATCHES "SunOS.*")
+# SUN
+# not yet supported
+# has em64t/cc3.4.3_kernel5.10
+# has ia32/*
+endif (CMAKE_SYSTEM MATCHES "SunOS.*")
+
+
+#-- Clear the public variables
+set (TBB_FOUND "NO")
+
+
+#-- Find TBB install dir and set ${_TBB_INSTALL_DIR} and cached ${TBB_INSTALL_DIR}
+# first: use CMake variable TBB_INSTALL_DIR
+if (TBB_INSTALL_DIR)
+ set (_TBB_INSTALL_DIR ${TBB_INSTALL_DIR})
+endif (TBB_INSTALL_DIR)
+# second: use environment variable
+if (NOT _TBB_INSTALL_DIR)
+ if (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB_INSTALL_DIR})
+ endif (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "")
+ # Intel recommends setting TBB21_INSTALL_DIR
+ if (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB21_INSTALL_DIR})
+ endif (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "")
+ if (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB22_INSTALL_DIR})
+ endif (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "")
+ if (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "")
+ set (_TBB_INSTALL_DIR $ENV{TBB30_INSTALL_DIR})
+ endif (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "")
+endif (NOT _TBB_INSTALL_DIR)
+# third: try to find path automatically
+if (NOT _TBB_INSTALL_DIR)
+ if (_TBB_DEFAULT_INSTALL_DIR)
+ set (_TBB_INSTALL_DIR ${_TBB_DEFAULT_INSTALL_DIR})
+ endif (_TBB_DEFAULT_INSTALL_DIR)
+endif (NOT _TBB_INSTALL_DIR)
+# sanity check
+if (NOT _TBB_INSTALL_DIR)
+ message ("ERROR: Unable to find Intel TBB install directory. ${_TBB_INSTALL_DIR}")
+else (NOT _TBB_INSTALL_DIR)
+# finally: set the cached CMake variable TBB_INSTALL_DIR
+if (NOT TBB_INSTALL_DIR)
+ set (TBB_INSTALL_DIR ${_TBB_INSTALL_DIR} CACHE PATH "Intel TBB install directory")
+ mark_as_advanced(TBB_INSTALL_DIR)
+endif (NOT TBB_INSTALL_DIR)
+
+#-- A macro to rewrite the paths of the library. This is necessary, because
+# find_library() always found the em64t/vc9 version of the TBB libs
+macro(TBB_CORRECT_LIB_DIR var_name)
+# if (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t")
+ string(REPLACE em64t "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}})
+# endif (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t")
+ string(REPLACE ia32 "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}})
+ string(REPLACE vc7.1 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+ string(REPLACE vc8 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+ string(REPLACE vc9 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+ string(REPLACE vc10 "${_TBB_COMPILER}" ${var_name} ${${var_name}})
+endmacro(TBB_CORRECT_LIB_DIR var_content)
+
+
+#-- Look for include directory and set ${TBB_INCLUDE_DIR}
+set (TBB_INC_SEARCH_DIR ${_TBB_INSTALL_DIR}/include)
+# Jiri: tbbvars now sets the CPATH environment variable to the directory
+# containing the headers.
+find_path(TBB_INCLUDE_DIR
+ tbb/task_scheduler_init.h
+ PATHS ${TBB_INC_SEARCH_DIR} ENV CPATH
+)
+mark_as_advanced(TBB_INCLUDE_DIR)
+
+set (_TBB_LIBRARY_DIR "${_TBB_INSTALL_DIR}/lib/${_TBB_ARCHITECTURE}/${_TBB_COMPILER}" ${_TBB_LIBRARY_DIR})
+
+# GvdB: Mac OS X distribution places libraries directly in lib directory.
+list(APPEND _TBB_LIBRARY_DIR ${_TBB_INSTALL_DIR}/lib)
+
+# Jiri: No reason not to check the default paths. From recent versions,
+# tbbvars has started exporting the LIBRARY_PATH and LD_LIBRARY_PATH
+# variables, which now point to the directories of the lib files.
+# It all makes more sense to use the ${_TBB_LIBRARY_DIR} as a HINTS
+# argument instead of the implicit PATHS as it isn't hard-coded
+# but computed by system introspection. Searching the LIBRARY_PATH
+# and LD_LIBRARY_PATH environment variables is now even more important
+# that tbbvars doesn't export TBB_ARCH_PLATFORM and it facilitates
+# the use of TBB built from sources.
+find_library(TBB_LIBRARY ${_TBB_LIB_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+find_library(TBB_MALLOC_LIBRARY ${_TBB_LIB_MALLOC_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+
+#Extract path from TBB_LIBRARY name
+get_filename_component(TBB_LIBRARY_DIR ${TBB_LIBRARY} PATH)
+
+#TBB_CORRECT_LIB_DIR(TBB_LIBRARY)
+#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY)
+mark_as_advanced(TBB_LIBRARY TBB_MALLOC_LIBRARY)
+
+#-- Look for debug libraries
+# Jiri: Changed the same way as for the release libraries.
+find_library(TBB_LIBRARY_DEBUG ${_TBB_LIB_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+find_library(TBB_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_MALLOC_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR}
+ PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH)
+
+# Jiri: Self-built TBB stores the debug libraries in a separate directory.
+# Extract path from TBB_LIBRARY_DEBUG name
+get_filename_component(TBB_LIBRARY_DEBUG_DIR ${TBB_LIBRARY_DEBUG} PATH)
+
+#TBB_CORRECT_LIB_DIR(TBB_LIBRARY_DEBUG)
+#TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY_DEBUG)
+mark_as_advanced(TBB_LIBRARY_DEBUG TBB_MALLOC_LIBRARY_DEBUG)
+
+if (TBB_INCLUDE_DIR)
+ if (TBB_LIBRARY)
+ set (TBB_FOUND "YES")
+ set (TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY} ${TBB_LIBRARIES})
+ set (TBB_DEBUG_LIBRARIES ${TBB_LIBRARY_DEBUG} ${TBB_MALLOC_LIBRARY_DEBUG} ${TBB_DEBUG_LIBRARIES})
+ set (TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR} CACHE PATH "TBB include directory" FORCE)
+ set (TBB_LIBRARY_DIRS ${TBB_LIBRARY_DIR} CACHE PATH "TBB library directory" FORCE)
+ # Jiri: Self-built TBB stores the debug libraries in a separate directory.
+ set (TBB_DEBUG_LIBRARY_DIRS ${TBB_LIBRARY_DEBUG_DIR} CACHE PATH "TBB debug library directory" FORCE)
+ mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARY_DIRS TBB_DEBUG_LIBRARY_DIRS TBB_LIBRARIES TBB_DEBUG_LIBRARIES)
+ message(STATUS "Found Intel TBB")
+ endif (TBB_LIBRARY)
+endif (TBB_INCLUDE_DIR)
+
+if (NOT TBB_FOUND)
+ message("ERROR: Intel TBB NOT found!")
+ message(STATUS "Looked for Threading Building Blocks in ${_TBB_INSTALL_DIR}")
+ # do only throw fatal, if this pkg is REQUIRED
+ if (TBB_FIND_REQUIRED)
+ message(FATAL_ERROR "Could NOT find TBB library.")
+ endif (TBB_FIND_REQUIRED)
+endif (NOT TBB_FOUND)
+
+endif (NOT _TBB_INSTALL_DIR)
+
+if (TBB_FOUND)
+ set(TBB_INTERFACE_VERSION 0)
+ FILE(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _TBB_VERSION_CONTENTS)
+ STRING(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_TBB_VERSION_CONTENTS}")
+ set(TBB_INTERFACE_VERSION "${TBB_INTERFACE_VERSION}")
+endif (TBB_FOUND)
diff --git a/source/blender/python/manta_full/source/commonkernels.h b/source/blender/python/manta_full/source/commonkernels.h
new file mode 100644
index 00000000000..d2cfea768a2
--- /dev/null
+++ b/source/blender/python/manta_full/source/commonkernels.h
@@ -0,0 +1,128 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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
+KERNEL(idx)
+void InvertCheckFluid (FlagGrid& flags, Grid<Real>& grid)
+{
+ if (flags.isFluid(idx) && grid[idx] > 0)
+ grid[idx] = 1.0 / grid[idx];
+}
+
+//! Kernel: Squared sum over grid
+KERNEL(idx, reduce=+) returns(double sum=0)
+double GridSumSqr (Grid<Real>& grid) {
+ sum += square((double)grid[idx]);
+}
+
+//! Kernel: rotation operator \nabla x v for centered vector fields
+KERNEL(bnd=1)
+void CurlOp (const Grid<Vec3>& grid, Grid<Vec3>& dst) {
+ 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;
+};
+
+//! Kernel: divergence operator (from MAC grid)
+KERNEL(bnd=1)
+void DivergenceOpMAC(Grid<Real>& div, const MACGrid& grid) {
+ 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;
+}
+
+//! Kernel: gradient operator for MAC grid
+KERNEL(bnd=1)void GradientOpMAC(MACGrid& gradient, const Grid<Real>& grid) {
+ 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;
+}
+
+//! Kernel: centered gradient operator
+KERNEL(bnd=1) void GradientOp(Grid<Vec3>& gradient, const Grid<Real>& grid) {
+ 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;
+}
+
+//! Kernel: Laplace operator
+KERNEL (bnd=1) void LaplaceOp(Grid<Real>& laplace, const Grid<Real>& grid) {
+ laplace(i,j,k) = -(6.0*grid(i,j,k)-grid(i+1,j,k)-grid(i-1,j,k)-grid(i,j+1,k)-grid(i,j-1,k)-grid(i,j,k+1)-grid(i,j,k-1));
+}
+
+//! Kernel: get component at MAC positions
+KERNEL(bnd=1) void GetShiftedComponent(const Grid<Vec3>& grid, Grid<Real>& comp, int dim) {
+ Vec3i ishift(i,j,k);
+ ishift[dim]--;
+ comp(i,j,k) = 0.5*(grid(i,j,k)[dim] + grid(ishift)[dim]);
+};
+
+//! Kernel: get component (not shifted)
+KERNEL(idx) void GetComponent(const Grid<Vec3>& grid, Grid<Real>& comp, int dim) {
+ comp[idx] = grid[idx][dim];
+};
+
+//! Kernel: get norm of centered grid
+KERNEL(idx) void GridNorm(Grid<Real>& n, const Grid<Vec3>& grid) {
+ n[idx] = norm(grid[idx]);
+};
+
+//! Kernel: set component (not shifted)
+KERNEL(idx) void SetComponent(Grid<Vec3>& grid, const Grid<Real>& comp, int dim) {
+ grid[idx][dim] = comp[idx];
+};
+
+//! Kernel: compute centered velocity field from MAC
+KERNEL(bnd=1) void GetCentered(Grid<Vec3>& center, const MACGrid& vel) {
+ 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;
+};
+
+//! Kernel: compute MAC from centered velocity field
+KERNEL(bnd=1) void GetMAC(MACGrid& vel, const Grid<Vec3>& center) {
+ 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;
+};
+
+//! Fill in the domain boundary cells (i,j,k=0/size-1) from the neighboring cells
+KERNEL void FillInBoundary(Grid<Vec3>& grid, int g) {
+ 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);
+}
+
+} // namespace
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/conjugategrad.cpp b/source/blender/python/manta_full/source/conjugategrad.cpp
new file mode 100644
index 00000000000..ee432b47259
--- /dev/null
+++ b/source/blender/python/manta_full/source/conjugategrad.cpp
@@ -0,0 +1,303 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Conjugate gradient solver
+ *
+ ******************************************************************************/
+
+#include "conjugategrad.h"
+#include "commonkernels.h"
+
+using namespace std;
+namespace Manta {
+
+const int CG_DEBUGLEVEL = 4;
+
+//*****************************************************************************
+// Precondition helpers
+
+//! Preconditioning a la Wavelet Turbulence (needs 4 add. grids)
+void InitPreconditionIncompCholesky(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 = orgA0;
+ Ai = orgAi;
+ Aj = orgAj;
+ Ak = orgAk;
+
+ FOR_IJK(A0) {
+ if (flags.isFluid(i,j,k)) {
+ const int 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(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 );
+ }
+};
+
+//! Apply WT-style ICP
+void ApplyPreconditionIncompCholesky(Grid<Real>& dst, Grid<Real>& Var1, 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 int 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, 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 int 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);
+ }
+}
+
+
+//*****************************************************************************
+// Kernels
+
+//! Kernel: Compute the dot product between two Real grids
+/*! Uses double precision internally */
+KERNEL(idx, reduce=+) returns(double result=0.0)
+double GridDotProduct (const Grid<Real>& a, const Grid<Real>& b) {
+ result += (a[idx] * b[idx]);
+};
+
+//! Kernel: compute residual (init) and add to sigma
+KERNEL(idx, reduce=+) returns(double sigma=0)
+double InitSigma (FlagGrid& flags, Grid<Real>& dst, Grid<Real>& rhs, Grid<Real>& temp)
+{
+ const double res = rhs[idx] - temp[idx];
+ dst[idx] = (Real)res;
+
+ // only compute residual in fluid region
+ if(flags.isFluid(idx))
+ sigma += res*res;
+};
+
+//! Kernel: update search vector
+KERNEL(idx) void UpdateSearchVec (Grid<Real>& dst, Grid<Real>& src, Real factor)
+{
+ dst[idx] = src[idx] + factor * dst[idx];
+}
+
+//*****************************************************************************
+// CG class
+
+template<class APPLYMAT>
+GridCg<APPLYMAT>::GridCg(Grid<Real>& dst, Grid<Real>& rhs, Grid<Real>& residual, Grid<Real>& search, 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(pA0), mpPCAi(pAi), mpPCAj(pAj), mpPCAk(pAk), mSigma(0.), mAccuracy(VECTOR_EPSILON), mResNorm(1e20)
+{
+ dst.clear();
+ residual.clear();
+ search.clear();
+ tmp.clear();
+}
+
+template<class APPLYMAT>
+void GridCg<APPLYMAT>::doInit() {
+ mInited = true;
+
+ mResidual = 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 {
+ mTmp = mResidual;
+ }
+
+ mSearch = 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
+ mTmp = mResidual;
+
+ // compute norm of the residual?
+ if(this->mUseResNorm) {
+ mResNorm = GridSumSqr(mResidual).sum;
+ } else {
+ mResNorm = mResidual.getMaxAbsValue();
+ }
+ //if(mIterations % 10 == 9) debMsg("GridCg::Iteration i="<<mIterations<<", resNorm="<<mResNorm<<" accuracy="<<mAccuracy, 1);
+
+ // 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("PB-Cg::iter i="<<mIterations<<" sigmaNew="<<sigmaNew<<" sigmaLast="<<mSigma<<" alpha="<<alpha<<" beta="<<beta<<" ", CG_DEBUGLEVEL);
+ mSigma = sigmaNew;
+
+ //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>::setPreconditioner(PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak) {
+ mPcMethod = method;
+ if( (!A0->is3D()) && (mPcMethod!=PC_None) ) {
+ if(gPrint2dWarning) {
+ debMsg("Pre-conditioning only supported in 3D for now, disabling it.", 1);
+ gPrint2dWarning = false;
+ }
+ mPcMethod=PC_None;
+ }
+ mpPCA0 = A0;
+ mpPCAi = Ai;
+ mpPCAj = Aj;
+ mpPCAk = Ak;
+}
+
+// explicit instantiation
+template class GridCg<ApplyMatrix>;
+template class GridCg<ApplyMatrix2D>;
+
+}; // DDF
diff --git a/source/blender/python/manta_full/source/conjugategrad.h b/source/blender/python/manta_full/source/conjugategrad.h
new file mode 100644
index 00000000000..2fede9658d3
--- /dev/null
+++ b/source/blender/python/manta_full/source/conjugategrad.h
@@ -0,0 +1,169 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Conjugate gradient solver
+ *
+ ******************************************************************************/
+
+#ifndef _CONJUGATEGRADIENT_H
+#define _CONJUGATEGRADIENT_H
+
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+
+namespace Manta {
+
+static const bool CG_DEBUG = false;
+
+//! Basic CG interface
+class GridCgInterface {
+ public:
+ enum PreconditionType { PC_None=0, PC_ICP, PC_mICP };
+
+ GridCgInterface() : mUseResNorm(true) {};
+ virtual ~GridCgInterface() {};
+
+ // solving functions
+ virtual bool iterate() = 0;
+ virtual void solve(int maxIter) = 0;
+
+ // precond
+ virtual void setPreconditioner(PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak) = 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;
+
+ void setUseResNorm(bool set) { mUseResNorm = set; }
+
+ protected:
+
+ // use norm of residual, or max value for threshold?
+ bool mUseResNorm;
+};
+
+
+//! 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, 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 setPreconditioner(PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak);
+
+ // 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;
+ FlagGrid& mFlags;
+ Grid<Real>& mTmp;
+
+ Grid<Real> *mpA0, *mpAi, *mpAj, *mpAk;
+
+ PreconditionType mPcMethod;
+ //! preconditioning grids
+ Grid<Real> *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk;
+
+ //! sigma / residual
+ Real mSigma;
+ //! accuracy of solver (max. residuum)
+ Real mAccuracy;
+ //! norm of the residual
+ Real mResNorm;
+}; // GridCg
+
+
+//! Kernel: Apply symmetric stored Matrix
+KERNEL(idx)
+void ApplyMatrix (FlagGrid& flags, Grid<Real>& dst, Grid<Real>& src,
+ Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak)
+{
+ 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];
+}
+
+//! Kernel: Apply symmetric stored Matrix. 2D version
+KERNEL(idx)
+void ApplyMatrix2D (FlagGrid& flags, Grid<Real>& dst, Grid<Real>& src,
+ Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak)
+{
+ 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];
+}
+
+//! Kernel: Construct the matrix for the poisson equation
+KERNEL (bnd=1)
+void MakeLaplaceMatrix(FlagGrid& flags, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak) {
+ if (!flags.isFluid(i,j,k))
+ return;
+
+ // center
+ 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.;
+
+ 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.;
+}
+
+
+
+
+} // namespace
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/cuda/buoyancy.cu b/source/blender/python/manta_full/source/cuda/buoyancy.cu
new file mode 100644
index 00000000000..41f49f38f50
--- /dev/null
+++ b/source/blender/python/manta_full/source/cuda/buoyancy.cu
@@ -0,0 +1,421 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * CUDA functions for meshes
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <map>
+#include "cudatools.h"
+#include "vortexsheet.h"
+
+using namespace std;
+
+namespace Manta {
+
+
+const int VortKernelBlockSize = 512;
+
+//! for each Node, integrate all triangles
+//! [for simplicity, expects array with multiples of VortKernelBlockSize]
+__global__ void VorticityKernel(CVec3Ptr nodes, const CVec3Ptr vortexPos, const CVec3Ptr strength, float reg2, float cutoff2,
+ const int len, const int triBlocks, const int offset) {
+ const int nodeIdx = threadIdx.x + VortKernelBlockSize * blockIdx.x + offset;
+
+ __shared__ float3 vpos[VortKernelBlockSize];
+ __shared__ float3 vstr[VortKernelBlockSize];
+
+ // load current position
+ const int triLocal = threadIdx.x;
+ float3 pos = nodes.get(nodeIdx);
+ float3 u = pos;
+
+ // divide triangles into blocks for shared memeory usage
+ for (int i=0; i<triBlocks; i++) {
+ const int triGlobal = threadIdx.x + VortKernelBlockSize * i;
+
+ // load shared data
+ vpos[triLocal] = vortexPos.get(triGlobal);
+ vstr[triLocal] = strength.get(triGlobal);
+ __syncthreads();
+
+ //if (nodeIdx < len) {
+ for (int j=0; j<VortKernelBlockSize; j++) {
+ // actual vorticity kernel
+ float3 r = pos - vpos[j];
+ float r2 = normSqr(r);
+ if (r2 < cutoff2) {
+ float l = r2+reg2, l2=l*l;
+ float div = rsqrtf(l2*l);
+ u += cross (vstr[j], r) * div;
+ }
+ }
+ //}
+ __syncthreads();
+ }
+
+ // writeback
+ nodes.set(nodeIdx, u);
+}
+
+PYTHON void meshApplyBuoyancyTotalCuda(VortexSheetMesh& mesh,
+ Real scale=1e-3, Real regularization=1, Real cutoffCells = 1e10, bool useDiff = false)
+{
+ Real dt = parent->getDt();
+ // align len to blocksize
+ int nodelen = ((mesh.numNodes() - 1) / VortKernelBlockSize + 1) * VortKernelBlockSize;
+ int trilen = ((mesh.numTris() - 1) / VortKernelBlockSize + 1) * VortKernelBlockSize;
+
+ // construct device arrays
+ CVec3Array nodes(nodelen);
+ CVec3Array tripos(trilen);
+ CVec3Array strength(trilen);
+
+ // copy values from mesh
+ for(size_t i=0; i<mesh.numTris(); i++) {
+ Vec3 center = mesh.getFaceCenter(i);
+ Vec3 vort = mesh.sheet(i).vorticity;
+ if (useDiff)
+ vort -= mesh.sheet(i).vorticitySmoothed;
+ Vec3 str = vort * (mesh.getFaceArea(i) * scale * dt);
+
+ tripos.set(i, center);
+ strength.set(i, str);
+ }
+ for(size_t i=0; i<mesh.numNodes(); i++)
+ nodes.set(i, mesh.nodes(i).pos);
+
+ // fill aligned parts
+ for(int i=mesh.numTris(); i<trilen; i++) { tripos.set(i, Vec3::Zero); strength.set(i, Vec3::Zero); }
+ for(int i=mesh.numNodes(); i<nodelen; i++) { nodes.set(i, Vec3::Zero); }
+
+ nodes.upload();
+ tripos.upload();
+ strength.upload();
+
+ // construct parameters
+ float reg2=regularization*regularization;
+ float cutoff2 = cutoffCells*cutoffCells;
+
+ // to avoid timeout, divide launches
+ const int diff = 15000000 / tripos.size() * VortKernelBlockSize;
+ cout << "Mesh buoyancy start" << endl;
+ for (int offset=0; offset<nodelen; offset+= diff) {
+ int blocks = (min(nodelen-offset, diff) - 1) / VortKernelBlockSize + 1;
+
+ // invoke kernel
+ VorticityKernel<<<blocks, VortKernelBlockSize>>> (nodes.data(), tripos.data(), strength.data(), reg2, cutoff2, mesh.numNodes(), trilen/VortKernelBlockSize, offset);
+ }
+ cout << "Mesh buoyancy: " << (nodelen/diff)+1 << " calls" << endl;
+ nodes.download();
+
+ // readback new node positions
+ for(size_t i=0; i<mesh.numNodes(); i++) {
+ if (!mesh.isNodeFixed(i))
+ mesh.nodes(i).pos = nodes[i];
+ }
+}
+
+
+const int FvnBlockSize = 512;
+const int FastEvalGridDivider = 2;
+
+//! for each Node, integrate all triangles
+//! use block cell structure for fast pruning
+__global__ void FastVorticityKernelNoshare(CVec3Ptr nodes, const CVec3Ptr srcPos, const CVec3Ptr strength, const int* srcStart, const int* srcLen,
+ float reg2, float cutoff2, float safeRadius2, int intRadius, int3 gridRes, float maxres, const int len, const int divider, const int offset)
+{
+ const int nodeIdx = threadIdx.x + FvnBlockSize * blockIdx.x + offset;
+ if (nodeIdx >= len) return;
+
+ // load current node position
+ float3 pos = nodes.get(nodeIdx);
+ int3 cell = make_int3((int)pos.x / divider, (int)pos.y / divider, (int)pos.z / divider);
+ float3 u = pos;
+
+ // query cells within block radius
+ int3 minBlock = make_int3(max(cell.x - intRadius,0), max(cell.y - intRadius,0), max(cell.z - intRadius,0));
+ int3 maxBlock = make_int3(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
+ float3 d = make_float3(cell.x-i, cell.y-j, cell.z-k);
+ if (normSqr(d) > safeRadius2) continue;
+
+ // find source cell, and divide it into thread blocks
+ int block = i + gridRes.x * (j + gridRes.y * k);
+ int slen = srcLen[block];
+ if (slen == 0) continue;
+ int start = srcStart[block];
+
+ // process sources
+ for(int s=0; s<slen; s++) {
+ // actual vorticity kernel
+ float3 r = pos - srcPos.get(start+s);
+ float r2 = normSqr(r);
+ if (r2 < cutoff2) {
+ float l = r2+reg2, l2=l*l;
+ float div = rsqrtf(l2*l);
+ u += cross (strength.get(start+s), r) * div;
+ }
+ }
+ }
+
+
+ // writeback
+ nodes.set(nodeIdx, u);
+}
+
+inline int cIndex(const Vec3& pos, const Vec3i& s) {
+ Vec3i p = toVec3i(pos) / FastEvalGridDivider;
+ 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);
+}
+
+// TODO: don't reorder nodes -- performance ?
+PYTHON void meshApplyBuoyancyLocalCuda(VortexSheetMesh& mesh,
+ Real scale=1e-3, int cutoffCells=5, Real regularization=1)
+{
+ Real dt = parent->getDt();
+
+ // prepare center values and strength
+ vector<Vec3> center(mesh.numTris());
+ vector<Vec3> strength(mesh.numTris());
+ for(size_t i=0; i<mesh.numTris(); i++) {
+ Vec3 vort = mesh.sheet(i).vorticity - mesh.sheet(i).vorticitySmoothed;
+ strength[i] = vort * (mesh.getFaceArea(i) * scale * dt);
+ center[i] = mesh.getFaceCenter(i);
+ }
+
+ // create triangles(sources) lookup grid
+ Vec3i gridRes = parent->getGridSize() / FastEvalGridDivider;
+ const int numCells = gridRes.x * gridRes.y * gridRes.z;
+
+ // 1. count sources per cell
+ CArray<int> srcPerCell(numCells);
+ Real maxres = gridRes.max();
+ for (size_t i=0; i<center.size(); i++) {
+ int cell = cIndex(center[i], gridRes);
+ if (cell >= 0)
+ srcPerCell[cell]++;
+ }
+ srcPerCell.upload();
+
+ // 2. create start index lookup
+ CArray<int> srcCellStart(numCells);
+ int cnt=0;
+ for (int i=0; i<numCells; i++) {
+ srcCellStart[i] = cnt;
+ cnt += srcPerCell[i];
+ }
+ srcCellStart.upload();
+
+ // 3. reorder sources
+ CVec3Array reorderStrength(center.size());
+ CVec3Array reorderSourcePos(center.size());
+ {
+ vector<int> curSrcCell(numCells);
+ for (int i=0; i<(int)center.size(); i++) {
+ int cell = cIndex(center[i], gridRes);
+ if (cell < 0) continue;
+ int idx = srcCellStart[cell] + curSrcCell[cell];
+ reorderStrength.set(idx, strength[i]);
+ reorderSourcePos.set(idx, center[i]);
+ curSrcCell[cell]++;
+ }
+ }
+ reorderStrength.upload();
+ reorderSourcePos.upload();
+
+ // group nodes into blocks
+ // 1. count nodes per cell
+ vector<int> nodesPerCell(numCells);
+ for (int i=0; i<mesh.numNodes(); i++) {
+ int cell = cIndex(mesh.nodes(i).pos, gridRes);
+ if (cell >= 0)
+ nodesPerCell[cell]++;
+ }
+ // 2. cluster blocks into execution plan
+ vector<int> nodesCellStart(numCells);
+ int offset = 0;
+ for (int i=0; i<numCells; i++) {
+ nodesCellStart[i] = offset;
+ offset += nodesPerCell[i];
+ }
+ // 3. reorder nodes
+ CVec3Array reorderNodes(mesh.numNodes());
+ {
+ vector<int> curNodeCell(numCells);
+ for (int i=0; i<mesh.numNodes(); i++) {
+ int cell = cIndex(mesh.nodes(i).pos, gridRes);
+ if (cell < 0) continue;
+ int idx = nodesCellStart[cell] + curNodeCell[cell];
+ reorderNodes.set(idx, mesh.nodes(i).pos);
+ curNodeCell[cell]++;
+ }
+ }
+ reorderNodes.upload();
+
+ // construct parameters
+ int cutoffInCells = cutoffCells / FastEvalGridDivider; // translate to lookup grid
+ float safeRadius = (float)cutoffCells / (float)FastEvalGridDivider + sqrt(3.0);
+ float safeRadius2 = safeRadius*safeRadius;
+ float reg2 = regularization*regularization;
+ float cutoff2 = cutoffCells*cutoffCells;
+ cout << "cutoff int " <<cutoffInCells << " safe " << safeRadius << " cutoff " << cutoffCells << endl;
+
+ // call in chunks for prevent timeout
+ const int MAXBLOCK = 100;
+ const int diff = MAXBLOCK*FvnBlockSize;
+ int rcnt = 0;
+ for (int offset=0; offset<(int)reorderNodes.size(); offset+= diff, rcnt++) {
+ int blocks = (std::min(reorderNodes.size() - offset,diff)-1)/FvnBlockSize + 1;
+
+ FastVorticityKernelNoshare<<<blocks,FvnBlockSize>>>
+ (reorderNodes.data(), reorderSourcePos.data(), reorderStrength.data(), srcCellStart.data(), srcPerCell.data(),
+ reg2, cutoff2, safeRadius2, cutoffInCells, make_int3(gridRes.x, gridRes.y, gridRes.z), maxres, reorderNodes.size(), FastEvalGridDivider, offset);
+ }
+ cout << "maxblocks " << MAXBLOCK << " total calls " << rcnt << endl;
+
+ // download and reorder
+ reorderNodes.download();
+ {
+ vector<int> curNodeCell(numCells); // redo ordering
+ for (int i=0; i<mesh.numNodes(); i++) {
+ int cell = cIndex(mesh.nodes(i).pos, gridRes);
+ if (cell < 0) continue;
+ int idx = nodesCellStart[cell] + curNodeCell[cell];
+ if (!mesh.isNodeFixed(i))
+ mesh.nodes(i).pos = reorderNodes[idx];
+ curNodeCell[cell]++;
+ }
+ }
+}
+
+#define MAXFRONT 500
+
+__global__ void GaussKernel(CVec3Ptr distance, int* con, CVec3Ptr vort, CVec3Ptr vortSmooth, int blocksize, int stride, float cutoff, float mult, int offset) {
+ const int Cidx = threadIdx.x + blocksize * blockIdx.x + offset;
+ if (Cidx >= stride) return;
+
+ int kernelIdx[MAXFRONT];
+ float kernelDist[MAXFRONT];
+ for(int i=0; i<MAXFRONT; i++) {
+ kernelIdx[i] = -1;
+ kernelDist[i] = 0;
+ }
+ int kernelElements = 1, newKernelElements = 1, lastPos = 0;
+ kernelIdx[0] = Cidx;
+
+ //float a =0;
+ int iter;
+ for(iter=0; iter < 40; iter++) {
+ for (int i=lastPos; i<kernelElements; i++) {
+
+ int curidx = kernelIdx[i];
+ float curdist = kernelDist[i];
+
+ // add adjacent triangles to front list
+ float nextdist[3];
+ nextdist[0] = distance.x[curidx];
+ nextdist[1] = distance.y[curidx];
+ nextdist[2] = distance.z[curidx];
+ for (int c=0; c<3; c++) {
+ int nextidx = con[c+3*curidx];
+ if (nextidx < 0) continue;
+ float dist = nextdist[c] + curdist;
+ if (dist > cutoff) continue;
+
+ // check if already in list
+ bool found = false;
+ for (int j=0; j<newKernelElements; j++) {
+ if (kernelIdx[j] == nextidx) {
+ found = true;
+ if (kernelDist[j] > dist) kernelDist[j] = dist;
+ break;
+ }
+ }
+ if (!found) {
+ if (newKernelElements >= MAXFRONT-1) goto finish;
+ kernelIdx[newKernelElements] = nextidx;
+ kernelDist[newKernelElements] = dist;
+ newKernelElements++;
+ }
+ }
+ }
+ if (kernelElements == newKernelElements) break;
+ lastPos = kernelElements;
+ kernelElements = newKernelElements;
+ }
+ finish:
+
+ // run gauss kernel over all nodes
+ float sum = 0;
+ float3 smooth = make_float3(0,0,0);
+ for (int j=0; j<newKernelElements; j++) {
+ const int idx = kernelIdx[j];
+ float dist = kernelDist[j];
+ float coeff = exp(dist*dist*mult);
+ sum += coeff;
+ smooth += make_float3(vort.x[idx] * coeff, vort.y[idx] * coeff, vort.z[idx] * coeff);
+ }
+ vortSmooth.set(Cidx, make_float3(smooth.x/sum, smooth.y/sum, smooth.z/sum));
+}
+
+PYTHON void filterVorticityCuda(VortexSheetMesh& mesh, Real sigma) {
+ const int len = mesh.numTris();
+
+ // upload mesh properties
+ CArray<int> connectivity(len*3);
+ CVec3Array faceCenter(len), distance(len), vorticity(len), vortSmooth(len);
+ for (int i=0; i<len; i++) {
+ faceCenter.set(i, mesh.getFaceCenter(i));
+ vorticity.set(i, mesh.sheet(i).vorticity);
+ }
+ faceCenter.upload();
+ vorticity.upload();
+ vortSmooth.upload();
+ for (int i=0; i<len; i++) {
+ Vec3 dist;
+ for (int c=0; c<3; c++) {
+ int ot = mesh.corners(mesh.corners(i,c).opposite).tri;
+ connectivity[i*3+c] = ot;
+ dist[c] = norm(faceCenter[i] - faceCenter[ot]);
+ }
+ distance.set(i, dist);
+ }
+ distance.upload();
+ connectivity.upload();
+
+ const float cutoff = 2.0*sigma;
+ const float mult = -0.5/sigma/sigma;
+
+ // invoke kernel in blocks (to avoid GUI stall)
+ const int blockSize = 128;
+ const int numblocks = 100;
+ const int maxProcess = blockSize * numblocks;
+ int cnt=0;
+ for (int offset=0; offset<len; offset+= maxProcess, cnt++) {
+ int blocks = (min(len - offset, maxProcess)-1)/blockSize + 1;
+
+ GaussKernel<<<blocks,blockSize>>>(distance.data(), connectivity.data(), vorticity.data(), vortSmooth.data(), blockSize, len, cutoff, mult, offset);
+ }
+ cout << "Maxblocks: " << numblocks << ", Totalblocks: " << faceCenter.size()/blockSize << " -> " << cnt << " calls in total" << endl;
+
+ // download and set
+ vortSmooth.download();
+ for (int i=0; i<len; i++) {
+ mesh.sheet(i).vorticitySmoothed = vortSmooth[i];
+ }
+}
+
+} // namespace \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/cuda/cudatools.h b/source/blender/python/manta_full/source/cuda/cudatools.h
new file mode 100644
index 00000000000..c9435659ad5
--- /dev/null
+++ b/source/blender/python/manta_full/source/cuda/cudatools.h
@@ -0,0 +1,176 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Some helper functions for using CUDA
+ *
+ ******************************************************************************/
+
+#ifndef _CUDATOOLS_H
+#define _CUDATOOLS_H
+
+#include <cuda.h>
+#include <vector>
+#include <thrust/device_vector.h>
+#include "vectorbase.h"
+
+// *****************************************************************
+// extending float3 type
+
+__device__ inline float3 operator+(const float3 &a, const float3 &b) {
+ return make_float3(a.x+b.x, a.y+b.y, a.z+b.z);
+}
+__device__ inline float3 operator*(const float3 &a, const float b) {
+ return make_float3(a.x*b, a.y*b, a.z*b);
+}
+__device__ inline float3 operator/(const float3 &a, const float b) {
+ return make_float3(a.x/b, a.y/b, a.z/b);
+}
+__device__ inline float3 operator*(const float b, const float3 &a) {
+ return make_float3(a.x*b, a.y*b, a.z*b);
+}
+__device__ inline float3 operator-(const float3 &a, const float3 &b) {
+ return make_float3(a.x-b.x, a.y-b.y, a.z-b.z);
+}
+__device__ inline void operator+=(float3 &a, const float3 &b) {
+ a.x += b.x; a.y += b.y; a.z += b.z;
+}
+__device__ inline float normSqr(const float3& v) {
+ return (v.x*v.x)+(v.y*v.y)+(v.z*v.z);
+}
+__device__ inline float norm(const float3& v) {
+ return sqrtf((v.x*v.x)+(v.y*v.y)+(v.z*v.z));
+}
+__device__ inline float normalize(float3& v) {
+ float n = norm(v);
+ if (n==0)
+ v = make_float3(0,0,0);
+ else {
+ float in = 1.0f/n;
+ v = make_float3(v.x * in, v.y * in, v.z * in);
+ }
+ return n;
+}
+__device__ inline float3 cross(const float3& a, const float3& b) {
+ return make_float3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
+}
+__device__ inline float dot(const float3&a, const float3& b) {
+ return (a.x*b.x + a.y*b.y + a.z*b.z);
+}
+
+
+namespace Manta {
+
+// *****************************************************************
+// some general macros
+
+inline void cudaAssert(cudaError_t er) {
+ if (er != cudaSuccess) {
+ throw Error("CUDA assert error: " + std::string(cudaGetErrorString(er)));
+ }
+}
+// *****************************************************************
+// define some helpers for unpacking Vec3s etc.
+
+//! Device object to access data provided by Vec3AArray
+struct CVec3Ptr {
+ float *x, *y, *z;
+ __device__ inline float3 get(int i) const { return make_float3(x[i],y[i],z[i]); };
+ __device__ inline void set(int i, const float3& v) { x[i]=v.x; y[i]=v.y; z[i]=v.z; };
+};
+
+//! Provide host and data for easy coalescing by the GPU.
+//! Has the same methods as CVector
+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;
+ }
+ upload();
+ }
+ void upload() {
+ dx = x;
+ dy = y;
+ dz = z;
+ }
+ void download() {
+ x = dx;
+ y = dy;
+ z = dz;
+ }
+ void downloadTo(std::vector<Vec3>& v) {
+ download();
+ if (v.size() != x.size())
+ v.resize(x.size());
+ for (size_t i=0; i<v.size(); i++)
+ v[i] = Vec3(x[i],y[i],z[i]);
+ }
+
+
+ CVec3Ptr data() {
+ CVec3Ptr a = { thrust::raw_pointer_cast(dx.data()), thrust::raw_pointer_cast(dy.data()), thrust::raw_pointer_cast(dz.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(); }
+ inline int blocks(int blockSize) { return (x.size() - 1) / blockSize + 1; }
+
+ thrust::host_vector<float> x, y, z;
+ thrust::device_vector<float> dx, dy, dz;
+};
+
+//! wrapper around thrust device vector for easier access in CUDA
+template<class T>
+struct CArray {
+ CArray(const std::vector<T>& v) :
+ dev(v.begin(), v.end())
+ {
+ }
+ CArray(int sz) {
+ dev.resize(sz);
+ host.resize(sz);
+ }
+ T* data() {
+ return thrust::raw_pointer_cast(dev.data());
+ }
+ void upload() {
+ if (host.size() == dev.size())
+ dev = host;
+ }
+ void download() {
+ host = dev;
+ }
+ void downloadTo(std::vector<T>& v) {
+ thrust::copy(dev.begin(), dev.end(), v.begin());
+ }
+ inline T& operator[](int idx) { return host[idx]; }
+ inline void set(int idx, T val) { host[idx] = val; }
+
+ int size() { return dev.size(); }
+ int blocks(int blockSize) { return (dev.size()-1) / blockSize + 1; }
+
+ thrust::host_vector<T> host;
+ thrust::device_vector<T> dev;
+};
+
+} // namespace
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/cuda/curlnoise.cu b/source/blender/python/manta_full/source/cuda/curlnoise.cu
new file mode 100644
index 00000000000..3f2b34dc0a6
--- /dev/null
+++ b/source/blender/python/manta_full/source/cuda/curlnoise.cu
@@ -0,0 +1,110 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * CUDA curl noise evaluation
+ *
+ ******************************************************************************/
+
+#include "curlnoise.h"
+#include "cudatools.h"
+#include "noisefield.h"
+#include "manta.h"
+
+using namespace std;
+
+namespace Manta {
+
+
+void CudaNoiseTexture::init() {
+ cudaExtent noiseSize = {NOISE_SIZE, NOISE_SIZE, NOISE_SIZE};
+ size_t memSize = noiseSize.width*noiseSize.height*noiseSize.depth;
+
+ // register channels
+ cudaChannelFormatDesc noiseChannelDesc = cudaCreateChannelDesc(16, 16, 16, 16, cudaChannelFormatKindSigned);
+ cudaAssert(cudaMalloc3DArray(&mNoiseArray, &noiseChannelDesc, noiseSize));
+
+ // create noise objects
+ WaveletNoiseField nx(NULL), ny(NULL), nz(NULL);
+
+ // find scales
+ float maxval = -1e20f;
+ for (size_t i = 0; i < memSize; i++)
+ maxval = std::max(std::max(std::max(fabs(nx.data()[i]), fabs(ny.data()[i])), fabs(nz.data()[i])), maxval);
+
+ float scale = 65535.0f / (2.0 * maxval);
+ mScale = maxval;
+
+ // alloc local buffer
+ short4* buffer = new short4[memSize];
+ for (size_t i = 0; i < memSize; i++) {
+ buffer[i].x = (signed short) (nx.data()[i] * scale);
+ buffer[i].y = (signed short) (ny.data()[i] * scale);
+ buffer[i].z = (signed short) (nz.data()[i] * scale);
+ buffer[i].w = 0;
+ }
+
+ // copy to page-locked mem
+ cudaPitchedPtr page_locked_ptr;
+ page_locked_ptr.pitch = noiseSize.width*sizeof(short4);
+ page_locked_ptr.xsize = noiseSize.width;
+ page_locked_ptr.ysize = noiseSize.height;
+ page_locked_ptr.ptr = buffer;
+
+ // copy data to 3D array
+ cudaMemcpy3DParms copy_params = {0};
+ copy_params.srcPtr = page_locked_ptr;
+ copy_params.dstArray = mNoiseArray;
+ copy_params.extent = noiseSize;
+ copy_params.kind = cudaMemcpyHostToDevice;
+ cudaAssert(cudaMemcpy3D(&copy_params));
+
+ //FILE* fp=fopen("/tmp/a.bin","wb"); fwrite(nx.data(), sizeof(float), 128*128*128, fp); fclose(fp);
+ delete[] buffer;
+}
+
+CudaNoiseDev CudaNoiseTexture::bind(CompressedTex& tex) {
+ // Bind the texture
+ tex.normalized = true;
+ tex.filterMode = cudaFilterModeLinear; // this kills high frequencies !
+ tex.addressMode[0] = cudaAddressModeWrap;
+ tex.addressMode[1] = cudaAddressModeWrap;
+ tex.addressMode[2] = cudaAddressModeWrap;
+ cudaAssert(cudaBindTextureToArray(tex, mNoiseArray));
+
+ return CudaNoiseDev(mScale);
+}
+
+CudaNoiseTexture::~CudaNoiseTexture() {
+ cudaFreeArray(mNoiseArray);
+}
+
+/*
+CompressedTex noise;
+
+__global__ void rewriteNoise(CudaNoiseDev nd, float* a) {
+ int3 cell = make_int3(threadIdx.x + blockDim.x*blockIdx.x, threadIdx.y + blockDim.y*blockIdx.y, threadIdx.z + blockDim.z*blockIdx.z);
+ float scale = 1.0f/128.0f;
+ float3 p = make_float3((float)(cell.x+0.5f) * scale, (float)(cell.y+0.5f) * scale, (float)(cell.z+0.5f) * scale);
+ float4 n = tex3D(noise, p.x, p.y, p.z);
+ a[cell.x + 128*cell.y + 128*128*cell.z] = (float)n.x * nd.scale;
+}
+
+PYTHON void testme() {
+ CudaNoiseTexture nd;
+ CArray<float> a(128*128*128);
+ a.upload();
+
+ dim3 blocksize(8, 8, 8);
+ dim3 blocks(128/8, 128/8, 128/8);
+ rewriteNoise<<<blocks, blocksize>>>(nd.bind(noise), a.data());
+ a.download();
+ FILE* fp=fopen("/tmp/re.bin","wb"); fwrite(&a[0], sizeof(float), 128*128*128, fp); fclose(fp);
+}*/
+
+} //namespace \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/cuda/curlnoise.h b/source/blender/python/manta_full/source/cuda/curlnoise.h
new file mode 100644
index 00000000000..121e47291f7
--- /dev/null
+++ b/source/blender/python/manta_full/source/cuda/curlnoise.h
@@ -0,0 +1,196 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * CUDA curl noise evaluation
+ *
+ ******************************************************************************/
+
+#ifndef _CURLNOISE_H
+#define _CURLNOISE_H
+
+#include "cudatools.h"
+
+namespace Manta {
+
+const int NOISE_SIZE = 128;
+typedef texture<short4, 3, cudaReadModeNormalizedFloat> CompressedTex;
+
+//! Device interface for CUDA noise texture
+struct CudaNoiseDev {
+ CudaNoiseDev(float s) : scale(s) {};
+ float scale;
+
+ __device__ inline float3 eval(CompressedTex tex, const float3& p);
+ __device__ inline float3 synthesizeK41(CompressedTex tex, const float3& p, int octaves, float L0);
+};
+
+//! Host interface for CUDA noise texture
+class CudaNoiseTexture {
+public:
+ CudaNoiseTexture() { init(); }
+ ~CudaNoiseTexture();
+ void init();
+ CudaNoiseDev bind(CompressedTex& tex);
+
+//private:
+ cudaArray* mNoiseArray;
+ float mScale;
+};
+
+
+
+
+// *****************************************************************************
+// Implementation
+// *****************************************************************************
+
+template<char X, int N, int M>
+__device__ inline float derivativeWeight(const float t)
+{
+ if ((X == 'x' && N == 0) || (X == 'y' && N == 1) || (X == 'z' && N == 2)) {
+ if (M == 0)
+ return t;
+ else if (M == 1)
+ return 1.0f - 2.0f * t;
+ else
+ return t - 1.0f;
+ } else {
+ if (M == 0)
+ return t * t * 0.5f;
+ else if (M == 1)
+ return 0.5f + t - t*t;
+ else
+ return 0.5f - t + 0.5f * t * t;
+ }
+}
+
+__device__ inline float3 CudaNoiseDev::eval(CompressedTex noise, const float3& p) {
+ float cache[12];
+ float ext = 1.0f / (float) NOISE_SIZE;
+
+ float t0, t1, t2;
+ float midX, midY, midZ;
+
+ midX = ceil(p.x - 0.5f);
+ t0 = midX - (p.x - 0.5f);
+ midX -= 1.0f;
+ midX *= ext;
+
+ midY = ceil(p.y - 0.5f);
+ t1 = midY - (p.y - 0.5f);
+ midY -= 1.0f;
+ midY *= ext;
+
+ midZ = ceil(p.z - 0.5f);
+ t2 = midZ - (p.z - 0.5f);
+ midZ -= 1.0f;
+ midZ *= ext;
+
+ cache[0] = derivativeWeight<'x', 2, 0>(t2);
+ cache[1] = derivativeWeight<'x', 2, 1>(t2);
+ cache[2] = derivativeWeight<'x', 2, 2>(t2);
+
+ cache[3] = derivativeWeight<'z', 2, 0>(t2);
+ cache[4] = derivativeWeight<'z', 2, 1>(t2);
+ cache[5] = derivativeWeight<'z', 2, 2>(t2);
+
+ cache[6] = derivativeWeight<'x', 1, 0>(t1);
+ cache[7] = derivativeWeight<'x', 1, 1>(t1);
+ cache[8] = derivativeWeight<'x', 1, 2>(t1);
+
+ cache[9] = derivativeWeight<'y', 1, 0>(t1);
+ cache[10] = derivativeWeight<'y', 1, 1>(t1);
+ cache[11] = derivativeWeight<'y', 1, 2>(t1);
+
+ float3 v;
+ v.x = 0.0f;
+ v.y = 0.0f;
+ v.z = 0.0f;
+
+ ///////////////////////////////////////////////////////////////////////////////////////
+ // x, y, z derivatives
+ ///////////////////////////////////////////////////////////////////////////////////////
+ for (int k = 0; k < 3; k++, midZ += ext)
+ {
+ for (int j = 0; j < 3; j++, midY += ext)
+ {
+ for (int i = 0; i < 3; i++, midX += ext)
+ {
+ // Read the noise texture
+ float4 n = tex3D(noise, midX, midY, midZ);
+
+ float w2_x = cache[0 + k];
+ float w2_y = w2_x;
+ float w2_z = cache[3 + k];
+
+ float w1_x = cache[6 + j];
+ float w1_y = cache[9 + j];
+ float w1_z = w1_x;
+
+ float w0_x = (i == 0) ? derivativeWeight<'x', 0, 0>(t0) :
+ (i == 1) ? derivativeWeight<'x', 0, 1>(t0) :
+ derivativeWeight<'x', 0, 2>(t0);
+
+ float w0_y = (i == 0) ? derivativeWeight<'y', 0, 0>(t0) :
+ (i == 1) ? derivativeWeight<'y', 0, 1>(t0) :
+ derivativeWeight<'y', 0, 2>(t0);
+ float w0_z = w0_y;
+
+ // Decompress noise
+ n.x *= scale;
+ n.y *= scale;
+ n.z *= scale;
+
+ // Calculate the final weights
+ float w_x = w0_x * w1_x * w2_x;
+ float w_y = w0_y * w1_y * w2_y;
+ float w_z = w0_z * w1_z * w2_z;
+
+ // Add the weighted noise
+ v.z += n.y * w_x;
+ v.y -= n.z * w_x;
+
+ v.z -= n.x * w_y;
+ v.x += n.z * w_y;
+
+ v.y += n.x * w_z;
+ v.x -= n.y * w_z;
+ }
+ midX -= 3.0f * ext;
+ }
+ midY -= 3.0f * ext;
+ }
+
+ return v;
+}
+
+const __device__ float PERSISTENCE = 0.56123f;
+
+__device__ inline float3 CudaNoiseDev::synthesizeK41(CompressedTex tex, const float3& p, int octaves, float L0) {
+ // Base parameters for octave 0
+ float multiplier = L0;
+ float amplitude = 1.0f;
+ float3 vel = make_float3(0,0,0);
+
+ for (int octave = 0; octave < octaves; octave++) {
+ float3 noiseLookup = eval(tex, multiplier * p);
+ vel += noiseLookup * amplitude;
+
+ // next scale
+ amplitude *= PERSISTENCE;
+ multiplier *= 2.0f;
+ }
+ return vel;
+}
+
+
+
+} // namespace
+
+#endif
diff --git a/source/blender/python/manta_full/source/cuda/meshtools.cu b/source/blender/python/manta_full/source/cuda/meshtools.cu
new file mode 100644
index 00000000000..4ad4232fad5
--- /dev/null
+++ b/source/blender/python/manta_full/source/cuda/meshtools.cu
@@ -0,0 +1,165 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * GPU SDF creation from triangle mesh
+ *
+ ******************************************************************************/
+
+#include "cudatools.h"
+#include "mesh.h"
+#include "grid.h"
+#include <stack>
+
+using namespace std;
+namespace Manta {
+
+const int SDFBlockSize = 8;
+
+__global__ void SDFKernel(const int* partStart, const int* partLen, CVec3Ptr pos, CVec3Ptr normal, float* sdf, int3 gridRes, int intRadius, float safeRadius2, float cutoff2, float isigma2)
+{
+ // cell index, center
+ int3 cell = make_int3(threadIdx.x + blockDim.x*blockIdx.x, threadIdx.y + blockDim.y*blockIdx.y, threadIdx.z + blockDim.z*blockIdx.z);
+ if (cell.x >= gridRes.x || cell.y >= gridRes.y || cell.z >= gridRes.z) return;
+ float3 cpos = make_float3(cell.x + 0.5f, cell.y + 0.5f, cell.z + 0.5f);
+ float sum = 0.0f;
+ float dist = 0.0f;
+
+ // query cells within block radius
+ int3 minBlock = make_int3(max(cell.x - intRadius,0), max(cell.y - intRadius,0), max(cell.z - intRadius,0));
+ int3 maxBlock = make_int3(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
+ float3 d = make_float3(cell.x-i, cell.y-j, cell.z-k);
+ if (normSqr(d) > 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
+ float3 r = cpos - pos.get(start+s);
+ float r2 = normSqr(r);
+ if (r2 < cutoff2) {
+ float 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;
+}
+
+inline int _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);
+}
+
+//! Obtain levelset from mesh.
+//! This only works for dense meshes -- simply uses normals and triangle centers, no triangle integration
+PYTHON void meshSDFCuda(Mesh& mesh, Grid<Real>& levelset, Real sigma, Real cutoff=-1)
+{
+ if (cutoff<0) cutoff = 2*sigma;
+
+ Vec3i gridRes = levelset.getSize();
+ Vec3 mult = toVec3(gridRes) / toVec3(mesh.getParent()->getGridSize());
+
+ // prepare center values
+ vector<Vec3> center(mesh.numTris());
+ for(size_t i=0; i<mesh.numTris(); i++)
+ center[i] = mesh.getFaceCenter(i) * mult;
+
+ // prepare grid
+ const int numCells = gridRes.x * gridRes.y * gridRes.z;
+ CArray<Real> gridDev(numCells);
+ for (int i=0; i<numCells; i++)
+ gridDev[i] = -cutoff;
+ gridDev.upload();
+
+ // 1. count sources per cell
+ CArray<int> srcPerCell(numCells);
+ for (size_t i=0; i<center.size(); i++) {
+ int cell = _cIndex(center[i], gridRes);
+ if (cell >= 0)
+ srcPerCell[cell]++;
+ }
+ srcPerCell.upload();
+
+ // 2. create start index lookup
+ CArray<int> srcCellStart(numCells);
+ int cnt=0;
+ for (int i=0; i<numCells; i++) {
+ srcCellStart[i] = cnt;
+ cnt += srcPerCell[i];
+ }
+ srcCellStart.upload();
+
+ // 3. reorder nodes
+ CVec3Array reorderPos(center.size());
+ CVec3Array reorderNormal(center.size());
+ {
+ vector<int> curSrcCell(numCells);
+ for (int i=0; i<(int)center.size(); i++) {
+ int cell = _cIndex(center[i], gridRes);
+ if (cell < 0) continue;
+ int idx = srcCellStart[cell] + curSrcCell[cell];
+ reorderPos.set(idx, center[i]);
+ reorderNormal.set(idx, mesh.getFaceNormal(i));
+ curSrcCell[cell]++;
+ }
+ }
+ reorderPos.upload();
+ reorderNormal.upload();
+
+ // construct parameters
+ float safeRadius = cutoff + sqrt(3.0)*0.5;
+ float safeRadius2 = safeRadius*safeRadius;
+ float cutoff2 = cutoff*cutoff;
+ float isigma2 = 1.0/(sigma*sigma);
+ int intRadius = (int)(cutoff+0.5);
+
+ dim3 blocksize(SDFBlockSize, SDFBlockSize, SDFBlockSize);
+ dim3 blocks((gridRes.x-1)/SDFBlockSize+1, (gridRes.y-1)/SDFBlockSize+1, (gridRes.z-1)/SDFBlockSize+1);
+ SDFKernel<<<blocks, blocksize>>>(srcCellStart.data(), srcPerCell.data(), reorderPos.data(), reorderNormal.data(), gridDev.data(),
+ make_int3(gridRes.x, gridRes.y, gridRes.z), intRadius, safeRadius2, cutoff2, isigma2);
+
+ gridDev.download();
+ for (int i=0;i<numCells; i++)
+ levelset[i] = gridDev[i];
+
+ // floodfill outside
+ 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));
+ };
+}
+
+} // namespace \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/cuda/particle.cu b/source/blender/python/manta_full/source/cuda/particle.cu
new file mode 100644
index 00000000000..bc1ad3ee85d
--- /dev/null
+++ b/source/blender/python/manta_full/source/cuda/particle.cu
@@ -0,0 +1,172 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * GPU SDF creation from triangle mesh
+ *
+ ******************************************************************************/
+
+#include "cudatools.h"
+#include "particle.h"
+#include "grid.h"
+
+/*using namespace std;
+namespace Manta {
+using namespace std;
+using DDF::nVec3i;
+using DDF::Vec3;
+
+// vortex particle effect: (cyl coord around wp)
+// u = -|wp|*rho*exp( (-rho^2-z^2)/(2sigma^2) ) e_phi
+__device__ inline float3 velocityKernel(const float3& r, const float3& vortNorm, const float strength, const float isigma) {
+ // transform in cylinder coordinate system
+ const float rlen2 = normSqr(r);
+ const float rlendiv = rsqrtf(rlen2);
+ const float z = dot(r, vortNorm);
+ const float3 ePhi = cross(r, vortNorm) * rlendiv;
+ const float rho2 = rlen2 - z*z;
+
+ float vortex;
+ if (rho2 > 1e-10) {
+ // evaluate Kernel
+ vortex = strength * sqrtf(rho2) * expf (rlen2 * isigma);
+ } else {
+ vortex = 0;
+ }
+ return vortex * ePhi;
+}
+
+__device__ inline float3 rk4(const float3& p, const float3& vortNorm, const float strength, const float isigma, const float dt) {
+ float3 k1 = velocityKernel(p, vortNorm, strength, isigma);
+ float3 p2 = p + k1 * (0.5*dt);
+ float3 k2 = velocityKernel(p2, vortNorm, strength, isigma);
+ float3 p3 = p + k2 * (0.5*dt);
+ float3 k3 = velocityKernel(p3, vortNorm, strength, isigma);
+ float3 p4 = p + dt*k3;
+ float3 k4 = velocityKernel(p4, vortNorm, strength, isigma);
+ return (k1 + (k2+k3)*2.0 + k4) * (dt/6.0);
+}
+
+const int VortKernelBlockSize = 256;
+
+// apply vortex kernel to nodes
+__global__ void integrateNodesRK4 (AlignedVec3Array nodes, const AlignedVec3Array sources, const AlignedVec3Array vortex, const AlignedFloatArray sigma2,
+ const float dt)
+{
+ const int globalIdx = threadIdx.x + VortKernelBlockSize * blockIdx.x;
+ const int localIdx = threadIdx.x;
+ __shared__ float3 vpos[VortKernelBlockSize];
+ __shared__ float3 vort[VortKernelBlockSize];
+ __shared__ float vstr[VortKernelBlockSize];
+ __shared__ float vsig[VortKernelBlockSize];
+
+ // load current position
+ float3 pos = nodes.get(globalIdx);
+ float3 u = pos;
+
+ // divide sources into blocks for shared memeory usage
+ for (int i=0; i<sources.blocks; i++) {
+ const int blockIdx = VortKernelBlockSize * i;
+ const int srcGlobal = localIdx + blockIdx;
+
+ // load shared data
+ vpos[localIdx] = sources.get(srcGlobal);
+ vsig[localIdx] = sigma2.get(srcGlobal);
+ float3 v = vortex.get(srcGlobal);
+ float vnorm = normalize(v);
+ vstr[localIdx] = vnorm;
+ vort[localIdx] = v;
+ __syncthreads();
+
+ if (globalIdx < nodes.len) {
+ for (int j=0; j<VortKernelBlockSize; j++) {
+ if (j+blockIdx >= sources.len) continue;
+
+ // apply actual vorticity kernel
+ float3 r = pos - vpos[j];
+ float sig2 = vsig[j];
+ float r2 = normSqr(r);
+ float cutoff2 = 6.0f*sig2;
+ if (r2 > cutoff2 || r2 < 1e-8) continue;
+ // RK4 integration
+ u += rk4(r, vort[j], vstr[j], -0.5/sig2, dt);
+ }
+ }
+ __syncthreads();
+ }
+
+ // writeback
+ if (globalIdx < nodes.len)
+ nodes.set(globalIdx, u);
+}
+
+void cudaIntegrateVortexParticles(vector<SurfaceNode>& nodes, DDF::ParticleSystemVortex& sys, const float scale, const float dt, const float dx)
+{
+ // count valid source, create host array
+ int numSources = 0;
+ for(int i=0; i<sys.size(); i++)
+ if (sys.isActive(i)) numSources++;
+
+ vector<Vec3> srcPos(numSources), srcStr(numSources);
+ vector<float> srcSig(numSources);
+ for (int i=0,idx=0; i<sys.size(); i++) {
+ if (sys.isActive(i)) {
+ srcPos[idx] = sys.pos(i);
+ srcStr[idx] = sys.vortex(i).vorticity * scale;
+ float sig = sys.vortex(i).sigma;
+ srcSig[idx] = sig*sig;
+ idx++;
+ }
+ }
+ if (numSources == 0) return;
+
+ // count valid dest, create host arrays
+ int numDest = 0;
+ for(size_t i=0; i<nodes.size(); i++)
+ if ((nodes[i].flags & SurfaceNode::FIXED) == 0) numDest++;
+
+ vector<Vec3> dstPos(numDest);
+ for(int i=0,idx=0; i<(int)nodes.size(); i++) {
+ if ((nodes[i].flags & SurfaceNode::FIXED) == 0) {
+ SmVector3 p = nodes[i].pos;
+ dstPos[idx] = Vec3(p[0] / dx, p[1] / dx, p[2] / dx);
+ idx++;
+ }
+ }
+
+ // upload sources to GPU
+ DeviceVec3 dSrcPos(VortKernelBlockSize), dSrcStr(VortKernelBlockSize), dDstPos(VortKernelBlockSize), dVDstPos(VortKernelBlockSize);
+ DeviceFloat dSrcSig(VortKernelBlockSize);
+ dSrcPos.upload(srcPos);
+ dSrcSig.upload(srcSig);
+ dSrcStr.upload(srcStr);
+
+ // apply to mesh
+ dDstPos.upload(dstPos);
+ integrateNodesRK4<<<dDstPos.blocks(), VortKernelBlockSize>>>(dDstPos.device, dSrcPos.device, dSrcStr.device, dSrcSig.device, dt);
+ dDstPos.errorTest();
+ dDstPos.download(dstPos);
+
+ // apply to vortex particles
+ dVDstPos.upload(srcPos);
+ integrateNodesRK4<<<dVDstPos.blocks(), VortKernelBlockSize>>>(dVDstPos.device, dSrcPos.device, dSrcStr.device, dSrcSig.device, dt);
+ dVDstPos.errorTest();
+ dVDstPos.download(srcPos);
+
+ // back to arrays...
+ for (int i=0,idx=0; i<sys.size(); i++)
+ if (sys.isActive(i)) sys.setPos(i, srcPos[idx++]);
+
+ for (int i=0,idx=0; i<(int)nodes.size(); i++) {
+ if ((nodes[i].flags & SurfaceNode::FIXED) == 0) {
+ nodes[i].pos = SmVector3(dstPos[idx].x * dx, dstPos[idx].y * dx, dstPos[idx].z * dx);
+ idx++;
+ }
+ }
+}
+*/ \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/cuda/turbulence.cu b/source/blender/python/manta_full/source/cuda/turbulence.cu
new file mode 100644
index 00000000000..2ea9847cac0
--- /dev/null
+++ b/source/blender/python/manta_full/source/cuda/turbulence.cu
@@ -0,0 +1,164 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * GPU turbulence synthesis
+ *
+ ******************************************************************************/
+
+#include "curlnoise.h"
+#include "vortexsheet.h"
+#include "grid.h"
+#include "commonkernels.h"
+
+using namespace std;
+namespace Manta {
+
+CompressedTex gNoiseTex;
+
+//! synthesize uniform K41 curl noise onto node list
+__global__ void KnSynthesizeK41(CVec3Ptr nodes, CVec3Ptr tex1, CVec3Ptr tex2, Real alpha, float* ke,
+ CudaNoiseDev noise, const int octaves, const float iL0, const float str, const int len, const float kmin)
+{
+ const int nodeIdx = threadIdx.x + blockDim.x * blockIdx.x;
+ if (nodeIdx >= len) return;
+
+ // load from array
+ float3 p = nodes.get(nodeIdx);
+ float3 tc1 = tex1.get(nodeIdx);
+ float3 tc2 = tex2.get(nodeIdx);
+ float k = ke ? ke[nodeIdx] : 1.0f;
+ //tc1=p; // static
+ k = k - kmin;
+ k = (k<0.0f) ? 0.0f : sqrtf(k);
+
+ // interpolate texcoords
+ /*float3 tc = alpha * tc1 + (1.0f-alpha) * tc2;
+ float3 v = noise.synthesizeK41(gNoiseTex, tc, octaves, L0);*/
+
+ // interpolate velocities
+ float3 v1 = noise.synthesizeK41(gNoiseTex, tc1, octaves, iL0);
+ float3 v2 = noise.synthesizeK41(gNoiseTex, tc2, octaves, iL0);
+ float3 v = alpha * v1 + (1.0f-alpha) * v2;
+
+ // apply
+ float3 update = (str * k) * v;
+ p += update;
+ tc1 += update;
+ tc2 += update;
+
+ // writeback
+ nodes.set(nodeIdx, p);
+ tex1.set(nodeIdx, tc1);
+ tex2.set(nodeIdx, tc2);
+}
+
+//! synthesize K41 curl noise onto mesh
+PYTHON void synthesizeK41(VortexSheetMesh& mesh, Grid<Real>* k = NULL,
+ Real scale = 1.0, Real L0 = 0.1, int octaves=3, Real switchLength = 10.0, bool hardReset=false, Real minIntensity=0.1)
+{
+ const int blockSize = 256;
+ const int blocks = (mesh.numNodes()-1)/blockSize+1;
+ const float dt = parent->getDt();
+ const float str = dt * scale;
+ const float kmin = 1.5 * square(minIntensity);
+
+ // hat function over time
+ static float ctime = 0;
+ float oldAlpha = 2.0f*nmod(ctime/switchLength, 1.0f);
+ ctime += parent->getDt();
+ float alpha = 2.0f*nmod(ctime/switchLength, 1.0f);
+ if (hardReset) {
+ if (oldAlpha > alpha) mesh.resetTex1();
+ alpha = 1.0f;
+ } else {
+ if (oldAlpha < 1.0f && alpha >= 1.0f) mesh.resetTex2();
+ if (oldAlpha > alpha) mesh.resetTex1();
+ if (alpha>1.0f) alpha=2.0f-alpha;
+ }
+
+ // create noise tex on first call
+ static CudaNoiseTexture noise;
+
+ // upload data
+ CVec3Array nodes(mesh.numNodes());
+ CVec3Array tc1(mesh.numNodes()), tc2(mesh.numNodes());
+ CArray<float> ke(mesh.numNodes());
+ for (int i=0; i<mesh.numNodes(); i++) {
+ nodes.set(i, mesh.nodes(i).pos);
+ tc1.set(i, mesh.tex1(i));
+ tc2.set(i, mesh.tex2(i));
+ }
+ nodes.upload();
+ tc1.upload();
+ tc2.upload();
+ if (k) {
+ for (int i=0; i<mesh.numNodes(); i++)
+ ke.set(i, k->getInterpolated(mesh.nodes(i).pos));
+ ke.upload();
+ }
+ KnSynthesizeK41<<<blocks, blockSize>>> (nodes.data(), tc1.data(), tc2.data(), alpha, k ? (ke.data()) : 0,
+ noise.bind(gNoiseTex), octaves, 1.0f/L0, str, mesh.numNodes(), kmin);
+
+ // download data
+ nodes.download();
+ tc1.download();
+ tc2.download();
+ for (int i=0; i<mesh.numNodes(); i++) {
+ if (!mesh.isNodeFixed(i)) {
+ mesh.nodes(i).pos = nodes[i];
+ mesh.tex1(i) = tc1[i];
+ mesh.tex2(i) = tc2[i];
+ }
+ }
+}
+
+//! Kernel: synthesize uniform K41 curl noise onto grid
+__global__ void KnSynthesizeGridK41(CVec3Ptr nodes, CudaNoiseDev noise, const int octaves, const float iL0, const float str, int stridey, int stridez)
+{
+ int3 cell = make_int3(threadIdx.x + blockDim.x*blockIdx.x, threadIdx.y + blockDim.y*blockIdx.y, threadIdx.z + blockDim.z*blockIdx.z);
+ float3 p = make_float3(cell.x , cell.y , cell.z );
+
+ // interpolate velocities
+ float3 v = noise.synthesizeK41(gNoiseTex, p, octaves, iL0);
+
+ // writeback
+ nodes.set(cell.x + stridey* cell.y + stridez* cell.z, str*v);
+}
+
+//! synthesize K41 curl noise onto grid
+PYTHON void synthesizeK41Grid(MACGrid& vel, MACGrid& dst, Real scale = 1.0, Real L0 = 0.1, int octaves=3)
+{
+ const float dt = parent->getDt();
+ const float str = dt * scale;
+
+ // create noise tex on first call
+ static CudaNoiseTexture noise;
+
+ // upload data
+ const Vec3i gridRes = parent->getGridSize();
+ const int num = vel.getSizeX()*vel.getSizeY()*vel.getSizeZ();
+ CVec3Array nodes(num);
+ nodes.upload();
+
+ dim3 blocksize(8, 8, 8);
+ dim3 blocks((gridRes.x-1)/8+1, (gridRes.y-1)/8+1, (gridRes.z-1)/8+1);
+ KnSynthesizeGridK41<<<blocks, blocksize>>> (nodes.data(), noise.bind(gNoiseTex), octaves, 1.0f/L0, str, vel.getStrideY(), vel.getStrideZ());
+
+ nodes.download();
+ Grid<Vec3> center(parent);
+ MACGrid mac(parent);
+ for (int i=0; i<num; i++)
+ center[i] = nodes[i];
+
+ GetMAC(mac, center);
+ dst = vel;
+ dst += (Grid<Vec3>&)mac;
+}
+
+} // namespace \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/edgecollapse.cpp b/source/blender/python/manta_full/source/edgecollapse.cpp
new file mode 100644
index 00000000000..a2ef21d8f57
--- /dev/null
+++ b/source/blender/python/manta_full/source/edgecollapse.cpp
@@ -0,0 +1,666 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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) throw Error("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) throw Error("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)
+ throw Error("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 \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/edgecollapse.h b/source/blender/python/manta_full/source/edgecollapse.h
new file mode 100644
index 00000000000..1b704d56ac7
--- /dev/null
+++ b/source/blender/python/manta_full/source/edgecollapse.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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);
+
+}
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/fastmarch.cpp b/source/blender/python/manta_full/source/fastmarch.cpp
new file mode 100644
index 00000000000..a801732f33b
--- /dev/null
+++ b/source/blender/python/manta_full/source/fastmarch.cpp
@@ -0,0 +1,424 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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(FlagGrid& flags, Grid<int>& fmFlags, LevelsetGrid& levelset, Real maxTime,
+ MACGrid* velTransport, Grid<Real>* velMag )
+ : mLevelset(levelset), mFlags(flags), mFmFlags(fmFlags)
+{
+ if (velTransport)
+ mVelTransport.initMarching(velTransport, &flags);
+ if (velMag)
+ mMagTransport.initMarching(velMag, &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:
+ throw Error("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 int 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;
+
+ if (mVelTransport.isInitialized())
+ mVelTransport.transpTouch(p.x, p.y, p.z, mWeights, ttime);
+ if (mMagTransport.isInitialized())
+ mMagTransport.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
+KERNEL(single)
+void SetLevelsetBoundaries (LevelsetGrid& 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);
+ }
+}
+
+/*****************************************************************************/
+//! 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);
+}
+
+// explicit instantiation
+template class FastMarch<FmHeapEntryIn, -1>;
+template class FastMarch<FmHeapEntryOut, +1>;
+
+
+/*****************************************************************************/
+// simpler extrapolation functions (primarily for FLIP)
+
+KERNEL(bnd=1)
+void knExtrapolateMACSimple (MACGrid& vel, int distance , Grid<int>& tmp , const int d , const int c )
+{
+ 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;
+ }
+}
+KERNEL(bnd=0)
+void knExtrapolateIntoBnd (FlagGrid& flags, MACGrid& vel)
+{
+ int c=0;
+ Vec3 v(0,0,0);
+ if( i==0 ) {
+ v = vel(i+1,j,k);
+ if(v[0] < 0.) v[0] = 0.;
+ c++;
+ }
+ else if( i==(flags.getSizeX()-1) ) {
+ v = vel(i-1,j,k);
+ if(v[0] > 0.) v[0] = 0.;
+ c++;
+ }
+ if( j==0 ) {
+ v = vel(i,j+1,k);
+ if(v[1] < 0.) v[1] = 0.;
+ c++;
+ }
+ else if( j==(flags.getSizeY()-1) ) {
+ v = vel(i,j-1,k);
+ if(v[1] > 0.) v[1] = 0.;
+ c++;
+ }
+ if(flags.is3D()) {
+ if( k==0 ) {
+ v = vel(i,j,k+1);
+ if(v[2] < 0.) v[2] = 0.;
+ c++;
+ }
+ else if( k==(flags.getSizeY()-1) ) {
+ v = vel(i,j,k-1);
+ if(v[2] > 0.) v[2] = 0.;
+ c++;
+ } }
+ if(c>0) {
+ vel(i,j,k) = v/(Real)c;
+ }
+}
+
+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) );
+}
+KERNEL(bnd=1)
+void knUnprojectNormalComp (FlagGrid& flags, MACGrid& vel, LevelsetGrid& phi, Real maxDist)
+{
+ // 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;
+ }
+}
+// a simple extrapolation step , used for cases where there's no levelset
+// (note, less accurate than fast marching extrapolation!)
+PYTHON void extrapolateMACSimple (FlagGrid& flags, MACGrid& vel, int distance = 4, LevelsetGrid* phiObs=NULL )
+{
+ 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
+ FOR_IJK_BND(flags,1) {
+ Vec3i p(i,j,k);
+ if (flags.isFluid(p) || flags.isFluid(p-dir) ) {
+ tmp(p) = 1;
+ }
+ }
+
+ // debug init! , enable for testing only - set varying velocities inside
+ //FOR_IJK_BND(flags,1) { if (tmp(i,j,k) == 0) continue; vel(i,j,k)[c] = (i+j+k+c+1.)*0.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
+ knExtrapolateIntoBnd(flags, vel);
+}
+
+KERNEL(bnd=1)
+void knExtrapolateMACFromWeight ( MACGrid& vel, Grid<Vec3>& weight, int distance , const int d, const int c )
+{
+ 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;
+ }
+}
+// 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
+PYTHON 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
+
+ }
+}
+
+} // namespace
diff --git a/source/blender/python/manta_full/source/fastmarch.h b/source/blender/python/manta_full/source/fastmarch.h
new file mode 100644
index 00000000000..a6f7759097e
--- /dev/null
+++ b/source/blender/python/manta_full/source/fastmarch.h
@@ -0,0 +1,196 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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, 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;
+ //if(!mpVal) return;
+
+ T val = fmInterpolateNeighbors<GRID,T>(mpVal,x,y,z,weights); /*T(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];
+ }*/
+
+ // 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; }
+ //(*mpVal)(x,y,z).x = val.x;
+ //(*mpVal)(x,y,z).y = val.y;
+ //if(mpVal->is3D()) { (*mpVal)(x,y,z).z = val.z; }
+ };
+
+protected:
+ GRID* mpVal;
+ 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(FlagGrid& flags, Grid<int>& fmFlags, LevelsetGrid& levelset, Real maxTime,
+ MACGrid* velTransport = NULL, Grid<Real>* velMag = 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:
+ LevelsetGrid& mLevelset;
+ FlagGrid& mFlags;
+ Grid<int>& mFmFlags;
+
+ //! velocity extrpolation
+ FmValueTransportVec3<MACGrid , Vec3> mVelTransport;
+ FmValueTransportScalar<Grid<Real>, Real> mMagTransport;
+
+ //! 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
+#endif
+
diff --git a/source/blender/python/manta_full/source/fileio.cpp b/source/blender/python/manta_full/source/fileio.cpp
new file mode 100644
index 00000000000..dd1557f397c
--- /dev/null
+++ b/source/blender/python/manta_full/source/fileio.cpp
@@ -0,0 +1,700 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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 "fileio.h"
+#include "grid.h"
+#include "mesh.h"
+#include "vortexsheet.h"
+#include "particle.h"
+#include <cstring>
+
+using namespace std;
+
+namespace Manta {
+
+//*****************************************************************************
+// mesh data
+//*****************************************************************************
+
+void writeBobjFile(const string& name, Mesh* mesh) {
+ cout << "writing mesh file " << name << endl;
+# 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
+ 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
+ cout << "file format not supported without zlib" << endl;
+# 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();
+ 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, ignore
+ } 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();
+}
+
+void writeObjFile(const string& name, Mesh* mesh) {
+ errMsg("obj exporter not yet implemented");
+}
+
+//*****************************************************************************
+// grid data
+//*****************************************************************************
+
+template<class T>
+void writeGridTxt(const string& name, Grid<T>* grid) {
+ cout << "writing grid " << grid->getName() << " to text file " << name << endl;
+
+ ofstream ofs(name.c_str());
+ if (!ofs.good())
+ errMsg("can't open file!");
+ 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) {
+ cout << "writing grid " << grid->getName() << " to raw file " << name << endl;
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file");
+ gzwrite(gzf, &((*grid)[0]), sizeof(T)*grid->getSizeX()*grid->getSizeY()*grid->getSizeZ());
+ gzclose(gzf);
+# else
+ cout << "file format not supported without zlib" << endl;
+# endif
+}
+
+template<class T>
+void readGridRaw(const string& name, Grid<T>* grid) {
+ cout << "reading grid " << grid->getName() << " from raw file " << name << endl;
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("can't open file");
+
+ int bytes = sizeof(T)*grid->getSizeX()*grid->getSizeY()*grid->getSizeZ();
+ int 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
+ cout << "file format not supported without zlib" << endl;
+# 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;
+
+//! uni file header
+typedef struct {
+ int dimX, dimY, dimZ; // grid size
+ int gridType, elementType, bytesPerElement; // data type info
+ char info[256]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+} UniHeader;
+
+//! for test run debugging
+PYTHON() void printUniFileInfoString(const string& name) {
+# 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);
+ if (!strcmp(ID, "MNT2")) {
+ UniHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader), "can't read file, no header present");
+ gzclose(gzf);
+ debMsg("File '"<<name<<"' info: "<< head.info ,1);
+ return; // all good!
+ }
+ gzclose(gzf);
+ }
+# endif
+ debMsg("File '"<<name<<"', no valid info string found",1);
+}
+
+//! for auto-init & check of results of test runs
+PYTHON() Vec3 getUniFileSize(const string& name) {
+ Vec3 s(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);
+ if (!strcmp(ID, "MNT2")) {
+ UniHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader), "can't read file, no header present");
+ s = Vec3(head.dimX,head.dimY,head.dimZ);
+ }
+ gzclose(gzf);
+ }
+# endif
+ return s;
+}
+
+#if NO_ZLIB!=1
+template <class T>
+void convertDoubleAndWrite(Grid<T>& grid, void* ptr, gzFile& gzf, UniHeader& head) {
+ errMsg("unknown type, not yet supported");
+}
+
+template <>
+void convertDoubleAndWrite(Grid<int>& grid, void* ptr, gzFile& gzf, UniHeader& head) {
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, ptr, sizeof(int)*head.dimX*head.dimY*head.dimZ);
+}
+
+template <>
+void convertDoubleAndWrite(Grid<double>& grid, void* ptr, gzFile& gzf, 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 convertDoubleAndWrite(Grid<Vector3D<double> >& grid, void* ptr, gzFile& gzf, 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(float)*3 *head.dimX*head.dimY*head.dimZ);
+}
+#endif // NO_ZLIB!=1
+
+template <class T>
+void writeGridUni(const string& name, Grid<T>* grid) {
+ cout << "writing grid " << grid->getName() << " to uni file " << name << endl;
+
+# if NO_ZLIB!=1
+ char ID[5] = "MNT2";
+ UniHeader head;
+ head.dimX = grid->getSizeX();
+ head.dimY = grid->getSizeY();
+ head.dimZ = grid->getSizeZ();
+ head.gridType = grid->getType();
+ head.bytesPerElement = sizeof(T);
+ snprintf( head.info, 256, "%s", buildInfoString().c_str() );
+ MuTime stamp; stamp.get();
+ 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("unknown element type");
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file");
+
+ gzwrite(gzf, ID, 4);
+ void* ptr = &((*grid)[0]);
+# 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)
+ //ptr = &(temp[0]);
+ //float* ptrf = (float*)ptr;
+ convertDoubleAndWrite( *grid, &(temp[0]), gzf, head);
+# endif
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, ptr, sizeof(T)*head.dimX*head.dimY*head.dimZ);
+ gzclose(gzf);
+# else
+ cout << "file format not supported without zlib" << endl;
+# endif
+};
+
+// grid conversion functions for double precision
+template <class T>
+void convertFloatGridToDouble(Grid<T>& grid, void* ptr, int bytesPerElement) {
+ errMsg("unknown type, not yet supported");
+}
+
+template <>
+void convertFloatGridToDouble<int>(Grid<int>& grid, void* ptr, int bytesPerElement) {
+ 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 convertFloatGridToDouble<double>(Grid<double>& grid, void* ptr, int bytesPerElement) {
+ 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 convertFloatGridToDouble<Vec3>(Grid<Vec3>& grid, void* ptr, int bytesPerElement) {
+ 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;
+ }
+}
+
+// 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;
+}
+
+template <class T>
+void readGridUni(const string& name, Grid<T>* grid) {
+ cout << "reading grid " << grid->getName() << " from uni file " << name << endl;
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("can't open file");
+
+ 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")) {
+ // 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]);
+ gzread(gzf, ptr, sizeof(T)*head.dimX*head.dimY*head.dimZ);
+ convertFloatGridToDouble<T>(*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
+ }
+ gzclose(gzf);
+# else
+ cout << "file format not supported without zlib" << endl;
+# endif
+};
+
+template <class T>
+void writeGridVol(const string& name, Grid<T>* grid) {
+ cout << "writing grid " << grid->getName() << " to vol file " << name << endl;
+ errMsg("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) {
+ cout << "writing real grid " << grid->getName() << " to vol file " << name << endl;
+
+ 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("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);
+};
+
+
+//*****************************************************************************
+// particle data
+//*****************************************************************************
+
+//! in line with grid uni 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[256]; // mantaflow build information
+ unsigned long timestamp; // creation time
+} UniPartHeader;
+
+template <class T>
+void writeParticlesUni(const std::string& name, BasicParticleSystem* parts ) {
+ cout << "writing particles " << parts->getName() << " to uni file " << name << endl;
+
+# 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 = sizeof(T);
+ head.elementType = 0; // 0 for base data
+ snprintf( head.info, 256, "%s", buildInfoString().c_str() );
+ MuTime stamp; stamp.get();
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file");
+
+ gzwrite(gzf, ID, 4);
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &(parts->getData()[0]), sizeof(T)*head.dim);
+ gzclose(gzf);
+# else
+ cout << "file format not supported without zlib" << endl;
+# endif
+};
+
+template <class T>
+void readParticlesUni(const std::string& name, BasicParticleSystem* parts ) {
+ cout << "reading particles " << parts->getName() << " from uni file " << name << endl;
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("can't open file");
+
+ 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 == sizeof(T)) && (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");
+ int bytes = sizeof(T)*head.dim;
+ int readBytes = gzread(gzf, &(parts->getData()[0]), sizeof(T)*head.dim);
+ assertMsg(bytes==readBytes, "can't read uni file, stream length does not match, "<<bytes<<" vs "<<readBytes );
+
+ parts->transformPositions( Vec3i(head.dimX,head.dimY,head.dimZ), parts->getParent()->getGridSize() );
+ }
+ gzclose(gzf);
+# else
+ cout << "file format not supported without zlib" << endl;
+# endif
+};
+
+template <class T>
+void writePdataUni(const std::string& name, ParticleDataImpl<T>* pdata ) {
+ cout << "writing particle data " << pdata->getName() << " to uni file " << name << endl;
+
+# if NO_ZLIB!=1
+ char ID[5] = "PD01";
+ UniPartHeader head;
+ head.dim = pdata->size();
+ head.bytesPerElement = sizeof(T);
+ head.elementType = 1; // 1 for particle data, todo - add sub types?
+ snprintf( head.info, 256, "%s", buildInfoString().c_str() );
+ MuTime stamp; stamp.get();
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file");
+
+ gzwrite(gzf, ID, 4);
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &(pdata->get(0)), sizeof(T)*head.dim);
+ gzclose(gzf);
+# else
+ cout << "file format not supported without zlib" << endl;
+# endif
+};
+
+template <class T>
+void readPdataUni(const std::string& name, ParticleDataImpl<T>* pdata ) {
+ cout << "reading particle data " << pdata->getName() << " from uni file " << name << endl;
+
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "rb");
+ if (!gzf) errMsg("can't open file");
+
+ 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.bytesPerElement == sizeof(T)) && (head.elementType==1) ), "pdata type doesn't match");
+ assertMsg (head.dim == pdata->size() , "pdata size doesn't match");
+ int bytes = sizeof(T)*head.dim;
+ int 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 );
+ }
+ gzclose(gzf);
+# else
+ cout << "file format not supported without zlib" << endl;
+# endif
+}
+
+// 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 writeParticlesUni<BasicParticleData>(const std::string& name, BasicParticleSystem* parts );
+template void readParticlesUni<BasicParticleData> (const std::string& name, BasicParticleSystem* parts );
+
+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 );
+
+#if ENABLE_GRID_TEST_DATATYPE==1
+// dummy functions for test datatype - not really supported right now!
+// but we need some function body for linking
+template<> void writeGridRaw<nbVector>(const string& name, Grid<nbVector>* grid) {assertMsg(false,"Not supported right now.");};
+template<> void writeGridUni<nbVector>(const string& name, Grid<nbVector>* grid) {assertMsg(false,"Not supported right now.");};
+template<> void writeGridVol<nbVector>(const string& name, Grid<nbVector>* grid) {assertMsg(false,"Not supported right now.");};
+template<> void writeGridTxt<nbVector>(const string& name, Grid<nbVector>* grid) {assertMsg(false,"Not supported right now.");};
+template<> void readGridRaw<nbVector> (const string& name, Grid<nbVector>* grid) {assertMsg(false,"Not supported right now.");};
+template<> void readGridUni<nbVector> (const string& name, Grid<nbVector>* grid) {assertMsg(false,"Not supported right now.");};
+#endif // ENABLE_GRID_TEST_DATATYPE
+
+
+} //namespace
diff --git a/source/blender/python/manta_full/source/fileio.h b/source/blender/python/manta_full/source/fileio.h
new file mode 100644
index 00000000000..26c206629ac
--- /dev/null
+++ b/source/blender/python/manta_full/source/fileio.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
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * 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;
+class BasicParticleSystem;
+template<class T> class ParticleDataImpl;
+
+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);
+
+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);
+
+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 writeParticlesUni(const std::string& name, BasicParticleSystem* parts );
+template <class T> 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 );
+
+} // namespace
+
+#endif
diff --git a/source/blender/python/manta_full/source/flip.cpp b/source/blender/python/manta_full/source/flip.cpp
new file mode 100644
index 00000000000..56046349a28
--- /dev/null
+++ b/source/blender/python/manta_full/source/flip.cpp
@@ -0,0 +1,487 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * FLIP (fluid implicit particles)
+ * for use with particle data fields
+ *
+ ******************************************************************************/
+
+#include "particle.h"
+#include "grid.h"
+#include "randomstream.h"
+#include "levelset.h"
+
+using namespace std;
+namespace Manta {
+
+
+
+
+// init
+
+PYTHON void sampleFlagsWithParticles( FlagGrid& flags, BasicParticleSystem& parts,
+ int discretization, Real randomness )
+{
+ bool is3D = flags.is3D();
+ Real jlen = randomness / discretization;
+ Vec3 disp (1.0 / discretization, 1.0 / discretization, 1.0/discretization);
+ RandomStream mRand(9832);
+
+ //clear();
+
+ FOR_IJK_BND(flags, 0) {
+ if ( flags.isObstacle(i,j,k) ) continue;
+ if ( flags.isFluid(i,j,k) ) {
+ 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.add( BasicParticleData(subpos) );
+ }
+ }
+ }
+}
+
+PYTHON void sampleLevelsetWithParticles( LevelsetGrid& phi, FlagGrid& flags, BasicParticleSystem& parts,
+ int discretization, Real randomness )
+{
+ bool is3D = phi.is3D();
+ Real jlen = randomness / discretization;
+ Vec3 disp (1.0 / discretization, 1.0 / discretization, 1.0/discretization);
+ RandomStream mRand(9832);
+
+ //clear();
+
+ FOR_IJK_BND(phi, 0) {
+ if ( flags.isObstacle(i,j,k) ) continue;
+ if ( phi(i,j,k) < 1.733 ) {
+ 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;
+ parts.add( BasicParticleData(subpos) );
+ }
+ }
+ }
+}
+
+PYTHON void markFluidCells(BasicParticleSystem& parts, FlagGrid& flags) {
+ // remove all fluid cells
+ FOR_IJK(flags) {
+ if (flags.isFluid(i,j,k)) {
+ flags(i,j,k) = (flags(i,j,k) | FlagGrid::TypeEmpty) & ~FlagGrid::TypeFluid;
+ }
+ }
+
+ // mark all particles in flaggrid as fluid
+ for(int idx=0;idx<parts.size();idx++) {
+ if (!parts.isActive(idx)) continue;
+ Vec3i p = toVec3i( parts.getPos(idx) );
+ if (flags.isInBounds(p) && flags.isEmpty(p))
+ flags(p) = (flags(p) | FlagGrid::TypeFluid) & ~FlagGrid::TypeEmpty;
+ }
+}
+
+// for testing purposes only...
+PYTHON void testInitGridWithPos(Grid<Real>& grid) {
+ FOR_IJK(grid) { grid(i,j,k) = norm( Vec3(i,j,k) ); }
+}
+
+
+//! helper to calculate particle radius factor to cover the diagonal of a cell in 2d/3d
+inline Real calculateRadiusFactor(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
+PYTHON void adjustNumber( BasicParticleSystem& parts, MACGrid& vel, FlagGrid& flags,
+ int minParticles, int maxParticles, LevelsetGrid& phi, Real radiusFactor=1. )
+{
+ // 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 (int 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;
+ }
+ int num = tmp(p);
+
+ bool atSurface = false;
+ Real phiv = phi.getInterpolated( parts.getPos(idx) );
+ if (phiv > SURFACE_LS) atSurface = true;
+
+ // 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 (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();
+}
+
+// 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)
+PYTHON void debugIntToReal( Grid<int>& source, Grid<Real>& dest, Real factor=1. )
+{
+ FOR_IJK( source ) { dest(i,j,k) = (Real)source(i,j,k) * factor; }
+}
+
+// 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)] alreadu belongs to cell i+1,j,k)
+PYTHON void gridParticleIndex( BasicParticleSystem& parts, ParticleIndexSystem& indexSys,
+ 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 (int idx=0; idx<(int)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
+ int 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 (int idx=0; idx<(int)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;
+}
+
+KERNEL
+void ComputeUnionLevelsetPindex(Grid<int>& index, BasicParticleSystem& parts, ParticleIndexSystem& indexSys,
+ LevelsetGrid& phi, Real radius=1.)
+{
+ const Vec3 gridPos = Vec3(i,j,k) + Vec3(0.5); // shifted by half cell
+ Real phiv = radius * 1.732; // 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)
+ int isysIdxS = phi.index(xj,yj,zj);
+ int 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(int p=pStart; p<pEnd; ++p) {
+ const int psrc = indexSys[p].sourceIndex;
+ const Vec3 pos = parts[psrc].pos;
+ phiv = std::min( phiv , fabs( norm(gridPos-pos) )-radius );
+ }
+ }
+ phi(i,j,k) = phiv;
+}
+
+PYTHON void unionParticleLevelset( BasicParticleSystem& parts, ParticleIndexSystem& indexSys,
+ FlagGrid& flags, Grid<int>& index, LevelsetGrid& phi, Real radiusFactor=1. )
+{
+ // 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);
+}
+
+
+KERNEL
+void ComputeAveragedLevelsetWeight(BasicParticleSystem& parts,
+ Grid<int>& index, ParticleIndexSystem& indexSys,
+ LevelsetGrid& phi, Real radius=1.)
+{
+ const Vec3 gridPos = Vec3(i,j,k) + Vec3(0.5); // shifted by half cell
+ Real phiv = radius * 1.732; // 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;
+
+ int isysIdxS = phi.index(xj,yj,zj);
+ int pStart = index(isysIdxS), pEnd=0;
+ if(phi.isInBounds(isysIdxS+1)) pEnd = index(isysIdxS+1);
+ else pEnd = indexSys.size();
+ for(int p=pStart; p<pEnd; ++p) {
+ int psrc = indexSys[p].sourceIndex;
+ Vec3 pos = parts[psrc].pos;
+ Real s = normSquare(gridPos-pos) * sradiusInv;
+ Real w = std::max(0., cubed(1.-s) );
+ wacc += w;
+ racc += radius * w;
+ pacc += pos * w;
+ }
+ }
+
+ if(wacc > VECTOR_EPSILON) {
+ racc /= wacc;
+ pacc /= wacc;
+ phiv = fabs( norm(gridPos-pacc) )-racc;
+ }
+ phi(i,j,k) = phiv;
+}
+
+// smoothing, and
+KERNEL(bnd=1) template<class T>
+void knSmoothGrid(Grid<T>& me, Grid<T>& tmp, Real factor) {
+ 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;
+}
+
+KERNEL(bnd=1) template<class T>
+void knSmoothGridNeg(Grid<T>& me, Grid<T>& tmp, Real factor) {
+ 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);
+}
+
+
+PYTHON void averagedParticleLevelset( BasicParticleSystem& parts, ParticleIndexSystem& indexSys,
+ FlagGrid& flags, Grid<int>& index, LevelsetGrid& phi, Real radiusFactor=1. ,
+ int smoothen=1 , int smoothenNeg=1 )
+{
+ // use half a cell diagonal as base radius
+ const Real radius = 0.5 * calculateRadiusFactor(phi, radiusFactor);
+ ComputeAveragedLevelsetWeight(parts, index, indexSys, phi, radius);
+
+ // post-process level-set
+ for(int i=0; i<smoothen; ++i) {
+ LevelsetGrid tmp(flags.getParent());
+ knSmoothGrid<Real>(phi,tmp, 1./(phi.is3D() ? 7. : 5.) );
+ phi.swap(tmp);
+ }
+ for(int i=0; i<smoothenNeg; ++i) {
+ LevelsetGrid tmp(flags.getParent());
+ knSmoothGridNeg<Real>(phi,tmp, 1./(phi.is3D() ? 7. : 5.) );
+ phi.swap(tmp);
+ }
+ // NT_DEBUG , todo copy border
+}
+
+
+
+
+//******************************************************************************
+// grid interpolation functions
+
+KERNEL(idx) template<class T>
+void knSafeDivReal(Grid<T>& me, const Grid<Real>& other, Real cutoff=VECTOR_EPSILON) {
+ if(other[idx]<cutoff) {
+ me[idx] = 0.;
+ } else {
+ T div( other[idx] );
+ me[idx] = safeDivide(me[idx], div );
+ }
+}
+
+// Set velocities on the grid from the particle system
+
+KERNEL(idx)
+void knStompVec3PerComponent(Grid<Vec3>& grid, Real threshold) {
+ if(grid[idx][0] < threshold) grid[idx][0] = 0.;
+ if(grid[idx][1] < threshold) grid[idx][1] = 0.;
+ if(grid[idx][2] < threshold) grid[idx][2] = 0.;
+}
+
+KERNEL(pts, single)
+void knMapLinearVec3ToMACGrid( BasicParticleSystem& p, FlagGrid& flags, MACGrid& vel, Grid<Vec3>& tmp,
+ ParticleDataImpl<Vec3>& pvel )
+{
+ unusedParameter(flags);
+ if (!p.isActive(idx)) return;
+ vel.setInterpolated( p[idx].pos, pvel[idx], &tmp[0] );
+}
+
+// optionally , this function can use an existing vec3 grid to store the weights
+// this is useful in combination with the simple extrapolation function
+PYTHON void mapPartsToMAC( FlagGrid& flags, MACGrid& vel , MACGrid& velOld ,
+ BasicParticleSystem& parts , ParticleDataImpl<Vec3>& partVel , Grid<Vec3>* weight=NULL )
+{
+ // 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 );
+
+ // stomp small values in weight to zero to prevent roundoff errors
+ knStompVec3PerComponent( *weight, VECTOR_EPSILON );
+ vel.safeDivide(*weight);
+
+ // store original state
+ velOld = vel;
+ if(freeTmp) delete weight;
+}
+
+
+KERNEL(pts, single) template<class T>
+void knMapLinear( BasicParticleSystem& p, FlagGrid& flags, Grid<T>& target, Grid<Real>& gtmp,
+ ParticleDataImpl<T>& psource )
+{
+ unusedParameter(flags);
+ if (!p.isActive(idx)) return;
+ target.setInterpolated( p[idx].pos, psource[idx], gtmp );
+}
+template<class T>
+void mapLinearRealHelper( FlagGrid& flags, Grid<T>& target ,
+ BasicParticleSystem& parts , ParticleDataImpl<T>& source )
+{
+ Grid<Real> tmp(flags.getParent());
+ target.clear();
+ knMapLinear<T>( parts, flags, target, tmp, source );
+ knSafeDivReal<T>( target, tmp );
+}
+
+PYTHON void mapPartsToGrid ( FlagGrid& flags, Grid<Real>& target , BasicParticleSystem& parts , ParticleDataImpl<Real>& source ) {
+ mapLinearRealHelper<Real>(flags,target,parts,source);
+}
+PYTHON void mapPartsToGridVec3( FlagGrid& flags, Grid<Vec3>& target , BasicParticleSystem& parts , ParticleDataImpl<Vec3>& source ) {
+ mapLinearRealHelper<Vec3>(flags,target,parts,source);
+}
+// 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);
+//}
+
+KERNEL(pts) template<class T>
+void knMapFromGrid( BasicParticleSystem& p, Grid<T>& gsrc, ParticleDataImpl<T>& target )
+{
+ if (!p.isActive(idx)) return;
+ target[idx] = gsrc.getInterpolated( p[idx].pos );
+}
+PYTHON void mapGridToParts ( Grid<Real>& source , BasicParticleSystem& parts , ParticleDataImpl<Real>& target ) {
+ knMapFromGrid<Real>(parts, source, target);
+}
+PYTHON void mapGridToPartsVec3( Grid<Vec3>& source , BasicParticleSystem& parts , ParticleDataImpl<Vec3>& target ) {
+ knMapFromGrid<Vec3>(parts, source, target);
+}
+
+
+// Get velocities from grid
+
+KERNEL(pts)
+void knMapLinearMACGridToVec3_PIC( BasicParticleSystem& p, FlagGrid& flags, MACGrid& vel, ParticleDataImpl<Vec3>& pvel )
+{
+ if (!p.isActive(idx)) return;
+ // pure PIC
+ pvel[idx] = vel.getInterpolated( p[idx].pos );
+}
+PYTHON void mapMACToParts(FlagGrid& flags, MACGrid& vel ,
+ BasicParticleSystem& parts , ParticleDataImpl<Vec3>& partVel ) {
+ knMapLinearMACGridToVec3_PIC( parts, flags, vel, partVel );
+}
+
+// with flip delta interpolation
+KERNEL(pts)
+void knMapLinearMACGridToVec3_FLIP( BasicParticleSystem& p, FlagGrid& flags, MACGrid& vel, MACGrid& oldVel, ParticleDataImpl<Vec3>& pvel , Real flipRatio)
+{
+ if (!p.isActive(idx)) 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;
+}
+
+PYTHON void flipVelocityUpdate(FlagGrid& flags, MACGrid& vel , MACGrid& velOld ,
+ BasicParticleSystem& parts , ParticleDataImpl<Vec3>& partVel , Real flipRatio ) {
+ knMapLinearMACGridToVec3_FLIP( parts, flags, vel, velOld, partVel, flipRatio );
+}
+
+
+} // namespace
+
diff --git a/source/blender/python/manta_full/source/flip.h b/source/blender/python/manta_full/source/flip.h
new file mode 100644
index 00000000000..c427a97df24
--- /dev/null
+++ b/source/blender/python/manta_full/source/flip.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * FLIP (fluid implicit particles)
+ *
+ ******************************************************************************/
+
+#ifndef _FLIP_H
+#define _FLIP_H
+
+namespace Manta {
+
+// todo remove this file, not needed anymore...
+
+} // namespace
+
+#endif
diff --git a/source/blender/python/manta_full/source/fluidsolver.cpp b/source/blender/python/manta_full/source/fluidsolver.cpp
new file mode 100644
index 00000000000..1e1557750b6
--- /dev/null
+++ b/source/blender/python/manta_full/source/fluidsolver.cpp
@@ -0,0 +1,172 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Main class for the fluid solver
+ *
+ ******************************************************************************/
+
+#include "fluidsolver.h"
+#include "grid.h"
+#include <sstream>
+#include <fstream>
+
+using namespace std;
+namespace Manta {
+
+#ifdef GUI
+ // defined in qtmain.cpp
+ extern void updateQtGui(bool full, int frame, const std::string& curPlugin);
+#else
+ inline void updateQtGui(bool full, int frame, const std::string& curPlugin) {}
+#endif
+
+//******************************************************************************
+// 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) {
+ grids.push_back(new T[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<> 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);
+}
+
+void FluidSolver::pluginStart(const string& name) {
+ mLastPlugin = name;
+ mPluginTimer.get();
+}
+
+void FluidSolver::pluginStop(const string& name) {
+ if (mLastPlugin == name && name != "FluidSolver::step") {
+ MuTime diff = mPluginTimer.update();
+ mTimings.push_back(pair<string,MuTime>(name, diff));
+ }
+}
+
+//******************************************************************************
+// FluidSolver members
+
+FluidSolver::FluidSolver(Vec3i gridsize, int dim)
+ : PbClass(this), mDt(1.0), mGridSize(gridsize), mDim(dim), mTimeTotal(0.), mScale(1.0), mFrame(0)
+{
+ assertMsg(dim==2 || dim==3, "Can only create 2D and 3D solvers");
+ assertMsg(dim!=2 || gridsize.z == 1, "Trying to create 2D solver with size.z != 1");
+}
+
+FluidSolver::~FluidSolver() {
+ mGridsInt.free();
+ mGridsReal.free();
+ mGridsVec.free();
+}
+
+PbClass* FluidSolver::create(PbType t, PbTypeVec T, const string& name) {
+ _args.add("nocheck",true);
+ if (t.str() == "")
+ errMsg("Need to specify object type. Use e.g. Solver.create(FlagGrid, ...) or Solver.create(type=FlagGrid, ...)");
+
+ return PbClass::createPyObject(t.str() + T.str(), name, _args, this);
+}
+
+void FluidSolver::step() {
+ mTimeTotal += mDt;
+ mFrame++;
+ updateQtGui(true, mFrame, "FluidSolver::step");
+
+ // update timings
+ for(size_t i=0;i<mTimings.size(); i++) {
+ const string name = mTimings[i].first;
+ if (mTimingsTotal.find(name) == mTimingsTotal.end())
+ mTimingsTotal[name].second.clear();
+ mTimingsTotal[name].first++;
+ mTimingsTotal[name].second+=mTimings[i].second;
+ }
+ mTimings.clear();
+}
+
+void FluidSolver::printTimings() {
+ MuTime total;
+ total.clear();
+ for(size_t i=0; i<mTimings.size(); i++)
+ total += mTimings[i].second;
+
+ printf("\n-- STEP %d -----------------------------\n", mFrame);
+ for(size_t i=0; i<mTimings.size(); i++)
+ printf("[%4.1f%%] %s (%s)\n", 100.0*((Real)mTimings[i].second.time / (Real)total.time), mTimings[i].first.c_str(), mTimings[i].second.toString().c_str());
+ printf("----------------------------------------\n");
+ printf("Total : %s\n\n", total.toString().c_str());
+}
+
+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() <<". ";
+ printf("%s\n", msg.str().c_str() );
+}
+
+PYTHON() void printBuildInfo() {
+ debMsg( "Build info: "<<buildInfoString().c_str()<<" ",1);
+}
+
+void FluidSolver::saveMeanTimings(string filename) {
+ ofstream ofs(filename.c_str());
+ if (!ofs.good())
+ errMsg("can't open " + filename + " as timing log");
+ ofs << "Mean timings of " << mFrame << " steps :" <<endl <<endl;
+ MuTime total;
+ total.clear();
+ for(map<string, pair<int,MuTime> >::iterator it=mTimingsTotal.begin(); it!=mTimingsTotal.end(); it++) {
+ total += it->second.second;
+ }
+ for(map<string, pair<int,MuTime> >::iterator it=mTimingsTotal.begin(); it!=mTimingsTotal.end(); it++) {
+ ofs << it->first << ": " << it->second.second / it->second.first << endl;
+ }
+ ofs << endl << "Total : " << total << " (mean " << total/mFrame << ")" << endl;
+ ofs.close();
+}
+
+}
+
diff --git a/source/blender/python/manta_full/source/fluidsolver.h b/source/blender/python/manta_full/source/fluidsolver.h
new file mode 100644
index 00000000000..f3fd9e29e7c
--- /dev/null
+++ b/source/blender/python/manta_full/source/fluidsolver.h
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Main class for the fluid solver
+ *
+ ******************************************************************************/
+
+#ifndef _FLUIDSOLVER_H
+#define _FLUIDSOLVER_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include <vector>
+#include <map>
+
+namespace Manta {
+
+//! Encodes grid size, timstep etc.
+PYTHON(name=Solver)
+class FluidSolver : public PbClass {
+public:
+ PYTHON FluidSolver(Vec3i gridSize, int dim=3);
+ virtual ~FluidSolver();
+
+ // accessors
+ PYTHON Vec3i getGridSize() { return mGridSize; }
+ inline Real getDt() { return mDt; }
+ inline Real getTime() { return mTimeTotal; }
+ inline Real getDx() { return 1.0 / mGridSize.max(); }
+ inline Real getScale() { return mScale; }
+ //! Check dimensionality
+ inline bool is2D() const { return mDim==2; }
+ //! Check dimensionality
+ inline bool is3D() const { return mDim==3; }
+
+ // Python callable methods
+ //! output performace statistics
+ PYTHON void printTimings();
+ PYTHON void saveMeanTimings(std::string filename);
+ PYTHON void printMemInfo();
+
+ //! Advance the solver one timestep, update GUI if present
+ PYTHON void step();
+
+ //! create a object with the solver as its parent
+ PYTHON PbClass* create(PbType type, PbTypeVec T=PbTypeVec(),const std::string& name = "");
+
+ // temp grid and plugin stuff: you shouldn't call this manually
+ template<class T> T* getGridPointer();
+ template<class T> void freeGridPointer(T* ptr);
+ void pluginStart(const std::string& name);
+ void pluginStop(const std::string& name);
+
+ PYTHON(name=timestep) Real mDt;
+protected:
+ //! 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;
+ };
+
+ Vec3i mGridSize;
+ const int mDim;
+ Real mTimeTotal, mScale;
+ int mFrame;
+
+ GridStorage<int> mGridsInt;
+ GridStorage<Real> mGridsReal;
+ GridStorage<Vec3> mGridsVec;
+
+ // for timing plugins
+ MuTime mPluginTimer;
+ std::string mLastPlugin;
+ std::vector<std::pair<std::string, MuTime> > mTimings;
+ std::map<std::string, std::pair<int,MuTime> > mTimingsTotal;
+};
+
+}
+
+#endif
diff --git a/source/blender/python/manta_full/source/general.cpp b/source/blender/python/manta_full/source/general.cpp
new file mode 100644
index 00000000000..e6218e677b1
--- /dev/null
+++ b/source/blender/python/manta_full/source/general.cpp
@@ -0,0 +1,128 @@
+ /******************************************************************************
+ *
+ * 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
+ *
+ * Globally used macros and functions
+ *
+ ******************************************************************************/
+
+#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 "hginfo.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;
+}
+
+std::string buildInfoString() {
+ std::ostringstream infoStr;
+ infoStr << "mantaflow";
+ // TODO , include hg branch info
+
+ // 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
+//# ifndef MANTA_HG_VERSION
+//# define MANTA_HG_VERSION "<unknown>"
+//# endif
+// infoStr << " hg "<< MANTA_HG_VERSION;
+//
+// infoStr << " from "<< __DATE__<<", "<<__TIME__;
+ return infoStr.str();
+}
+
+} // namespace
diff --git a/source/blender/python/manta_full/source/general.h b/source/blender/python/manta_full/source/general.h
new file mode 100644
index 00000000000..25ec2068ed0
--- /dev/null
+++ b/source/blender/python/manta_full/source/general.h
@@ -0,0 +1,138 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Globally used macros and functions
+ *
+ ******************************************************************************/
+
+#ifndef _GENERAL_H
+#define _GENERAL_H
+
+#include <iostream>
+#include <sstream>
+#include <cmath>
+
+namespace Manta {
+
+// 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) )
+
+// 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;
+}
+
+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
+
+#endif
diff --git a/source/blender/python/manta_full/source/grid.cpp b/source/blender/python/manta_full/source/grid.cpp
new file mode 100644
index 00000000000..9bde755f3fd
--- /dev/null
+++ b/source/blender/python/manta_full/source/grid.cpp
@@ -0,0 +1,445 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#include "grid.h"
+#include "levelset.h"
+#include "kernel.h"
+#include <limits>
+#include <sstream>
+#include <cstring>
+#include "fileio.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)
+{
+ 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(const Grid<T>& a) : GridBase(a.getParent()) {
+ 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() {
+ 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.");
+
+ 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
+ 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);
+ else if (ext == ".txt")
+ writeGridTxt(name, this);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+}
+
+//******************************************************************************
+// Grid<T> operators
+
+//! Kernel: Compute min value of Real grid
+KERNEL(idx, reduce=min) returns(Real minVal=std::numeric_limits<Real>::max())
+Real CompMinReal(Grid<Real>& val) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+}
+
+//! Kernel: Compute max value of Real grid
+KERNEL(idx, reduce=max) returns(Real maxVal=-std::numeric_limits<Real>::max())
+Real CompMaxReal(Grid<Real>& val) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+}
+
+//! Kernel: Compute min value of int grid
+KERNEL(idx, reduce=min) returns(int minVal=std::numeric_limits<int>::max())
+int CompMinInt(Grid<int>& val) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+}
+
+//! Kernel: Compute max value of int grid
+KERNEL(idx, reduce=max) returns(int maxVal=-std::numeric_limits<int>::min())
+int CompMaxInt(Grid<int>& val) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+}
+
+//! Kernel: Compute min norm of vec grid
+KERNEL(idx, reduce=min) returns(Real minVal=std::numeric_limits<Real>::max())
+Real CompMinVec(Grid<Vec3>& val) {
+ const Real s = normSquare(val[idx]);
+ if (s < minVal)
+ minVal = s;
+}
+
+//! Kernel: Compute max norm of vec grid
+KERNEL(idx, reduce=max) returns(Real maxVal=0)
+Real CompMaxVec(Grid<Vec3>& val) {
+ const Real s = normSquare(val[idx]);
+ if (s > maxVal)
+ maxVal = s;
+}
+
+
+template<class T> Grid<T>& Grid<T>::safeDivide (const Grid<T>& a) {
+ gridSafeDiv<T> (*this, a);
+ return *this;
+}
+template<class T> Grid<T>& Grid<T>::operator= (const Grid<T>& a) {
+ 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);
+ mType = a.mType; // copy type marker
+ return *this;
+}
+/*template<class T> Grid<T>& Grid<T>::operator= (const T& a) {
+ FOR_IDX(*this) { mData[idx] = a; }
+ return *this;
+}*/
+
+PYTHON void setConstant (Grid<Real>& grid, Real value=0.) { gridSetConst<Real>(grid,value); }
+PYTHON void setConstantVec3(Grid<Vec3>& grid, Vec3 value=0.) { gridSetConst<Vec3>(grid,value); }
+PYTHON void setConstantInt (Grid<int >& grid, int value=0.) { gridSetConst<int>(grid,value); }
+
+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);
+}
+KERNEL(idx) template<class T> void knGridSetAdded (Grid<T>& me, const Grid<T>& a, const Grid<T>& b) {
+ me[idx] = a[idx] + b[idx]; }
+template<class T> void Grid<T>::setAdd(const Grid<T>& a, const Grid<T>& b) {
+ knGridSetAdded<T>(*this, a, b);
+}
+KERNEL(idx) template<class T> void knGridSetSubtracted (Grid<T>& me, const Grid<T>& a, const Grid<T>& b) {
+ me[idx] = a[idx] - b[idx]; }
+template<class T> void Grid<T>::setSub(const Grid<T>& a, const Grid<T>& b) {
+ knGridSetSubtracted<T>(*this, a, b);
+}
+KERNEL(idx) template<class T> void knGridAddConstReal (Grid<T>& me, T val) {
+ me[idx] += val; }
+template<class T> void Grid<T>::addConstReal(Real a) {
+ knGridAddConstReal<T>( *this, T(a) );
+}
+KERNEL(idx) template<class T> void knGridMultConstReal (Grid<T>& me, Real val) {
+ me[idx] *= val; }
+template<class T> void Grid<T>::multiplyConstReal(Real a) {
+ knGridMultConstReal<T>( *this, a );
+}
+
+template<class T> void Grid<T>::addScaledReal(const Grid<T>& b, const Real& factor) {
+ gridScaledAdd<T,T> (*this, b, factor);
+}
+template<class T> void Grid<T>::multiply(const Grid<T>& b) {
+ gridMult<T,T> (*this, b);
+}
+
+KERNEL(idx) template<class T> void knGridClamp (Grid<T>& me, T min, T max) { me[idx] = clamp( me[idx], min, max); }
+template<class T> void Grid<T>::clamp(Real min, Real max) {
+ knGridClamp<T> (*this, T(min), T(max) );
+}
+
+//! Grid a += b*factor (note, shouldnt be part of the grid class! can cause problems with python instantiation)
+// (the template T class in argument list causes errors in fromPy etc. functions).
+// Also the python integration doesnt support templated functions for now (only classes)
+// So real and vec3 version are seperately declared here
+/*PYTHON void scaledAddReal(Grid<Real>& a, const Grid<Real>& b, const Real& factor) {
+ gridScaledAdd<Real,Real> (a, b, factor);
+}
+PYTHON void scaledAddVec3(Grid<Vec3>& a, const Grid<Vec3>& b, const Vec3& factor) {
+ gridScaledAdd<Vec3,Vec3> (a, b, factor);
+} */
+template<> Real Grid<Real>::getMaxValue() {
+ return CompMaxReal (*this);
+}
+template<> Real Grid<Real>::getMinValue() {
+ return CompMinReal (*this);
+}
+template<> Real Grid<Real>::getMaxAbsValue() {
+ Real amin = CompMinReal (*this);
+ Real amax = CompMaxReal (*this);
+ return max( fabs(amin), fabs(amax));
+}
+template<> Real Grid<Vec3>::getMaxValue() {
+ return sqrt(CompMaxVec (*this));
+}
+template<> Real Grid<Vec3>::getMinValue() {
+ return sqrt(CompMinVec (*this));
+}
+template<> Real Grid<Vec3>::getMaxAbsValue() {
+ return sqrt(CompMaxVec (*this));
+}
+template<> Real Grid<int>::getMaxValue() {
+ return (Real) CompMaxInt (*this);
+}
+template<> Real Grid<int>::getMinValue() {
+ return (Real) CompMinInt (*this);
+}
+template<> Real Grid<int>::getMaxAbsValue() {
+ int amin = CompMinInt (*this);
+ int amax = CompMaxInt (*this);
+ return max( fabs((Real)amin), fabs((Real)amax));
+}
+
+// compute maximal diference of two cells in the grid
+// used for testing
+PYTHON 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;
+}
+PYTHON 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;
+}
+PYTHON 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;
+}
+
+// simple helper functions to 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!)
+PYTHON void convertMacToVec3 (MACGrid &source, Grid<Vec3>& target)
+{
+ FOR_IJK(target) {
+ target(i,j,k) = source(i,j,k);
+ }
+}
+
+PYTHON void convertLevelsetToReal (LevelsetGrid &source , Grid<Real> &target)
+{
+ FOR_IJK(target) {
+ target(i,j,k) = source(i,j,k);
+ }
+}
+
+
+template<class T> void Grid<T>::printGrid(int zSlice, bool printIndex) {
+ std::ostringstream out;
+ out << std::endl;
+ const int bnd = 1;
+ FOR_IJK_BND(*this,bnd) {
+ int idx = (*this).index(i,j,k);
+ if(zSlice>=0 && k==zSlice) {
+ out << " ";
+ if(printIndex) out << " "<<i<<","<<j<<","<<k <<":";
+ out << (*this)[idx];
+ if(i==(*this).getSizeX()-1 -bnd) out << std::endl;
+ }
+ }
+ out << endl; debMsg("Printing " << this->getName() << out.str().c_str() , 1);
+}
+
+// helper functions for UV grid data (stored grid coordinates as Vec3 values, and uv weight in entry zero)
+
+// make uv weight accesible in python
+PYTHON Real getUvWeight (Grid<Vec3> &uv) { return uv[0][0]; }
+
+// 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;
+}
+
+KERNEL void knResetUvGrid (Grid<Vec3>& target) { target(i,j,k) = Vec3((Real)i,(Real)j,(Real)k); }
+
+PYTHON void resetUvGrid (Grid<Vec3> &target)
+{
+ knResetUvGrid reset(target); // note, llvm complains about anonymous declaration here... ?
+}
+PYTHON void updateUvWeight(Real resetTime, int index, int numUvs, Grid<Vec3> &uv , bool info=false)
+{
+ 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 );
+
+ // write new weight value to grid
+ uv[0] = Vec3( uvWeight, 0.,0.);
+
+ // print info about uv weights?
+ if(info) debMsg("Uv grid "<<index<<"/"<<numUvs<< " t="<<currt<<" w="<<uvWeight<<", reset:"<<(int)(currt<lastt) , 1);
+}
+
+PYTHON void setBoundaries(Grid<Real>& grid, Real value=0., int boundaryWidth=1) {
+ const int w = boundaryWidth;
+ FOR_IJK(grid) {
+ 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;
+ }
+}
+
+//******************************************************************************
+// Specialization classes
+
+void FlagGrid::initDomain(int boundaryWidth) {
+ FOR_IDX(*this)
+ mData[idx] = TypeEmpty;
+ initBoundaries(boundaryWidth);
+}
+
+void FlagGrid::initBoundaries(int boundaryWidth) {
+ const int w = boundaryWidth;
+ FOR_IJK(*this) {
+ bool bnd = (i<=w || i>=mSize.x-1-w || j<=w || j>=mSize.y-1-w || (is3D() && (k<=w || k>=mSize.z-1-w)));
+ if (bnd)
+ mData[index(i,j,k)] = TypeObstacle;
+ }
+}
+
+void FlagGrid::updateFromLevelset(LevelsetGrid& levelset) {
+ FOR_IDX(*this) {
+ if (!isObstacle(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] = (mData[idx] & ~(TypeEmpty | TypeFluid)) | type;
+ }
+}
+
+// explicit instantiation
+template class Grid<int>;
+template class Grid<Real>;
+template class Grid<Vec3>;
+
+//template void scaledAdd<Real,Real>(const Grid<Real>& a, const Grid<Real>& b, const Real& factor);
+
+#if ENABLE_GRID_TEST_DATATYPE==1
+// instantiate test datatype , not really required for simulations, mostly here for demonstration purposes
+template class Grid<nbVector>;
+#endif // ENABLE_GRID_TEST_DATATYPE
+
+
+} //namespace
diff --git a/source/blender/python/manta_full/source/grid.h b/source/blender/python/manta_full/source/grid.h
new file mode 100644
index 00000000000..cc5580611b7
--- /dev/null
+++ b/source/blender/python/manta_full/source/grid.h
@@ -0,0 +1,473 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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
+PYTHON class GridBase : public PbClass {
+public:
+ enum GridType { TypeNone = 0, TypeReal = 1, TypeInt = 2, TypeVec3 = 4, TypeMAC = 8, TypeLevelset = 16, TypeFlags = 32 };
+
+ PYTHON GridBase(FluidSolver* parent);
+
+ //! Get the grids X dimension
+ inline int getSizeX() const { return mSize.x; }
+ //! Get the grids Y dimension
+ inline int getSizeY() const { return mSize.y; }
+ //! Get the grids Z dimension
+ inline int getSizeZ() const { return mSize.z; }
+ //! Get the grids dimensions
+ inline Vec3i getSize() const { return mSize; }
+
+ //! Get Stride in X dimension
+ inline int getStrideX() const { return 1; }
+ //! Get Stride in Y dimension
+ inline int getStrideY() const { return mSize.x; }
+ //! Get Stride in Z dimension
+ inline int getStrideZ() const { return mStrideZ; }
+
+ 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) const;
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(int 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(int idx) const;
+
+ //! Get the type of grid
+ inline GridType getType() const { return mType; }
+ //! Check dimensionality
+ inline bool is2D() const { return !m3D; }
+ //! Check dimensionality
+ inline bool is3D() const { return m3D; }
+
+ //! Get index into the data
+ inline int index(int i, int j, int k) const { DEBUG_ONLY(checkIndex(i,j,k)); return i + mSize.x * j + mStrideZ * k; }
+ //! Get index into the data
+ inline int index(const Vec3i& pos) const { DEBUG_ONLY(checkIndex(pos.x,pos.y,pos.z)); return pos.x + mSize.x * pos.y + mStrideZ * pos.z; }
+protected:
+
+ GridType mType;
+ Vec3i mSize;
+ Real mDx;
+ bool m3D;
+ // precomputed Z shift: to ensure 2D compatibility, always use this instead of sx*sy !
+ int mStrideZ;
+};
+
+//! Grid class
+PYTHON template<class T>
+class Grid : public GridBase {
+public:
+ //! init new grid, values are set to zero
+ PYTHON Grid(FluidSolver* parent, bool show = true);
+ //! create new & copy content from another grid
+ Grid(const Grid<T>& a);
+ //! return memory to solver
+ virtual ~Grid();
+
+ typedef T BASETYPE;
+
+ PYTHON void save(std::string name);
+ PYTHON void load(std::string name);
+
+ //! set all cells to zero
+ PYTHON void clear();
+
+ //! 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(int 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()(int idx) { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T operator()(int 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[](int idx) { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline const T operator[](int 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
+ inline T getInterpolated(const Vec3& pos, int order) const {
+ switch(order) {
+ case 2: return interpolCubic<T>(mData, mSize, mStrideZ, pos);
+ default:
+ // default / fallback
+ assertMsg(false, "Unknown interpolation order "<<order);
+ case 1:
+ return interpol<T>(mData, mSize, mStrideZ, pos);
+ }
+ }
+
+ // 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>& operator=(const Grid<T>& a);
+ Grid<T>& safeDivide(const Grid<T>& a);
+
+ // python helper functions to work with grids in scene files
+ // note - unfortunately setConstant function has to be external! here only e.g. set to Real would work...
+ // see setConstant, setConstantVec3, setConstantInt in grid.cpp for details
+
+ //! add/subtract other grid
+ PYTHON void add(const Grid<T>& a);
+ PYTHON void sub(const Grid<T>& a);
+ //! set content to added/subtracted values of other two grids
+ PYTHON void setAdd(const Grid<T>& a, const Grid<T>& b);
+ PYTHON void setSub(const Grid<T>& a, const Grid<T>& b);
+ //! add real constant to all grid cells
+ PYTHON void addConstReal(Real s);
+ //! multiply contents of grid
+ PYTHON void multiply( const Grid<T>& b);
+ //! multiply each cell by a constant scalar value
+ PYTHON void multiplyConstReal(Real s);
+ //! add scaled other grid to current one (note, only "Real" factor, "T" type not supported here!)
+ PYTHON void addScaledReal(const Grid<T>& b, const Real& factor);
+ //! copy content from other grid (use this one instead of operator= !)
+ PYTHON void copyFrom(const Grid<T>& a) { *this = a; }
+ //! clamp content to range (for vec3, clamps each component separately)
+ PYTHON void clamp(Real min, Real max);
+
+ // common compound operators
+ //! get absolute max value in grid
+ PYTHON Real getMaxAbsValue();
+ //! get max value in grid
+ PYTHON Real getMaxValue();
+ //! get min value in grid
+ PYTHON Real getMinValue();
+ //! Swap data with another grid (no actual data is moved)
+ void swap(Grid<T>& other);
+
+ //! debugging helper, print grid from python
+ PYTHON void printGrid(int zSlice=-1, bool printIndex=false);
+
+protected:
+ T* mData;
+};
+
+// Python doesn't know about templates: explicit aliases needed
+PYTHON alias Grid<int> IntGrid;
+PYTHON alias Grid<Real> RealGrid;
+PYTHON alias Grid<Vec3> VecGrid;
+
+//! Special function for staggered grids
+PYTHON class MACGrid : public Grid<Vec3> {
+public:
+ PYTHON MACGrid(FluidSolver* parent, bool show=true) : Grid<Vec3>(parent, 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;
+ template<int comp> inline Real getInterpolatedComponent(Vec3 pos) const { return interpolComponent<comp>(mData, mSize, mStrideZ, pos); }
+ inline Vec3 getInterpolated(const Vec3& pos) const { return interpolMAC(mData, mSize, mStrideZ, pos); }
+ inline void setInterpolated(const Vec3& pos, const Vec3& val, Vec3* tmp) { return setInterpolMAC(mData, mSize, mStrideZ, pos, val, tmp); }
+
+protected:
+};
+
+//! Special functions for FlagGrid
+PYTHON class FlagGrid : public Grid<int> {
+public:
+ PYTHON FlagGrid(FluidSolver* parent, int dim=3, bool show=true) : Grid<int>(parent, 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,
+ TypeStick = 128,
+ TypeReserved = 256
+ // 2^10 - 2^14 reserved for moving obstacles
+ };
+
+ //! 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(int 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(int 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(int 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(int 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 isStick(int 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; }
+
+ // Python callables
+ PYTHON void initDomain(int boundaryWidth=0);
+ PYTHON void initBoundaries(int boundaryWidth=0);
+ PYTHON void updateFromLevelset(LevelsetGrid& levelset);
+ PYTHON void fillGrid(int type=TypeFluid);
+};
+
+
+//******************************************************************************
+// enable compilation of a more complicated test data type
+// for grids... note - this also enables code parts in fileio.cpp!
+// the code below is meant only as an example for a grid with a more complex data type
+// and illustrates which functions need to be implemented; it's not needed
+// to run any simulations in mantaflow!
+#define ENABLE_GRID_TEST_DATATYPE 0
+
+#if ENABLE_GRID_TEST_DATATYPE==1
+
+typedef std::vector<int> nbVectorBaseType;
+class nbVector : public nbVectorBaseType {
+ public:
+ inline nbVector() : nbVectorBaseType() {};
+ inline ~nbVector() {};
+
+ inline const nbVector& operator+= ( const nbVector &v1 ) {
+ assertMsg(false,"Never call!"); return *this;
+ }
+ inline const nbVector& operator*= ( const nbVector &v1 ) {
+ assertMsg(false,"Never call!"); return *this;
+ }
+};
+
+template<> inline nbVector* FluidSolver::getGridPointer<nbVector>() {
+ return new nbVector[mGridSize.x * mGridSize.y * mGridSize.z];
+}
+template<> inline void FluidSolver::freeGridPointer<nbVector>(nbVector* ptr) {
+ return delete[] ptr;
+}
+
+inline nbVector operator+ ( const nbVector &v1, const nbVector &v2 ) {
+ assertMsg(false,"Never call!"); return nbVector();
+}
+inline nbVector operator* ( const nbVector &v1, const nbVector &v2 ) {
+ assertMsg(false,"Never call!"); return nbVector();
+}
+template<class S>
+inline nbVector operator* ( const nbVector& v, S s ) {
+ assertMsg(false,"Never call!"); return nbVector();
+}
+template<class S>
+inline nbVector operator* ( S s, const nbVector& v ) {
+ assertMsg(false,"Never call!"); return nbVector();
+}
+
+template<> inline nbVector safeDivide<nbVector>(const nbVector &a, const nbVector& b) {
+ assertMsg(false,"Never call!"); return nbVector();
+}
+
+// make data type known to python
+// python keyword changed here, because the preprocessor does not yet parse #ifdefs correctly
+PYT HON alias Grid<nbVector> TestDataGrid;
+#endif // ENABLE_GRID_TEST_DATATYPE
+
+
+//! 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] );
+}
+
+
+//******************************************************************************
+// Implementation of inline functions
+
+inline void GridBase::checkIndex(int i, int j, int k) const {
+ //if (i<0 || j<0 || i>=mSize.x || j>=mSize.y || (is3D() && (k<0|| k>= mSize.z))) {
+ if (i<0 || j<0 || i>=mSize.x || j>=mSize.y || k<0|| 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(int 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(int 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 int 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 int 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 int 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 int 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;
+}
+
+KERNEL(idx) template<class T, class S> void gridAdd (Grid<T>& me, const Grid<S>& other) { me[idx] += other[idx]; }
+KERNEL(idx) template<class T, class S> void gridSub (Grid<T>& me, const Grid<S>& other) { me[idx] -= other[idx]; }
+KERNEL(idx) template<class T, class S> void gridMult (Grid<T>& me, const Grid<S>& other) { me[idx] *= other[idx]; }
+KERNEL(idx) template<class T, class S> void gridDiv (Grid<T>& me, const Grid<S>& other) { me[idx] /= other[idx]; }
+KERNEL(idx) template<class T, class S> void gridAddScalar (Grid<T>& me, const S& other) { me[idx] += other; }
+KERNEL(idx) template<class T, class S> void gridMultScalar (Grid<T>& me, const S& other) { me[idx] *= other; }
+KERNEL(idx) template<class T, class S> void gridScaledAdd (Grid<T>& me, const Grid<T>& other, const S& factor) { me[idx] += factor * other[idx]; }
+
+KERNEL(idx) template<class T> void gridAdd2 (Grid<T>& me, const Grid<T>& a, const Grid<T>& b) { me[idx] = a[idx] + b[idx]; }
+KERNEL(idx) template<class T> void gridSafeDiv (Grid<T>& me, const Grid<T>& other) { me[idx] = safeDivide(me[idx], other[idx]); }
+KERNEL(idx) template<class T> void gridSetConst(Grid<T>& grid, T value) { grid[idx] = 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;
+}
+
+
+
+} //namespace
+#endif
diff --git a/source/blender/python/manta_full/source/gui/customctrl.cpp b/source/blender/python/manta_full/source/gui/customctrl.cpp
new file mode 100644
index 00000000000..def8d2b03b7
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/customctrl.cpp
@@ -0,0 +1,172 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * GUI extension from python
+ *
+ ******************************************************************************/
+
+#include "customctrl.h"
+#include "qtmain.h"
+
+using namespace std;
+namespace Manta {
+
+// *****************************************************************************
+// Slider class
+
+CustomControl::CustomControl() : PbClass(0) {
+}
+
+CustomCheckbox::CustomCheckbox(string name, bool val) : mVal(val), mSName(name), mCheckbox(0) {
+}
+
+void CustomCheckbox::init(QBoxLayout* layout) {
+ mCheckbox = new TextCheckbox(mSName, mVal);
+ QObject::connect(mCheckbox, SIGNAL(stateChanged(int)), mCheckbox, SLOT(update(int)));
+ mCheckbox->attach(layout);
+}
+
+bool CustomCheckbox::get() {
+ if (!mCheckbox) throw Error("Slider is not attached yet!");
+ return mCheckbox->get();
+}
+void CustomCheckbox::set(bool v) {
+ if (!mCheckbox) throw Error("Slider is not attached yet!");
+ mCheckbox->set(v);
+}
+
+CustomSlider::CustomSlider(string name, float val, float min, float max) :
+ mMin(min), mMax(max), mVal(val), mSName(name), mSlider(0)
+{
+}
+
+void CustomSlider::init(QBoxLayout* layout) {
+ mSlider = new TextSlider(mSName, mVal, mMin, mMax);
+ QObject::connect(mSlider, SIGNAL(valueChanged(int)), mSlider, SLOT(update(int)));
+ mSlider->attach(layout);
+}
+
+float CustomSlider::get() {
+ if (!mSlider) throw Error("Slider is not attached yet!");
+ return mSlider->get();
+}
+
+void CustomSlider::set(float v) {
+ if (!mSlider) throw Error("Slider is not attached yet!");
+ mSlider->set(v);
+}
+
+TextSlider::TextSlider(const string& name, float val, float vmin, float vmax) :
+ QSlider(Qt::Horizontal), mMin(vmin), mMax(vmax), mSName(name.c_str())
+{
+ mLabel = new QLabel();
+ mScale = 1000;
+ setMinimum(0);
+ setMaximum(999);
+ set(val);
+ update(0);
+ }
+
+void TextSlider::attach(QBoxLayout* layout) {
+ layout->addWidget(mLabel);
+ layout->addWidget(this);
+}
+
+void TextSlider::update(int val) {
+ float v = get();
+ QString num;
+ num.sprintf("%.2g", v);
+ mLabel->setText(mSName + ": " + num);
+}
+
+float TextSlider::get() {
+ float va = mMin + (mMax-mMin) / mScale * (float)value();
+ return clamp(va, mMin, mMax);
+}
+
+void TextSlider::set(float v) {
+ float va = clamp(v, mMin, mMax);
+ va = (va - mMin) / (mMax-mMin) * mScale;
+ setValue((int)(va+0.5));
+}
+
+TextCheckbox::TextCheckbox(const string& name, bool val) :
+ QCheckBox(), mVal(val), mSName(name.c_str())
+{
+ mLabel = new QLabel();
+ set(val);
+ mLabel->setText(mSName);
+ }
+
+void TextCheckbox::attach(QBoxLayout* layout) {
+ QLayout* lay = new QHBoxLayout;
+ lay->setAlignment(Qt::AlignLeft);
+ lay->addWidget(this);
+ lay->addWidget(mLabel);
+ layout->addLayout(lay);
+}
+
+void TextCheckbox::update(int val) {
+}
+
+bool TextCheckbox::get() {
+ return isChecked();
+}
+
+void TextCheckbox::set(bool v) {
+ setChecked(v);
+}
+
+
+
+// **************************************************************************************
+// GUI class
+
+void updateQtGui(bool full, int frame, const std::string& curPlugin);
+extern MainThread* gMainThread;
+extern GuiThread* gGuiThread;
+
+Gui::Gui() :
+ PbClass(NULL), mGuiPtr(gGuiThread), mMainPtr(gMainThread) {
+}
+
+void Gui::setBackgroundMesh(Mesh* m) {
+ mGuiPtr->getWindow()->setBackground(m);
+}
+void Gui::show() {
+ mMainPtr->sendAndWait((int)MainWnd::EventGuiShow);
+}
+void Gui::update() {
+ updateQtGui(true,-1,"");
+}
+void Gui::pause() {
+ mMainPtr->sendAndWait((int)MainWnd::EventFullUpdate);
+ mGuiPtr->getWindow()->pause();
+}
+void Gui::screenshot(string filename) {
+ QString s(filename.c_str());
+ QMetaObject::invokeMethod(mGuiPtr->getWindow(), "screenshot", Q_ARG(QString, s));
+}
+
+PbClass* Gui::addControl(PbType t) {
+ _args.add("nocheck",true);
+ if (t.str() == "")
+ throw Error("Need to specify object type. Use e.g. gui.create(Slider, ...)");
+
+ PbClass* obj = PbClass::createPyObject(t.str(), "", _args, this);
+ if (!obj || !obj->canConvertTo("CustomControl"))
+ throw Error("gui.create() can only create CustomControl-based objects");
+
+ QMetaObject::invokeMethod(gGuiThread->getWindow(), "addControl", Q_ARG(void*, (void*)obj));
+
+ return obj;
+}
+
+
+} // namespace
diff --git a/source/blender/python/manta_full/source/gui/customctrl.h b/source/blender/python/manta_full/source/gui/customctrl.h
new file mode 100644
index 00000000000..c6fe94feefd
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/customctrl.h
@@ -0,0 +1,129 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * GUI extension from python
+ *
+ ******************************************************************************/
+
+#ifndef _CUSTOMCTRL_H__
+#define _CUSTOMCTRL_H__
+
+#include <QSlider>
+#include <QLabel>
+#include <QCheckBox>
+#include <QBoxLayout>
+#include "manta.h"
+
+namespace Manta {
+
+// fwd decl.
+class Mesh;
+class GuiThread;
+class MainThread;
+
+//! Interface for python declared controls
+PYTHON class CustomControl : public PbClass {
+public:
+ PYTHON CustomControl();
+
+ virtual void init(QBoxLayout* layout) {};
+
+protected:
+};
+
+//! Checkbox with attached text display
+class TextCheckbox : public QCheckBox {
+ Q_OBJECT
+public:
+ TextCheckbox(const std::string& name, bool val);
+ void attach(QBoxLayout* layout);
+ void set(bool v);
+ bool get();
+
+public slots:
+ void update(int v);
+
+protected:
+ bool mVal;
+ QLabel* mLabel;
+ QString mSName;
+};
+
+//! Slider with attached text display
+class TextSlider : public QSlider {
+ Q_OBJECT
+public:
+ TextSlider(const std::string& name, float val, float min, float max);
+ void attach(QBoxLayout* layout);
+ void set(float v);
+ float get();
+
+public slots:
+ void update(int v);
+
+protected:
+ float mMin, mMax, mScale;
+ QLabel* mLabel;
+ QString mSName;
+};
+
+//! Links a slider control
+PYTHON(name=Slider)
+class CustomSlider : public CustomControl {
+public:
+ PYTHON CustomSlider(std::string text, float val, float min, float max);
+ virtual void init(QBoxLayout* layout);
+
+ PYTHON float get();
+ PYTHON void set(float v);
+
+protected:
+ float mMin, mMax, mVal;
+ std::string mSName;
+ TextSlider* mSlider;
+};
+
+//! Links a checkbox control
+PYTHON(name=Checkbox)
+class CustomCheckbox : public CustomControl {
+public:
+ PYTHON CustomCheckbox(std::string text, bool val);
+ virtual void init(QBoxLayout* layout);
+
+ PYTHON bool get();
+ PYTHON void set(bool v);
+
+protected:
+ bool mVal;
+ std::string mSName;
+ TextCheckbox* mCheckbox;
+};
+
+
+//! GUI adapter class to call from Python
+PYTHON class Gui : public PbClass {
+public:
+ PYTHON Gui();
+
+ PYTHON void setBackgroundMesh(Mesh* m);
+ PYTHON void show();
+ PYTHON void update();
+ PYTHON void pause();
+ PYTHON PbClass* addControl(PbType t);
+ PYTHON void screenshot(std::string filename);
+
+protected:
+ GuiThread* mGuiPtr;
+ MainThread* mMainPtr;
+};
+
+} // namespace
+
+#endif
+
diff --git a/source/blender/python/manta_full/source/gui/glwidget.cpp b/source/blender/python/manta_full/source/gui/glwidget.cpp
new file mode 100644
index 00000000000..5869a617e93
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/glwidget.cpp
@@ -0,0 +1,292 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * QT OpenGL widget
+ *
+ ******************************************************************************/
+
+#include "glwidget.h"
+#ifdef __APPLE__
+# include <OpenGL/glu.h>
+#else
+# include <GL/glu.h>
+#endif
+#include <cmath>
+#include "painter.h"
+
+namespace Manta {
+
+GLWidget::GLWidget(QWidget* p): QGLWidget(QGLFormat(QGL::SampleBuffers), p), mRotX(0), mRotY(0), mGridsize(0), mScreenshotNumber(0)
+{
+ mPlaneDim = 2; // Y plane
+ mPlane = -1;
+ mCamPos = Vec3(0, 0, -2);
+ for (int i=0; i<MoveDirNum; i++)
+ mMoveState[i] = false;
+ mMoveFast = false;
+
+ setAutoBufferSwap(true);
+ setFocusPolicy(Qt::ClickFocus);
+ startTimer(10);
+}
+
+GLWidget::~GLWidget()
+{
+
+}
+
+QSize GLWidget::minimumSizeHint() const
+{
+ return QSize(400, 300);
+}
+
+QSize GLWidget::sizeHint() const
+{
+ return QSize(800, 600);
+}
+
+void GLWidget::initializeGL()
+{
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClearDepth(1.0);
+}
+
+void GLWidget::paintGL()
+{
+ if (mGridsize.max() == 0) return;
+ glDepthFunc(GL_ALWAYS);
+ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+ //glEnable(GL_POLYGON_OFFSET_FILL);
+ //glPolygonOffset(0,0);
+
+ // camera transform
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(mCamPos.x, mCamPos.y, mCamPos.z);
+ glRotatef(mRotX, 1.,0.,0.);
+ glRotatef(mRotY, 0.,1.,0.);
+ Real dx = 1.0 / (Real) mGridsize.max();
+ Vec3 sz = toVec3(mGridsize) * (-0.5f * dx);
+
+ glTranslatef(sz.x, sz.y, sz.z);
+ emit paintSub();
+}
+
+void GLWidget::resizeGL(int w, int h)
+{
+ glViewport(0, 0, (GLsizei) w, (GLsizei) h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ GLfloat fov = 45;
+ GLfloat zNear = 0.05f;
+ GLfloat zFar = 100.0f;
+ GLfloat aspect = float(w)/float(h);
+ GLfloat fH = tan( float(fov / 360.0f * M_PI) ) * zNear;
+ GLfloat fW = fH * aspect;
+ glFrustum( -fW, fW, -fH, fH, zNear, zFar );
+ glMatrixMode(GL_MODELVIEW);
+
+}
+
+void GLWidget::mouseReleaseEvent(QMouseEvent* event) {
+ // only do tooltip if not moving
+ QPoint pos = event->pos();
+ if ((mDownPos - pos).manhattanLength() == 0) {
+ // get GL transform matrices
+ int viewport[4];
+ GLdouble modelMatrix[16], projMatrix[16];
+ glGetDoublev(GL_MODELVIEW_MATRIX,modelMatrix);
+ glGetDoublev(GL_PROJECTION_MATRIX,projMatrix);
+ glGetIntegerv(GL_VIEWPORT,viewport);
+
+ // obtain click line
+ GLdouble line[6], wx=pos.x(), wy=viewport[3]-pos.y();
+ if (!gluUnProject(wx,wy,0,modelMatrix,projMatrix,viewport,&line[0],&line[1],&line[2])) return;
+ if (!gluUnProject(wx,wy,1.0,modelMatrix,projMatrix,viewport,&line[3],&line[4],&line[5])) return;
+
+ // calculate intersection with plane
+ emit clickLine(event->globalPos(), line[0],line[1],line[2],line[3],line[4],line[5]);
+ }
+}
+
+void GLWidget::mouseMoveEvent(QMouseEvent* e)
+{
+ const float speedRot = 0.2f, speedPan = 0.002f;
+
+ QPoint diff = e->pos() - mAnchor;
+ if (e->buttons() & Qt::LeftButton) {
+ mRotX += diff.y() * speedRot;
+ mRotY += diff.x() * speedRot;
+ updateGL();
+ }
+ if (e->buttons() & Qt::RightButton) {
+ mCamPos.x += diff.x() * speedPan;
+ mCamPos.y -= diff.y() * speedPan;
+ updateGL();
+ }
+
+ mAnchor = e->pos();
+}
+
+void GLWidget::mousePressEvent(QMouseEvent* e)
+{
+ mDownPos = mAnchor = e->pos();
+}
+
+void GLWidget::wheelEvent(QWheelEvent* e)
+{
+ const float speed = 0.002f;
+ mCamPos.z += speed*e->delta();
+ updateGL();
+}
+
+void GLWidget::timerEvent(QTimerEvent* e)
+{
+ bool doRepaint = false;
+
+ float speed = 0.005f;
+ if (mMoveFast) speed *= 5.;
+
+ if (mMoveState[MoveLeft]) { mCamPos.x += speed; doRepaint = true; }
+ if (mMoveState[MoveRight]) { mCamPos.x -= speed; doRepaint = true; }
+ if (mMoveState[MoveUp]) { mCamPos.y -= speed; doRepaint = true; }
+ if (mMoveState[MoveDown]) { mCamPos.y += speed; doRepaint = true; }
+ if (mMoveState[MoveOut]) { mCamPos.z -= speed; doRepaint = true; }
+ if (mMoveState[MoveIn]) { mCamPos.z += speed; doRepaint = true; }
+ if (doRepaint)
+ updateGL();
+}
+
+void GLWidget::setViewport(const Vec3i& gridsize) {
+ if (mGridsize.x != gridsize.x ||
+ mGridsize.y != gridsize.y ||
+ mGridsize.z != gridsize.z) {
+ if (mPlane < 0) {
+ mPlane = gridsize[mPlaneDim] / 2;
+ } else {
+ Real fac = (Real)gridsize[mPlaneDim] / (Real)mGridsize[mPlaneDim];
+ mPlane = (int)(fac * mPlane);
+ }
+ mGridsize = gridsize;
+ emit painterEvent(Painter::EventSetMax, mGridsize[mPlaneDim]);
+ emit painterEvent(Painter::EventSetPlane, mPlane);
+ }
+}
+
+void GLWidget::keyPressEvent(QKeyEvent* e)
+{
+ if(!keyProcess(e->key(), e->modifiers(), true))
+ QGLWidget::keyPressEvent(e);
+ else
+ updateGL();
+}
+
+void GLWidget::keyReleaseEvent(QKeyEvent* e)
+{
+ if(!keyProcess(e->key(), e->modifiers(), false))
+ QGLWidget::keyReleaseEvent(e);
+ else
+ updateGL();
+}
+
+bool GLWidget::keyProcess(int key, int modifier, bool down)
+{
+ bool shift = (modifier & Qt::ShiftModifier);
+ bool alt = (modifier & Qt::AltModifier);
+ bool ctrl = (modifier & Qt::ControlModifier);
+ if (key == Qt::Key_A) { mMoveState[MoveLeft] = down; mMoveFast = shift; }
+ else if (key == Qt::Key_D) { mMoveState[MoveRight] = down; mMoveFast = shift; }
+ else if (key == Qt::Key_W) { mMoveState[MoveIn] = down; mMoveFast = shift; }
+ else if (key == Qt::Key_S) { mMoveState[MoveOut] = down; mMoveFast = shift; }
+ else if (key == Qt::Key_Q) { mMoveState[MoveUp] = down; mMoveFast = shift; }
+ else if (key == Qt::Key_E) { mMoveState[MoveDown] = down; mMoveFast = shift; }
+ else if (down)
+ {
+ // only press events
+ // note Key_P and Key_L used for play/step in mainwindow.cpp
+ if (key == Qt::Key_Z) { /* next "solver" info sometime? */ }
+ else if (key == Qt::Key_G) { emit painterEvent(Painter::EventToggleGridDisplay); }
+ // data grids, first int
+ else if (key == Qt::Key_X && shift) { /* int display mdoes, not yet used */ }
+ else if (key == Qt::Key_X) { emit painterEvent(Painter::EventNextInt); updatePlane(mPlane); }
+ // real
+ else if (key == Qt::Key_C && shift) { /* real display mdoes, not yet used */ }
+ else if (key == Qt::Key_C) { emit painterEvent(Painter::EventNextReal); updatePlane(mPlane); }
+
+ // vec3 grids, scaling can be used with two key combinations (the second one is for international keyboards)
+ else if (key == Qt::Key_V && shift) { emit painterEvent(Painter::EventNextVelDisplayMode); }
+ else if (key == Qt::Key_V) { emit painterEvent(Painter::EventNextVec); updatePlane(mPlane); }
+ else if (key == Qt::Key_BraceLeft ) { emit painterEvent(Painter::EventScaleVecDown); }
+ else if (key == Qt::Key_BraceRight) { emit painterEvent(Painter::EventScaleVecUp); }
+ // grid scaling
+ else if (key == Qt::Key_BracketLeft && shift) { emit painterEvent(Painter::EventScaleVecDown); }
+ else if (key == Qt::Key_BracketRight && shift) { emit painterEvent(Painter::EventScaleVecUp); }
+ else if (key == Qt::Key_BracketLeft) { emit painterEvent(Painter::EventScaleRealDown); }
+ else if (key == Qt::Key_BracketRight) { emit painterEvent(Painter::EventScaleRealUp); }
+
+ // particles
+ else if (key == Qt::Key_B && shift) { emit painterEvent(Painter::EventNextParticleDisplayMode); }
+ else if (key == Qt::Key_B && alt) { emit painterEvent(Painter::EventNextSystem); }
+ else if (key == Qt::Key_B) { emit painterEvent(Painter::EventToggleParticles); }
+
+ else if((key == Qt::Key_ParenLeft) || // ugly, but for some reason parentheses dont work in some cases... fall back with dual assignment
+ ((key == Qt::Key_9) && shift) ) { emit painterEvent(Painter::EventScalePdataDown); }
+ else if((key == Qt::Key_ParenRight) ||
+ ((key == Qt::Key_0) && shift ) ) { emit painterEvent(Painter::EventScalePdataUp); }
+
+ // mesh display
+ else if (key == Qt::Key_M && shift) emit painterEvent(Painter::EventMeshMode);
+ else if((key == Qt::Key_Less) ||
+ ((key == Qt::Key_Comma) && shift) ) { emit painterEvent(Painter::EventScaleMeshDown); }
+ else if((key == Qt::Key_Greater) ||
+ ((key == Qt::Key_Period) && shift ) ) { emit painterEvent(Painter::EventScaleMeshUp); }
+ // special mesh display modes
+ else if (key == Qt::Key_M && alt) emit painterEvent(Painter::EventMeshColorMode);
+ else if (key == Qt::Key_M && ctrl) emit painterEvent(Painter::EventToggleBackgroundMesh);
+ else if (key == Qt::Key_M) emit painterEvent(Painter::EventNextMesh);
+
+ // switch display planes
+ else if (key == Qt::Key_Asterisk) {
+ mPlaneDim = (mPlaneDim+1) % 3;
+ emit painterEvent(Painter::EventSetDim, mPlaneDim);
+ emit painterEvent(Painter::EventSetMax, mGridsize[mPlaneDim]);
+ } else if (key == Qt::Key_Plus || key == Qt::Key_Equal) {
+ updatePlane(mPlane + 1);
+ } else if (key == Qt::Key_Minus) {
+ updatePlane(mPlane - 1);
+ }
+ else if ( key == Qt::Key_K) {
+ QString filename = QString("scr_%1.png").arg(QString::number(mScreenshotNumber), 3, QChar('0'));
+ screenshot(filename);
+ mScreenshotNumber++;
+ }
+
+ else return false;
+ }
+ else return false;
+ return true;
+}
+
+void GLWidget::screenshot(QString file) {
+ grabFrameBuffer().save(file);
+}
+
+void GLWidget::updatePlane(int plane) {
+ mPlane = clamp(plane, 0, mGridsize[mPlaneDim]);
+ emit painterEvent(Painter::EventSetPlane, mPlane);
+}
+
+
+
+}
diff --git a/source/blender/python/manta_full/source/gui/glwidget.h b/source/blender/python/manta_full/source/gui/glwidget.h
new file mode 100644
index 00000000000..1601a7c7732
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/glwidget.h
@@ -0,0 +1,72 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * QT OpenGL widget
+ *
+ ******************************************************************************/
+
+#ifndef _GLWIDGET_H__
+#define _GLWIDGET_H__
+
+#include <QGLWidget>
+#include <QtOpenGL>
+#include "vectorbase.h"
+
+namespace Manta {
+
+class GLWidget : public QGLWidget {
+Q_OBJECT
+
+public:
+ GLWidget(QWidget *parent = NULL);
+ ~GLWidget();
+
+ QSize minimumSizeHint() const;
+ QSize sizeHint() const;
+
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void wheelEvent(QWheelEvent *e);
+ void screenshot(QString file);
+
+public slots:
+ void setViewport(const Vec3i& gridsize);
+ void keyPressEvent(QKeyEvent* e);
+ void keyReleaseEvent(QKeyEvent* e);
+
+signals:
+ void paintSub();
+ void clickLine(QPoint pos, float p0, float p1,float p2, float q0, float q1, float q2);
+ void painterEvent(int e, int param=0);
+
+protected:
+ bool keyProcess(int key, int mod, bool down);
+ void timerEvent(QTimerEvent* e);
+ void initializeGL();
+ void resizeGL(int w, int h);
+ void paintGL();
+ void updatePlane(int plane);
+
+ enum MoveDir { None = 0, MoveLeft, MoveRight, MoveUp, MoveDown, MoveIn, MoveOut, MoveDirNum };
+
+ bool mMoveState[MoveDirNum];
+ bool mMoveFast;
+ QPoint mAnchor, mDownPos;
+ Vec3 mCamPos;
+ float mRotX, mRotY;
+ Vec3i mGridsize;
+ int mPlaneDim, mPlane;
+
+ int mScreenshotNumber;
+};
+
+} // namespace
+
+#endif
diff --git a/source/blender/python/manta_full/source/gui/mainwindow.cpp b/source/blender/python/manta_full/source/gui/mainwindow.cpp
new file mode 100644
index 00000000000..d176befbd8b
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/mainwindow.cpp
@@ -0,0 +1,243 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * QT main window
+ *
+ ******************************************************************************/
+
+#include "mainwindow.h"
+#include "qtmain.h"
+
+#include <QLabel>
+#include <QMenu>
+#include <QMenuBar>
+#include <QAction>
+#include <QtOpenGL>
+#include <sstream>
+#include "meshpainter.h"
+#include "particlepainter.h"
+
+using namespace std;
+
+namespace Manta {
+
+MainWnd::MainWnd() : QMainWindow(0), mPaused(true), mRequestPause(false), mRequestClose(false), mStep(0)
+{
+ // Frame info label
+ mInfo = new QLabel;
+ setFrame(0);
+
+ // register GL widget
+ mGlWidget = new GLWidget();
+ setCentralWidget(mGlWidget);
+ connect(mGlWidget, SIGNAL(clickLine(QPoint,float,float,float,float,float,float)), SLOT(clickLine(QPoint,float,float,float,float,float,float)));
+
+ // register grid painters
+ mPainterLayout = new QVBoxLayout;
+ mPainterLayout->setAlignment(Qt::AlignTop);
+ mPainterLayout->addWidget(mInfo);
+ GridPainter<int>* intPainter = new GridPainter<int>(NULL, this);
+ mPainter.push_back(new GridPainter<Real>((FlagGrid**)intPainter->getGridPtr(), this));
+ mPainter.push_back(new GridPainter<Vec3>(NULL, this));
+ mPainter.push_back(intPainter);
+ mPainter.push_back(new ParticlePainter(intPainter, this));
+ MeshPainter* ptr = new MeshPainter(this);
+ mPainter.push_back(ptr);
+ connect(this, SIGNAL(setBackgroundMesh(Mesh*)), ptr, SLOT(setBackgroundMesh(Mesh*)));
+
+ for (int i=0; i<(int)mPainter.size(); i++) {
+ connect(mGlWidget, SIGNAL(paintSub()), mPainter[i], SLOT(paint()));
+ connect(mGlWidget, SIGNAL(painterEvent(int, int)), mPainter[i], SLOT(doEvent(int, int)));
+ connect(this, SIGNAL(painterEvent(int, int)), mPainter[i], SLOT(doEvent(int, int)));
+ connect(mPainter[i], SIGNAL(setViewport(const Vec3i&)), mGlWidget, SLOT(setViewport(const Vec3i&)));
+ mPainter[i]->attachWidget(mPainterLayout);
+ }
+
+ // docking widget for painters
+ QDockWidget* painterDock = new QDockWidget("Info", this);
+ QWidget* painterProxy = new QWidget;
+ painterProxy->setLayout(mPainterLayout);
+ painterDock->setWidget(painterProxy);
+ painterDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
+ addDockWidget(Qt::RightDockWidgetArea, painterDock);
+
+ // Top toolbar
+ QToolBar* toolbar = addToolBar("Control");
+ toolbar->setAllowedAreas(Qt::TopToolBarArea);
+ toolbar->setMovable(false);
+ mAcPlay = toolbar->addAction(QIcon(":/play.png"),"Play");
+ mAcPlay->setStatusTip("Continue simulation");
+ connect(mAcPlay, SIGNAL(triggered()), SLOT(play()));
+ mAcPause = toolbar->addAction(QIcon(":/pause.png"),"Pause");
+ mAcPause->setStatusTip("Pause simulation");
+ connect(mAcPause, SIGNAL(triggered()), SLOT(pause()));
+ emit play();
+
+ // build menu
+ /*QAction* a = new QAction(this);
+ a->setText( "Quit" );
+ connect(a, SIGNAL(triggered()), SLOT(close()) );
+ menuBar()->addMenu( "File" )->addAction( a ); */
+
+ mGlWidget->setFocus();
+ this->raise();
+ this->activateWindow();
+
+ // uncomment to start paused
+ //emit pause();
+}
+
+void MainWnd::clickLine(QPoint pos, float p0, float p1,float p2, float q0, float q1, float q2) {
+ string msg;
+ for (int i=mPainter.size()-1; i>=0; i--) {
+ msg += mPainter[i]->clickLine(Vec3(p0,p1,p2),Vec3(q0,q1,q2));
+ }
+ if (!msg.empty())
+ QToolTip::showText(pos, QString(msg.c_str()));
+}
+
+void MainWnd::addControl(void* ctrl) {
+ CustomControl* control = (CustomControl*) ctrl;
+ mCtrls.push_back(control);
+ control->init(mPainterLayout);
+}
+
+void MainWnd::setFrame(int f) {
+ std::stringstream s;
+ s << "Simulation frame " << f;
+ mInfo->setText(s.str().c_str());
+}
+
+void MainWnd::setPauseStatus(bool v)
+{
+ mPaused = v;
+}
+
+bool MainWnd::event(QEvent* e) {
+ if (e->type() == (QEvent::Type)EventGuiShow) {
+ if (!mRequestClose) {
+ this->show();
+ emit painterEvent(Painter::UpdateFull);
+ mGlWidget->updateGL();
+ }
+ emit wakeMain();
+ return true;
+ }
+ else if (e->type() == (QEvent::Type)EventFullUpdate) {
+ if (!mRequestClose) {
+ emit painterEvent(Painter::UpdateFull);
+ mGlWidget->updateGL();
+ }
+ emit wakeMain();
+ return true;
+ }
+ else if (e->type() == (QEvent::Type)EventStepUpdate) {
+ if (!mRequestClose) {
+ if (mRequestPause)
+ emit painterEvent(Painter::UpdateFull);
+ else
+ emit painterEvent(Painter::UpdateStep);
+ mGlWidget->updateGL();
+ }
+ emit wakeMain();
+ return true;
+ }
+ else if (e->type() == (QEvent::Type)EventFinalUpdate) {
+ if (!mRequestClose) {
+ emit painterEvent(Painter::UpdateFull);
+ mGlWidget->updateGL();
+ }
+ mRequestClose = true;
+ emit wakeMain();
+ return true;
+ }
+ else if (e->type() == (QEvent::Type)EventInstantKill) {
+ emit killMain();
+ emit exitApp();
+ return true;
+ }
+
+ // update button states for pause events
+ if( (mRequestPause) && (!mAcPlay->isEnabled()) ) {
+ mAcPlay->setEnabled(true);
+ mAcPause->setEnabled(false);
+ }
+ if( (mRequestPause) && (!mAcPlay->isEnabled()) ) {
+ mAcPlay->setEnabled(true);
+ mAcPause->setEnabled(false);
+ }
+
+ return QMainWindow::event(e);
+}
+
+void MainWnd::keyPressEvent(QKeyEvent* e) {
+ if (e->key() == Qt::Key_Escape) {
+ mRequestClose = true;
+ emit killMain();
+ this->close();
+ } else if (e->key() == Qt::Key_Space) {
+ if (mRequestClose) {
+ emit killMain();
+ this->close();
+ } else {
+ emit painterEvent(mPaused ? Painter::UpdateFull : Painter::UpdateRequest);
+ mGlWidget->updateGL();
+ }
+ } else if (e->key() == Qt::Key_P) {
+ if (mRequestClose) {
+ emit killMain();
+ this->close();
+ } else if (mRequestPause)
+ emit play();
+ else
+ emit pause();
+ } else if (e->key() == Qt::Key_L) {
+ if (mRequestClose) {
+ emit killMain();
+ this->close();
+ } else if (mRequestPause) {
+ mRequestPause = false;
+ mStep = (e->modifiers() & Qt::ShiftModifier) ? 1 : 2;
+ } else
+ emit pause();
+ } else {
+ mGlWidget->keyPressEvent(e); // let gl widget take care of keyboard shortcuts
+ //QMainWindow::keyPressEvent(e);
+ }
+}
+void MainWnd::keyReleaseEvent(QKeyEvent* e)
+{
+ mGlWidget->keyReleaseEvent(e);
+}
+
+void MainWnd::pause() {
+ mRequestPause = true;
+ // dont call: mAcPlay/mAcPause ->setEnabled(true) here; wrong thread if called from python
+}
+
+void MainWnd::play() {
+ mRequestPause = false;
+ mAcPlay->setEnabled(false);
+ mAcPause->setEnabled(true);
+}
+
+void MainWnd::step() {
+ mStep = 2;
+ mRequestPause = false;
+}
+
+MainWnd::~MainWnd() {
+}
+
+void MainWnd::screenshot(QString file) {
+ mGlWidget->screenshot(file);
+}
+
+
+}
diff --git a/source/blender/python/manta_full/source/gui/mainwindow.h b/source/blender/python/manta_full/source/gui/mainwindow.h
new file mode 100644
index 00000000000..e3d11572685
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/mainwindow.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * QT main window
+ *
+ ******************************************************************************/
+
+#ifndef _MAINWINDOW_H_
+#define _MAINWINDOW_H_
+
+#include <QMainWindow>
+#include "glwidget.h"
+#include "customctrl.h"
+#include "painter.h"
+#include <vector>
+
+namespace Manta {
+class Mesh;
+
+class MainWnd : public QMainWindow
+{
+Q_OBJECT
+public:
+ enum EventType { EventFullUpdate = QEvent::User, EventGuiShow, EventStepUpdate, EventFinalUpdate, EventInstantKill };
+
+ MainWnd();
+ virtual ~MainWnd();
+ bool event(QEvent* e);
+ void keyPressEvent(QKeyEvent* e);
+ void keyReleaseEvent(QKeyEvent* e);
+ inline bool pauseRequest() { return mRequestPause && !mRequestClose; }
+ inline bool closeRequest() { return mRequestClose; }
+ void setPauseStatus(bool v);
+ void stepReset(bool fullUpdate) { if (mStep == 1 || (mStep == 2 && fullUpdate)) {mRequestPause = true; mStep = 0;} }
+ void requestClose() { mRequestClose =true; }
+ void setFrame(int f);
+ void setBackground(Mesh *m) { emit setBackgroundMesh(m); }
+
+public slots:
+ void pause();
+ void play();
+ void step();
+ void addControl(void* ctrl);
+ void screenshot(QString file);
+ void clickLine(QPoint pos, float p0, float p1,float p2, float q0, float q1, float q2);
+
+signals:
+ void painterEvent(int e, int param=0);
+ void wakeMain();
+ void setBackgroundMesh(Mesh* bgr);
+ void killMain();
+ void exitApp();
+
+protected:
+ bool mPaused, mRequestPause, mRequestClose;
+ int mStep;
+ GLWidget* mGlWidget;
+ QAction* mAcPlay, *mAcPause;
+ std::vector<Painter*> mPainter;
+ std::vector<CustomControl*> mCtrls;
+ QLabel* mInfo;
+ QVBoxLayout* mPainterLayout;
+};
+
+}
+
+#endif
diff --git a/source/blender/python/manta_full/source/gui/meshpainter.cpp b/source/blender/python/manta_full/source/gui/meshpainter.cpp
new file mode 100644
index 00000000000..cba75ff2316
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/meshpainter.cpp
@@ -0,0 +1,300 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Painting mesh objects
+ *
+ ******************************************************************************/
+
+#include "meshpainter.h"
+#include <QtOpenGL>
+#include "mesh.h"
+#include "vortexsheet.h"
+
+using namespace std;
+
+namespace Manta {
+
+MeshPainter::MeshPainter(QWidget* par)
+ : LockedObjPainter(par), mColorScale(1.0), mMode(ModeFlatShade), mVorticityMode(VModeNone),
+ mBackgroundMode(BModeNormal), mLocalMesh(0) , mBackground(0), mHide(false)
+{
+ mInfo = new QLabel();
+}
+
+MeshPainter::~MeshPainter() {
+ if (mLocalMesh)
+ delete mLocalMesh;
+}
+
+void MeshPainter::attachWidget(QLayout* layout) {
+ layout->addWidget(mInfo);
+}
+
+void MeshPainter::update() {
+ Mesh* src = (Mesh*) mObject;
+
+ // always reallocate
+ if (mLocalMesh)
+ delete mLocalMesh;
+
+ mLocalMesh = src->clone();
+
+ updateText();
+}
+
+string MeshPainter::getID() { return "Mesh"; }
+
+
+void MeshPainter::processKeyEvent(PainterEvent e, int param)
+{
+ if (e == EventNextMesh)
+ nextObject();
+ else if (e == EventMeshMode)
+ mMode = (DisplayMode) ((mMode+1) % (int)Num_DisplayModes);
+ else if (e == EventScaleMeshUp)
+ mColorScale *= 2.0;
+ else if (e == EventScaleMeshDown)
+ mColorScale /= 2.0;
+ else if (e == EventMeshColorMode)
+ mVorticityMode = (VorticityMode) ((mVorticityMode+1)%(int)Num_VorticityModes);
+ else if (e == EventToggleBackgroundMesh)
+ mBackgroundMode = (BackgroundMode) ((mBackgroundMode+1)%(int)Num_BackgroundModes);
+ else return;
+
+ updateText();
+}
+
+void MeshPainter::updateText() {
+ stringstream s;
+
+ if ( mObject && !mHide && mLocalMesh ) {
+ s << "Mesh '" << mLocalMesh->getName() << "' [" << mLocalMesh->numTris() << " tris]" << endl;
+ if (mMode == ModeFlatShade) s << "DisplayMode: Flatshade" << endl;
+ if (mMode == ModeInvisible) s << "DisplayMode: Invisible" << endl;
+ if (mMode == ModeLines) s << "DisplayMode: Wireframe" << endl;
+ if (mMode == ModePoints) s << "DisplayMode: Pointset" << endl;
+ if (mMode == ModeTrans) s << "DisplayMode: Semi-Transparent" << endl;
+ if (mLocalMesh->getType() == Mesh::TypeVortexSheet) {
+ if (mVorticityMode==VModeFull) s << "Vorticity: full" << endl;
+ if (mVorticityMode==VModeSmoothed) s << "Vorticity: gauss smooth" << endl;
+ if (mVorticityMode==VModeDiff) s << "Vorticity: gauss diff" << endl;
+ if (mVorticityMode==VModeSmoke) s << "Smoke Density" << endl;
+ if (mVorticityMode==VModeTex) s << "Texture coordinates 0" << endl;
+ if (mVorticityMode!=VModeNone) s << " Scale " << 1.0/mColorScale << "" << endl;
+ }
+ }
+ mInfo->setText(s.str().c_str());
+}
+
+void MeshPainter::setBackgroundMesh(Mesh* bgr) {
+ mBackground = bgr;
+}
+
+void MeshPainter::setupLights(bool specular) {
+ // control colors
+ float max = 1.0;
+ float dim = 0.5;
+ float dims = specular ? dim : 0;
+ float maxs = specular ? max : 0;
+ float amb = 0.1;
+ float shininess = 50.;
+ dim = 0.5; max = 0.75; amb = 0.25;
+
+ float ambient0[] = {amb, amb, amb, max};
+ glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);
+
+ float diffuse0[] = {max, dim, dim, 1.0};
+ float specular0[] = {maxs, dims, dims, 1.0};
+ float position0[] = { 5., 5., 5., 1.0f };
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);
+ glLightfv(GL_LIGHT0, GL_SPECULAR, specular0);
+ glLightfv(GL_LIGHT0, GL_POSITION, position0);
+
+ float diffuse1[] = {dim, max, dim, 1.0};
+ float specular1[] = {dims, maxs, dims, 1.0};
+ float position1[] = { 5., -5., -5., 1.0f };
+ glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1);
+ glLightfv(GL_LIGHT1, GL_SPECULAR, specular1);
+ glLightfv(GL_LIGHT1, GL_POSITION, position1);
+
+ float diffuse2[] = {dim, dim, max, 1.0};
+ float specular2[] = {dims, dims, maxs, 1.0};
+ float position2[] = { 0.3, 2., -10., 1.0f };
+ glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuse2);
+ glLightfv(GL_LIGHT2, GL_SPECULAR, specular2);
+ glLightfv(GL_LIGHT2, GL_POSITION, position2);
+
+ float specReflection[] = { dims, dims, dims, 1.0f };
+ if(shininess == 0.) specReflection[0] = specReflection[1] = specReflection[2] = 0.;
+ glMaterialfv(GL_FRONT, GL_SPECULAR, specReflection);
+ glMateriali(GL_FRONT, GL_SHININESS, shininess);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_LIGHT1);
+ glEnable(GL_LIGHT2);
+}
+
+//static inline void glColor(const Vec3& color) {
+ //glColor3f(std::max(_0,std::min(_1,color.x)), std::max(_0,std::min(_1,color.y)), std::max(_0,std::min(_1,color.z)));
+//}
+
+static inline void glVertex(const Vec3& v, Real dx) {
+ glVertex3f(v.x * dx, v.y * dx, v.z * dx);
+}
+static inline void glNormal(const Vec3& v) {
+ glNormal3f(v.x, v.y, v.z);
+}
+
+void MeshPainter::paint() {
+ if (!mObject || mHide || !mLocalMesh) return;
+
+ Real dx = mLocalMesh->getParent()->getDx();
+
+ bool triColor = (mMode == ModeFlatShade) && (mLocalMesh->getType() == Mesh::TypeVortexSheet) && (mVorticityMode!=VModeNone);
+ bool nodeColor = (mLocalMesh->getType() == Mesh::TypeVortexSheet) && (mVorticityMode==VModeTex);
+
+ // setup OpenGL lighting and material
+ const float isoAlpha = 0.4;
+ setupLights(false);
+ glColorMaterial ( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ) ;
+ glEnable(GL_COLOR_MATERIAL);
+ glDepthFunc(GL_LESS);
+ //glDisable(GL_CULL_FACE);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+
+ // draw background
+ if (mBackground != NULL && mBackgroundMode != BModeInvisible) {
+ if (mBackgroundMode != BModeTrans) {
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+ glColor3f(0.3,0.3,0.5);
+ } else {
+ glEnable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ glColor4f(0.6,0.6,0.8,0.5);
+ }
+ glEnable(GL_CULL_FACE);
+ glPolygonOffset(1.0, 0.5);
+ glBegin(GL_TRIANGLES);
+
+ for(int tri=0; tri<mBackground->numTris(); tri++) {
+ Vec3 normal = mBackground->getFaceNormal(tri);
+ for (int c=0; c<3; c++) {
+ glNormal(normal);
+ glVertex(mBackground->getNode(tri,c), dx);
+ }
+ }
+ glEnd();
+ glPolygonOffset(1., 1.);
+ glDisable(GL_CULL_FACE);
+ }
+
+ setupLights(true);
+ if (mMode == ModeFlatShade) {
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+ } else {
+ glEnable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ }
+ if (triColor)
+ glDisable(GL_LIGHTING);
+
+ // draw triangles
+ if (mMode == ModeFlatShade || mMode == ModeTrans)
+ {
+ glEnable(GL_CULL_FACE);
+ glPolygonOffset(1.0, 0.5);
+ glBegin(GL_TRIANGLES);
+
+ const int numTris = (int)mLocalMesh->numTris();
+ for(int tri=0; tri<numTris; tri++) {
+ if (!nodeColor && triColor) {
+ VortexSheetInfo& info = ((VortexSheetMesh*)mLocalMesh)->sheet(tri);
+ Vec3 v = info.vorticity;
+ if (mVorticityMode == VModeSmoothed) v = info.vorticitySmoothed;
+ if (mVorticityMode == VModeDiff) v -= info.vorticitySmoothed;
+ if (mVorticityMode == VModeSmoke) v = info.smokeAmount / 20.0f;
+
+ Vec3 ca = v * 20.0 * mColorScale;
+ Vec3 color = Vec3(fabs(ca.x),fabs(ca.y),fabs(ca.z));
+ glColor3f(color.x, color.y, color.z);
+ } else if (mLocalMesh->isTriangleFixed(tri))
+ glColor3f(0,1,0);
+ else if (mLocalMesh->tris(tri).flags & Mesh::FfMarked)
+ glColor3f(1,0,0);
+ else
+ glColor4f(0.5,0.5,0.5, isoAlpha);
+
+ for (int c=0; c<3; c++) {
+ if (nodeColor) {
+ Vec3 tc = ((VortexSheetMesh*)mLocalMesh)->tex1(mLocalMesh->tris(tri).c[c]);
+ //Vec3 tc2 = ((VortexSheetMesh*)mLocalMesh)->tex2(mLocalMesh->tris(tri).c[c]);
+ //Vec3 tc = gAlpha*tc1+(1-gAlpha)*tc2;
+ tc = mColorScale * (tc / toVec3(mLocalMesh->getParent()->getGridSize()));
+ tc = nmod(tc, Vec3(1,1,1));
+ glColor3f(tc.x, tc.y ,tc.z);
+ }
+ glNormal(mLocalMesh->getFaceNormal(tri));
+ glVertex(mLocalMesh->getNode(tri,c), dx);
+ }
+ }
+ glEnd();
+ glPolygonOffset(1., 1.);
+ glDisable(GL_CULL_FACE);
+ }
+
+ // Disable light setup
+ glDisable(GL_BLEND);
+ glDisable(GL_LIGHT0);
+ glDisable(GL_LIGHT1);
+ glDisable(GL_LIGHT2);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glDisable(GL_TEXTURE_2D);
+
+ // draw mesh lines
+ if(mMode == ModeLines) {
+ glColor3d(1.0, 0.9, 0.9);
+ glLineWidth(1.0);
+ glBegin(GL_LINES);
+ const int numTris = (int)mLocalMesh->numTris();
+ for(int tri=0; tri<numTris; tri++)
+ for (int j=5; j<5+6; j++)
+ glVertex( mLocalMesh->getNode(tri,(j/2)%3), dx);
+ glEnd();
+ }
+
+ // draw vertex points
+ if(mMode == ModePoints) {
+ static const Vec3 colorSpecial (0.3, 0.5, 0.2);
+ //static const Vec3 colortable[] = { Vec3(0.5), Vec3(1,0,0), Vec3(0,1,0), Vec3(0,0,1) };
+
+ glPointSize(2.0);
+ glBegin(GL_POINTS);
+ const int numNodes = (int)mLocalMesh->numNodes();
+ for(int i=0; i<numNodes; i++) {
+ Vec3 color(0.5, 0.5, 0.5);
+ if (mLocalMesh->isNodeFixed(i))
+ color = Vec3(0,1,0);
+ else if (mLocalMesh->nodes(i).flags & Mesh::NfMarked)
+ color = Vec3(1,0,0);
+ //int flags = mLocalMesh->flags(i);
+
+ glColor3f(color.x, color.y, color.z);
+ glVertex(mLocalMesh->nodes(i).pos, dx);
+ }
+ glEnd();
+ glPointSize(1.0);
+ }
+}
+
+
+
+} // namespace
diff --git a/source/blender/python/manta_full/source/gui/meshpainter.h b/source/blender/python/manta_full/source/gui/meshpainter.h
new file mode 100644
index 00000000000..8a0166a2ed2
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/meshpainter.h
@@ -0,0 +1,59 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Painting mesh objects
+ *
+ ******************************************************************************/
+
+#ifndef _MESHPAINTER_H_
+#define _MESHPAINTER_H_
+
+#include "painter.h"
+
+namespace Manta {
+// fwd decl
+class Mesh;
+
+//! Painter object for Meshes
+class MeshPainter : public LockedObjPainter {
+ Q_OBJECT
+public:
+ enum DisplayMode { ModeTrans=0, ModeLines, ModePoints, ModeFlatShade, ModeInvisible, Num_DisplayModes };
+ enum BackgroundMode { BModeNormal=0, BModeTrans, BModeInvisible, Num_BackgroundModes };
+ enum VorticityMode { VModeFull=0, VModeSmoothed, VModeDiff, VModeSmoke, VModeTex, VModeNone, Num_VorticityModes };
+
+ MeshPainter(QWidget* par = 0);
+ ~MeshPainter();
+
+ void paint();
+ void attachWidget(QLayout* layout);
+
+public slots:
+ void setBackgroundMesh(Mesh* bgr);
+
+protected:
+ std::string getID();
+ void update();
+ void updateText();
+ void processKeyEvent(PainterEvent e, int param);
+ void processSpecificKeyEvent(PainterEvent e, int param);
+ void setupLights(bool specular);
+
+ Real mColorScale;
+ DisplayMode mMode;
+ VorticityMode mVorticityMode;
+ BackgroundMode mBackgroundMode;
+ Mesh* mLocalMesh, *mBackground;
+ QLabel* mInfo;
+ bool mHide;
+};
+
+} // namespace
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/gui/painter.cpp b/source/blender/python/manta_full/source/gui/painter.cpp
new file mode 100644
index 00000000000..7437c8d6fed
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/painter.cpp
@@ -0,0 +1,539 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Base class for objects painting into the GL widget
+ *
+ ******************************************************************************/
+
+#include "painter.h"
+#include <QtOpenGL>
+#include <sstream>
+#include <iomanip>
+
+using namespace std;
+
+namespace Manta {
+
+//******************************************************************************
+// Base class
+
+void LockedObjPainter::doEvent(int e, int param) {
+ // try to obtain valid handle
+ if (!mObject)
+ nextObject();
+
+ // filter update events
+ if (e == UpdateFull) {
+ // always update
+ if (mObject) {
+ mObject->lock();
+ update();
+ mObject->unlock();
+ mRequestUpdate = false;
+ }
+ } else if (e == UpdateRequest) {
+ // update if resource is available, otherwise wait until next step
+ mRequestUpdate = true;
+ if (mObject) {
+ if (mObject->tryLock()) {
+ update();
+ mRequestUpdate = false;
+ mObject->unlock();
+ }
+ }
+ } else if (e == UpdateStep) {
+ // update if requested only
+ if (mRequestUpdate) {
+ if (mObject) {
+ mObject->lock();
+ update();
+ mObject->unlock();
+ mRequestUpdate = false;
+ }
+ }
+ } else {
+ // pass on all other events
+ processKeyEvent((PainterEvent)e, param);
+ }
+}
+
+void LockedObjPainter::nextObject() {
+ if (PbClass::getNumInstances() == 0) return;
+
+ int oldIndex = mObjIndex;
+ for(;;) {
+ mObjIndex = (mObjIndex + 1) % PbClass::getNumInstances();
+ if (oldIndex == mObjIndex) break;
+
+ PbClass* obj = PbClass::getInstance(mObjIndex);
+ if (obj->canConvertTo(getID()) && !obj->isHidden()) {
+ mObject = obj;
+ doEvent(UpdateRequest);
+ return;
+ }
+ if (oldIndex < 0) oldIndex = 0; // prevent endless loop on first run
+ }
+}
+
+//******************************************************************************
+// Grid painter
+
+template<class T>
+GridPainter<T>::GridPainter(FlagGrid** flags, QWidget* par)
+ : LockedObjPainter(par), mMaxVal(0), mDim(0), mPlane(0), mMax(0), mLocalGrid(NULL),
+ mFlags(flags), mInfo(NULL), mHide(false), mHideLocal(false), mVelMode(VelDispCentered), mValScale()
+{
+ mDim = 2; // Z plane
+ mPlane = 0;
+ mInfo = new QLabel();
+
+}
+
+template<class T>
+GridPainter<T>::~GridPainter() {
+ if (mLocalGrid)
+ delete mLocalGrid;
+}
+
+template<class T>
+void GridPainter<T>::attachWidget(QLayout* layout) {
+ layout->addWidget(mInfo);
+}
+
+template<class T>
+void GridPainter<T>::update() {
+ Grid<T>* src = (Grid<T>*) mObject;
+
+ if (!mLocalGrid) {
+ mLocalGrid = new Grid<T>(src->getParent());
+ // int grid is base for resolution
+ if (src->getType() & GridBase::TypeInt)
+ emit setViewport(src->getSize());
+ }
+ // reallocate if dimensions changed
+ if (mLocalGrid->getSize() != src->getSize()) {
+ delete mLocalGrid;
+ mLocalGrid = new Grid<T>(src->getParent());
+ // int grid is base for resolution
+ if (src->getType() & GridBase::TypeInt)
+ emit setViewport(src->getSize());
+ }
+
+ *mLocalGrid = *src; // copy grid data and type marker
+ mLocalGrid->setName(src->getName());
+ mLocalGrid->setParent(src->getParent());
+ mMaxVal = mLocalGrid->getMaxAbsValue();
+
+ mPlane = clamp(mPlane, 0, mLocalGrid->getSize()[mDim]-1);
+
+ updateText();
+}
+
+template<> string GridPainter<int>::getID() { return "Grid<int>"; }
+template<> string GridPainter<Vec3>::getID() { return "Grid<Vec3>"; }
+template<> string GridPainter<Real>::getID() { return "Grid<Real>"; }
+
+template<class T>
+void GridPainter<T>::processKeyEvent(PainterEvent e, int param)
+{
+ if (e == EventSetDim) {
+ mDim = param;
+ if (mLocalGrid->is2D()) mDim = 2;
+ } else if (e == EventSetMax) {
+ mMax = param;
+ } else if (e == EventSetPlane) {
+ mPlane = param;
+ if (mObject) {
+ if (mMax>0)
+ mPlane = mPlane * mLocalGrid->getSize()[mDim] / mMax;
+ mPlane = clamp(mPlane, 0, mLocalGrid->getSize()[mDim]-1);
+ }
+ } else if (e == EventToggleGridDisplay)
+ mHide = !mHide;
+ else
+ processSpecificKeyEvent(e, param);
+
+ updateText();
+}
+
+// get scale value for current grid from map, or create new
+template<class T>
+Real GridPainter<T>::getScale() {
+ if (!mObject) return 0;
+
+ if (mValScale.find(mObject) == mValScale.end()) {
+ // init new scale value
+ Real s = 1.0;
+ if (mLocalGrid->getType() & GridBase::TypeVec3)
+ s = 0.4;
+ else if (mLocalGrid->getType() & GridBase::TypeLevelset)
+ s = 1.0;
+ mValScale[mObject] = s;
+ }
+ return mValScale[mObject];
+
+}
+
+//******************************************************************************
+// Grid painter class specializations
+
+template<>
+void GridPainter<int>::processSpecificKeyEvent(PainterEvent e, int param) {
+ if (e == EventNextInt)
+ nextObject();
+}
+
+template<>
+void GridPainter<Real>::processSpecificKeyEvent(PainterEvent e, int param) {
+ if (e == EventNextReal)
+ nextObject();
+ else if (e == EventScaleRealDown && mObject)
+ mValScale[mObject] = getScale() * 0.5;
+ else if (e == EventScaleRealUp && mObject)
+ mValScale[mObject] = getScale() * 2.0;
+}
+
+template<>
+void GridPainter<Vec3>::processSpecificKeyEvent(PainterEvent e, int param) {
+ if (e == EventNextVec)
+ nextObject();
+ else if (e == EventScaleVecDown && mObject)
+ mValScale[mObject] = getScale() * 0.5;
+ else if (e == EventScaleVecUp && mObject)
+ mValScale[mObject] = getScale() * 2.0;
+ else if (e == EventNextVelDisplayMode) {
+ mVelMode = (mVelMode+1)%NumVelDispModes;
+ mHideLocal = (mVelMode==VelDispOff);
+
+ }
+}
+
+template<> void GridPainter<int>::updateText() {
+ stringstream s;
+ if (mObject && (!mHide)) {
+ s << "Int Grid '" << mLocalGrid->getName() << "'" << endl;
+ }
+ mInfo->setText(s.str().c_str());
+}
+
+template<> void GridPainter<Real>::updateText() {
+ stringstream s;
+
+ s << "Display Plane " << mPlane << " [" << (char)('X' + mDim) << "]" << endl << endl;
+ if (mObject) {
+ s << "Solver '" << mLocalGrid->getParent()->getName() << "'" << endl;
+ s << "Grid resolution [" << mLocalGrid->getSizeX() << ", " << mLocalGrid->getSizeY() << ", " << mLocalGrid->getSizeZ() << "]" << endl;
+ s << endl;
+ }
+
+ if (mObject && !mHide) {
+ s << "Real Grid '" << mLocalGrid->getName() << "'" << endl;
+ s << "-> Max " << fixed << setprecision(2) << mMaxVal << " Scale " << getScale() << endl;
+ }
+ mInfo->setText(s.str().c_str());
+}
+
+template<> void GridPainter<Vec3>::updateText() {
+ stringstream s;
+ if (mObject && !mHide && !mHideLocal) {
+ s << "Vec Grid '" << mLocalGrid->getName() << "'" << endl;
+ s << "-> Max norm " << fixed << setprecision(2) << mMaxVal << " Scale " << getScale() << endl;
+ }
+ mInfo->setText(s.str().c_str());
+}
+
+// compute line intersection with the display plane
+Vec3i getQuad(const Vec3& l0, const Vec3& l1, int dim, int plane, Real dx) {
+ Vec3 n(0.); n[dim] = 1;
+ Vec3 p0 = n*(plane+0.5);
+ Vec3 e = (l1-l0)/dx;
+ Vec3 e0 = l0/dx;
+ Real dotP = dot(p0-e0,n);
+ Real dotE = dot(e,n);
+ if (dotE == 0)
+ return Vec3i(-1,-1,-1);
+ Vec3 s = e0 + (dotP/dotE)*e;
+ return toVec3i(s);
+}
+
+template<> string GridPainter<int>::clickLine(const Vec3& p0, const Vec3& p1) {
+ if (!mObject) return "";
+ Vec3i s = getQuad(p0,p1,mDim,mPlane,mLocalGrid->getDx());
+ if (!mLocalGrid->isInBounds(s)) return "";
+ stringstream m;
+ m << "Grid [ " << s.x << ", " << s.y << ", " << s.z << " ]" << endl << mLocalGrid->getName() << ": " << mLocalGrid->get(s) << endl;
+ return m.str();
+}
+
+template<> string GridPainter<Real>::clickLine(const Vec3& p0, const Vec3& p1) {
+ if (!mObject) return "";
+ Vec3i s = getQuad(p0,p1,mDim,mPlane,mLocalGrid->getDx());
+ if (!mLocalGrid->isInBounds(s)) return "";
+ stringstream m;
+ m << mLocalGrid->getName() << ": " << setprecision(2) << mLocalGrid->get(s) << endl;
+ return m.str();
+}
+
+template<> string GridPainter<Vec3>::clickLine(const Vec3& p0, const Vec3& p1) {
+ if (!mObject) return "";
+ Vec3i s = getQuad(p0,p1,mDim,mPlane,mLocalGrid->getDx());
+ if (!mLocalGrid->isInBounds(s)) return "";
+ stringstream m;
+ m << mLocalGrid->getName() << ": [ " << setprecision(2) << mLocalGrid->get(s).x << ", " <<
+ mLocalGrid->get(s).y << ", " << mLocalGrid->get(s).z << " ]" << endl;
+ return m.str();
+}
+
+
+//******************************************************************************
+// Actual painting functions
+
+// GL helper functions
+
+// Macro to iterate through one plane
+#define FOR_P_SLICE(__g,__dim,__plane) \
+ for(Vec3i __g0(__fRange(Vec3i(0,0,0),__dim,__plane)), __g1(__fRange((__g)->getSize(),__dim,__plane+1)), p(__g0); p.z<__g1.z; p.z++) \
+ for(p.y=__g0.y; p.y < __g1.y; p.y++) \
+ for(p.x=__g0.x; p.x < __g1.x; p.x++)
+inline Vec3i __fRange(Vec3i size, int dim, int plane) { Vec3i p(size); p[dim]=plane; return p; }
+
+// coordinate system :
+// cell center(i,j,k) -> (i+0.5,j+0.5,k+0.5) / N
+//
+
+void getCellCoordinates(const Vec3i& pos, Vec3 box[4], int dim) {
+ int dim2=(dim+1)%3;
+ Vec3 p0(pos.x, pos.y, pos.z);
+ Vec3 p1(pos.x+1, pos.y+1, pos.z+1);
+ p1[dim] = p0[dim] = pos[dim] + 0.5;
+ box[0] = p0;
+ box[3] = p0; box[3][dim2] = p1[dim2];
+ box[1] = p1; box[1][dim2] = p0[dim2];
+ box[2] = p1;
+}
+static inline void glVertex(const Vec3& v, const float dx) {
+ glVertex3f(v.x * dx, v.y * dx, v.z * dx);
+}
+void glBox(const Vec3& p0, const Vec3& p1, const float dx) {
+ const int box[24] = {0,1,0,2,0,4,7,6,7,5,7,3,1,3,1,5,2,3,2,6,4,5,4,6};
+ for (int i=0;i<24;i++) {
+ const int b = box[i];
+ glVertex(Vec3( (b&1) ? p1.x : p0.x, (b&2) ? p1.y : p0.y, (b&4) ? p1.z : p0.z), dx);
+ }
+}
+
+// Paint gridlines
+template<> void GridPainter<int>::paint() {
+ if (!mObject || mHide || mPlane <0 || mPlane >= mLocalGrid->getSize()[mDim])
+ return;
+ float dx = mLocalGrid->getDx();
+ Vec3 box[4];
+ glColor3f(0.5,0,0);
+
+ bool rbox = true;
+ bool skipFluid = mLocalGrid->getSize().max() > 40;
+ bool drawLines = mLocalGrid->getSize().max() <= 80;
+ if (drawLines) {
+ //glDepthFunc(GL_LESS);
+ glBegin(GL_LINES);
+ FOR_P_SLICE(mLocalGrid, mDim, mPlane) {
+
+ int flag = 0;
+ flag = mLocalGrid->get(p);
+
+ if (flag & FlagGrid::TypeObstacle) {
+ glColor3f(0.2,0.2,0.2);
+ } else if (flag & FlagGrid::TypeOutflow) {
+ glColor3f(0.9,0.2,0);
+ } else if (flag & FlagGrid::TypeEmpty) {
+ glColor3f(0.25,0,0);
+ } else if (flag & FlagGrid::TypeFluid) {
+ if(skipFluid) continue;
+ glColor3f(0,0,0.75);
+ } else {
+ glColor3f(0.5,0,0); // unknown
+ }
+
+ getCellCoordinates(p, box, mDim);
+ for (int n=1;n<=8;n++)
+ glVertex(box[(n/2)%4], dx);
+ }
+ glEnd();
+ //glDepthFunc(GL_ALWAYS);
+ }
+
+ if (rbox) {
+ Vec3 p0(0.0), p1(toVec3(mLocalGrid->getSize())),p(p0);
+ glDepthFunc(GL_LESS);
+ glBegin(GL_LINES);
+ glBox(p0,p1,dx);
+ glEnd();
+ glDepthFunc(GL_ALWAYS);
+ }
+}
+
+// Paint box colors
+template<> void GridPainter<Real>::paint() {
+ if (!mObject || mHide || mHideLocal || mPlane <0 || mPlane >= mLocalGrid->getSize()[mDim] || !mFlags || !(*mFlags))
+ return;
+
+ float dx = mLocalGrid->getDx();
+ Vec3 box[4];
+ glBegin(GL_QUADS);
+ Real scale = getScale();
+ bool isLevelset = mLocalGrid->getType() & GridBase::TypeLevelset;
+ //glPolygonOffset(1.0,1.0);
+ //glDepthFunc(GL_LESS);
+
+ const bool useOldDrawStyle = false;
+ if(useOldDrawStyle) {
+ // original mantaflow drawing style
+ FlagGrid *flags = *mFlags;
+ if (flags->getSize() != mLocalGrid->getSize()) flags = 0;
+
+ FOR_P_SLICE(mLocalGrid, mDim, mPlane) {
+ int flag = FlagGrid::TypeFluid;
+ if (flags && (mLocalGrid->getType() & GridBase::TypeLevelset) == 0) flag = flags->get(p);
+ if (flag & FlagGrid::TypeObstacle)
+ glColor3f(0.15,0.15,0.15);
+ else if (flag & FlagGrid::TypeOutflow)
+ glColor3f(0.3,0.0,0.0);
+ else if (flag & FlagGrid::TypeEmpty)
+ glColor3f(0.,0.2,0.);
+ else {
+ Real v = mLocalGrid->get(p) * scale;
+
+ if (isLevelset) {
+ v = max(min(v*0.2, 1.0),-1.0);
+ if (v>=0)
+ glColor3f(v,0,0.5);
+ else
+ glColor3f(0.5, 1.0+v, 0.);
+ } else {
+ if (v>0)
+ glColor3f(v,0,0);
+ else
+ glColor3f(0,0,-v);
+ }
+ }
+
+ if ((flag & FlagGrid::TypeEmpty) == 0) {
+ getCellCoordinates(p, box, mDim);
+ for (int n=0;n<4;n++)
+ glVertex(box[n], dx);
+ }
+ }
+
+ } else {
+ // "new" drawing style
+ // ignore flags, its a bit dangerous to skip outside info
+
+ FOR_P_SLICE(mLocalGrid, mDim, mPlane)
+ {
+ Real v = mLocalGrid->get(p) * scale;
+ if (isLevelset) {
+ v = max(min(v*0.2, 1.0),-1.0);
+ if (v>=0)
+ glColor3f(v,0,0.5);
+ else
+ glColor3f(0.5, 1.0+v, 0.);
+ } else {
+ if (v>0)
+ glColor3f(v,v,v);
+ else
+ glColor3f(-v,0,0);
+ }
+
+ getCellCoordinates(p, box, mDim);
+ for (int n=0;n<4;n++)
+ glVertex(box[n], dx);
+ }
+ }
+
+ glEnd();
+ //glDepthFunc(GL_ALWAYS);
+ //glPolygonOffset(0,0);
+}
+
+// Paint velocity vectors
+template<> void GridPainter<Vec3>::paint() {
+ if (!mObject || mHide || mHideLocal || mPlane <0 || mPlane >= mLocalGrid->getSize()[mDim])
+ return;
+
+ float dx = mLocalGrid->getDx();
+ bool mac = mLocalGrid->getType() & GridBase::TypeMAC;
+ const Real scale = getScale();
+
+ if( (mVelMode==VelDispCentered) || (mVelMode==VelDispStaggered) ) {
+
+ // regular velocity drawing mode
+ glBegin(GL_LINES);
+
+ FOR_P_SLICE(mLocalGrid, mDim, mPlane) {
+ Vec3 vel = mLocalGrid->get(p) * scale;
+ Vec3 pos (p.x+0.5, p.y+0.5, p.z+0.5);
+ if (mVelMode==VelDispCentered) {
+ if (mac) {
+ if (p.x < mLocalGrid->getSizeX()-1)
+ vel.x = 0.5 * (vel.x + scale * mLocalGrid->get(p.x+1,p.y,p.z).x);
+ if (p.y < mLocalGrid->getSizeY()-1)
+ vel.y = 0.5 * (vel.y + scale * mLocalGrid->get(p.x,p.y+1,p.z).y);
+ if (p.z < mLocalGrid->getSizeZ()-1)
+ vel.z = 0.5 * (vel.z + scale * mLocalGrid->get(p.x,p.y,p.z+1).z);
+ }
+ glColor3f(0,1,0);
+ glVertex(pos, dx);
+ glColor3f(1,1,0);
+ glVertex(pos+vel*1.2, dx);
+ } else if (mVelMode==VelDispStaggered) {
+ for (int d=0; d<3; d++) {
+ if (fabs(vel[d]) < 1e-2) continue;
+ Vec3 p1(pos);
+ if (mac)
+ p1[d] -= 0.5f;
+ Vec3 color(0.0);
+ color[d] = 1;
+ glColor3f(color.x, color.y, color.z);
+ glVertex(p1, dx);
+ glColor3f(1,1,0);
+ p1[d] += vel[d];
+ glVertex(p1, dx);
+ }
+ }
+ }
+ glEnd();
+
+ } else if (mVelMode==VelDispUv) {
+ // draw as uv coordinates , note - this will completely hide the real grid display!
+ Vec3 box[4];
+ glBegin(GL_QUADS);
+ FOR_P_SLICE(mLocalGrid, mDim, mPlane)
+ {
+ Vec3 v = mLocalGrid->get(p) * scale;
+ for(int c=0; c<3; ++c) {
+ if(v[c]<0.) v[c] *= -1.;
+ v[c] = fmod( (Real)v[c], (Real)1.);
+ }
+ //v *= mLocalGrid->get(0)[0]; // debug, show uv grid weight as brightness of values
+ glColor3f(v[0],v[1],v[2]);
+ getCellCoordinates(p, box, mDim);
+ for (int n=0;n<4;n++)
+ glVertex(box[n], dx);
+ }
+ glEnd();
+ }
+}
+
+
+// explicit instantiation
+template class GridPainter<int>;
+template class GridPainter<Real>;
+template class GridPainter<Vec3>;
+
+} // namespace
diff --git a/source/blender/python/manta_full/source/gui/painter.h b/source/blender/python/manta_full/source/gui/painter.h
new file mode 100644
index 00000000000..8d5f9db229b
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/painter.h
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Base class for objects painting into the GL widget
+ *
+ ******************************************************************************/
+
+#ifndef _PAINTER_H_
+#define _PAINTER_H_
+
+#include <QWidget>
+#include <QLabel>
+#include <map>
+#include "grid.h"
+
+namespace Manta {
+
+// forward decl.
+class PbClass;
+
+//! Base class for all painter
+/*! Derived classes have to implement paint, doEvent */
+class Painter : public QObject {
+ Q_OBJECT
+public:
+ enum PainterEvent {
+ EventNone = 0, UpdateRequest, UpdateFull, UpdateStep,
+ EventScaleVecUp, EventScaleVecDown, EventScaleRealUp, EventScaleRealDown, EventChangePlane,
+ EventSetPlane, EventSetDim, EventNextInt, EventNextReal, EventNextVec, EventNextVelDisplayMode,
+ EventNextMesh, EventMeshMode, EventToggleGridDisplay, EventScaleMeshUp, EventScaleMeshDown, EventMeshColorMode,
+ EventNextSystem, EventToggleParticles, EventNextParticleDisplayMode, EventToggleBackgroundMesh, EventSetMax,
+ EventScalePdataDown, EventScalePdataUp };
+
+ enum VelDisplayModes { VelDispOff=0, VelDispCentered, VelDispStaggered, VelDispUv, NumVelDispModes };
+
+ Painter(QWidget* par = 0) : QObject(par) {}
+ virtual ~Painter() {}
+
+ virtual std::string clickLine(const Vec3& p0, const Vec3& p1) { return ""; }
+ virtual void attachWidget(QLayout* layout) {}
+signals:
+ void setViewport(const Vec3i& gridsize);
+
+public slots:
+ virtual void paint() = 0;
+ virtual void doEvent(int e, int param=0) = 0;
+};
+
+//! Base clas for all painters that require access to a locked PbClass
+/*! Derived classes have to implement paint, update, getID, processKeyEvent. doEvent is handled in this class */
+class LockedObjPainter : public Painter {
+ Q_OBJECT
+public:
+ LockedObjPainter(QWidget* par = 0) : Painter(par), mRequestUpdate(false), mObject(NULL), mObjIndex(-1) {}
+
+ void doEvent(int e, int param=0); // don't overload, use processKeyEvent and update instead
+
+protected:
+ void nextObject();
+ virtual std::string getID() = 0;
+ virtual void update() = 0;
+ virtual void processKeyEvent(PainterEvent e, int param) = 0;
+
+ bool mRequestUpdate;
+ PbClass* mObject;
+ int mObjIndex;
+};
+
+//! Painter object for int,Real,Vec3 grids
+template<class T>
+class GridPainter : public LockedObjPainter {
+public:
+ GridPainter(FlagGrid** flags = NULL, QWidget* par = 0);
+ ~GridPainter();
+
+ void paint();
+ void attachWidget(QLayout* layout);
+ Grid<T>** getGridPtr() { return &mLocalGrid; }
+ int getPlane() { return mPlane; }
+ int getDim() { return mDim; }
+ int getMax() { return mMax; }
+ virtual std::string clickLine(const Vec3& p0, const Vec3& p1);
+
+protected:
+ std::string getID();
+ Real getScale();
+ void update();
+ void updateText();
+ void processKeyEvent(PainterEvent e, int param);
+ void processSpecificKeyEvent(PainterEvent e, int param);
+ //void paintGridLines(bool lines, bool box);
+
+ Real mMaxVal;
+ int mDim, mPlane, mMax;
+ Grid<T>* mLocalGrid;
+ FlagGrid** mFlags;
+ QLabel* mInfo;
+ bool mHide, mHideLocal;
+ int mVelMode;
+ std::map<PbClass*, Real> mValScale;
+};
+
+}
+
+#endif
diff --git a/source/blender/python/manta_full/source/gui/particlepainter.cpp b/source/blender/python/manta_full/source/gui/particlepainter.cpp
new file mode 100644
index 00000000000..f9761255f51
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/particlepainter.cpp
@@ -0,0 +1,456 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Painting particle systems
+ *
+ ******************************************************************************/
+
+#include <ctime>
+#include "particlepainter.h"
+#include <sstream>
+#include <iomanip>
+#include <QtOpenGL>
+#include "vortexpart.h"
+//#include "vortexfilament.h"
+#include "turbulencepart.h"
+
+using namespace std;
+
+namespace Manta {
+
+ParticlePainter::ParticlePainter(GridPainter<int>* gridRef, QWidget* par)
+ : LockedObjPainter(par), mGridRef(gridRef), mLocal(0), mMode(PaintVel), mDisplayMode(0),
+ mLastPdata(-1), mHavePdata(false), mMaxVal(0.)
+{
+ mInfo = new QLabel();
+}
+
+ParticlePainter::~ParticlePainter() {
+ if (mLocal)
+ delete mLocal;
+}
+
+void ParticlePainter::attachWidget(QLayout* layout) {
+ layout->addWidget(mInfo);
+}
+
+void ParticlePainter::update() {
+ ParticleBase* src = (ParticleBase*) mObject;
+
+ // always reallocate
+ if (mLocal)
+ delete mLocal;
+
+ mLocal = src->clone();
+
+ updateText();
+}
+
+string ParticlePainter::getID() { return "ParticleBase"; }
+
+Real ParticlePainter::getScale() {
+ if (!mObject) return 0;
+
+ if (mValScale.find(mObject) == mValScale.end()) {
+ Real s = 1.0;
+ //if (mLocalGrid->getType() & GridBase::TypeVec3) s = 0.4;
+ mValScale[mObject] = s;
+ }
+ return mValScale[mObject];
+
+}
+
+void ParticlePainter::processKeyEvent(PainterEvent e, int param) {
+ if (e == EventNextSystem)
+ nextObject();
+ else if (e == EventScalePdataDown && mObject)
+ mValScale[mObject] = getScale() * 0.5;
+ else if (e == EventScalePdataUp && mObject)
+ mValScale[mObject] = getScale() * 2.0;
+ else if (e == EventToggleParticles) {
+ mMode++; // apply modulo later depending on particle system
+ //if(mMode>PaintVel) mMode=PaintOff;
+ }
+ else if (e == EventNextParticleDisplayMode) {
+ mDisplayMode++;
+ }
+ else return;
+
+ updateText();
+}
+
+void ParticlePainter::updateText() {
+ ostringstream s;
+
+ if (mObject && !(mMode==PaintOff) ) {
+ s << mLocal->infoString() << endl;
+ s << mPdataInfo;
+ if(mHavePdata) {
+ s << "-> Max " << fixed << setprecision(2) << mMaxVal << " Scale " << getScale() << endl;
+ }
+ }
+ mInfo->setText( s.str().c_str() );
+}
+
+
+static inline void glVertex(const Vec3& v, Real dx) {
+ glVertex3f(v.x * dx, v.y * dx, v.z * dx);
+}
+
+static inline void glColor(const Vec3& color) {
+ glColor3f( std::max(0.0f,std::min(1.0f,(float)color.x)),
+ std::max(0.0f,std::min(1.0f,(float)color.y)),
+ std::max(0.0f,std::min(1.0f,(float)color.z)) );
+}
+
+void ParticlePainter::paint() {
+ if (!mObject) return;
+ if (mMode == PaintOff) return;
+ float dx = mLocal->getParent()->getDx();
+ mHavePdata = false;
+ mMaxVal = 0.;
+
+ glDisable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST); // disable depth test for particles, clashes with display plane for regular ones
+ glDisable(GL_LIGHTING);
+
+ // draw points
+ if(mLocal->getType() == ParticleBase::VORTEX) {
+ VortexParticleSystem* vp = (VortexParticleSystem*) mLocal;
+ glColor3f(1,1,0);
+ for(int i=0; i<vp->size(); i++) {
+ if (vp->isActive(i)) {
+ Vec3 pos = (*vp)[i].pos;
+
+ glPointSize((*vp)[i].sigma);
+
+ glBegin(GL_POINTS);
+ glVertex(pos, dx);
+ glEnd();
+ }
+ }
+ } else if (mLocal->getType() == ParticleBase::FILAMENT) {
+ // Filaments don't work yet
+ /*VortexFilamentSystem* fp = (VortexFilamentSystem*) mLocal;
+ glColor3f(1,1,0);
+
+ for(int i=0; i<fp->segSize(); i++) {
+ if (!fp->isSegActive(i)) continue;
+ const VortexRing& r = fp->seg(i);
+
+ glPointSize(1.0);
+ glBegin(GL_LINES);
+ for(int j=0; j<r.size(); j++) {
+ glVertex( (*fp)[r.idx0(j)].pos, dx);
+ glVertex( (*fp)[r.idx1(j)].pos, dx);
+ }
+ glEnd();
+ } */
+ } else if(mLocal->getType() == ParticleBase::TURBULENCE) {
+ TurbulenceParticleSystem* vp = (TurbulenceParticleSystem*) mLocal;
+ glPointSize(2.5);
+ glColor3f(0,1,0);
+ glBegin(GL_POINTS);
+ for(int i=0; i<(int)vp->size(); i++) {
+ Vec3 pos = (*vp)[i].pos;
+ glColor((*vp)[i].color);
+ glVertex(pos, dx);
+
+ }
+ glEnd();
+
+ } else if(mLocal->getType() == ParticleBase::PARTICLE) {
+ paintBasicSys();
+#if 0
+ BasicParticleSystem* bp = (BasicParticleSystem*) mLocal;
+
+ // draw other particle data, if available
+ int pdataId = mMode % (bp->getNumPdata() + 2);
+ std::ostringstream infoStr;
+ bool drewPoints = false;
+
+ if( pdataId==0 ) {
+ // dont draw any points
+ infoStr << "Off\n";
+ drewPoints = true;
+ } else if( pdataId==1 ) {
+ // dont draw data, only flags with center below
+ infoStr << "Drawing center & flags\n";
+ } else if (bp->getNumPdata() > 0) {
+ int pdNum = pdataId-2; // start at 0
+ ParticleDataBase* pdb = bp->getPdata(pdNum);
+
+ switch (pdb->getType() ) {
+
+ case ParticleDataBase::DATA_REAL: {
+ ParticleDataImpl<Real>* pdi = dynamic_cast<ParticleDataImpl<Real>*>(pdb);
+ if(!pdi) break;
+ mHavePdata = true;
+ drewPoints = true;
+ glPointSize(1.5);
+ glBegin(GL_POINTS);
+ for(int i=0; i<(int)bp->size(); i++) {
+ if (!bp->isActive(i)) continue;
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+ mMaxVal = std::max( pdi->get(i), mMaxVal );
+ Real val = pdi->get(i) * scale;
+ glColor3f(0,val,0);
+ glVertex(pos, dx);
+ }
+ glEnd();
+ infoStr << "Pdata '"<<pdi->getName()<<"' #"<<pdNum<<", real\n";
+ } break;
+
+ case ParticleDataBase::DATA_INT: {
+ ParticleDataImpl<int>* pdi = dynamic_cast<ParticleDataImpl<int>*>(pdb);
+ if(!pdi) break;
+ mHavePdata = true;
+ drewPoints = true;
+ glPointSize(1.5);
+ glBegin(GL_POINTS);
+ for(int i=0; i<(int)bp->size(); i++) {
+ if (!bp->isActive(i)) continue;
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+ Real val = pdi->get(i);
+ mMaxVal = std::max( val, mMaxVal );
+ val *= scale;
+ glColor3f(0,val,0);
+ glVertex(pos, dx);
+ }
+ glEnd();
+ infoStr << "Pdata '"<<pdi->getName()<<"' #"<<pdNum<<", int\n";
+ } break;
+
+ case ParticleDataBase::DATA_VEC3: {
+ ParticleDataImpl<Vec3>* pdi = dynamic_cast<ParticleDataImpl<Vec3>*>(pdb);
+ if(!pdi) break;
+ mHavePdata = true;
+ glBegin(GL_LINES);
+ for(int i=0; i<(int)bp->size(); i++) {
+ if (!bp->isActive(i)) continue;
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+ mMaxVal = std::max( norm(pdi->get(i)), mMaxVal );
+ Vec3 val = pdi->get(i) * scale;
+ glColor3f(0.5,0.0,0);
+ glVertex(pos, dx);
+ pos += val;
+ glColor3f(0.5,1.0,0);
+ glVertex(pos, dx);
+ }
+ glEnd();
+ infoStr << "Pdata '"<<pdi->getName()<<"' #"<<pdNum<<", vec3\n";
+ } break;
+
+ default: {
+ // skip...
+ } break;
+ }
+ }
+
+ mPdataInfo = infoStr.str();
+ // enforce refresh upon change
+ if(mLastPdata!=pdataId) {
+ mLastPdata = pdataId;
+ updateText();
+ }
+
+ // otherwise draw center
+ if(!drewPoints) {
+ glPointSize(1.5);
+ glBegin(GL_POINTS);
+
+ for(int i=0; i<(int)bp->size(); i++) {
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+
+ if(!bp->isActive(i) ) {
+ glColor3f(1.0, 0., 0.); // deleted, red
+ } else if(bp->getStatus(i) & ParticleBase::PNEW ) {
+ glColor3f(0.0, 1.0, 0.); // new, greem
+ } else {
+ glColor3f(0, 0.0, 1.0); // regular, blue
+ }
+ glVertex(pos, dx);
+
+ }
+ glEnd();
+ }
+
+ // draw basic part sys done
+#endif
+ }
+
+ glPointSize(1.0);
+ glEnable(GL_DEPTH_TEST);
+}
+
+void ParticlePainter::paintBasicSys() {
+ BasicParticleSystem* bp = (BasicParticleSystem*) mLocal;
+ //int dim = mGridRef->getDim();
+
+ // obtain current plane & draw settings
+ int dim = mGridRef->getDim();
+ Real factor = mGridRef->getMax() / mLocal->getParent()->getGridSize()[dim];
+ int plane = factor * mGridRef->getPlane();
+ Real scale = getScale();
+ float dx = mLocal->getParent()->getDx();
+
+ // draw other particle data, if available
+ int pdataId = mMode % (bp->getNumPdata() + 2);
+ std::ostringstream infoStr;
+ bool drewPoints = false;
+
+ if( pdataId==0 ) {
+ // dont draw any points
+ infoStr << "Off\n";
+ drewPoints = true;
+ } else if( pdataId==1 ) {
+ // dont draw data, only flags with center below
+ infoStr << "Drawing center & flags\n";
+ } else if (bp->getNumPdata() > 0) {
+ int pdNum = pdataId-2; // start at 0
+ ParticleDataBase* pdb = bp->getPdata(pdNum);
+
+ switch (pdb->getType() ) {
+
+ case ParticleDataBase::DATA_REAL: {
+ ParticleDataImpl<Real>* pdi = dynamic_cast<ParticleDataImpl<Real>*>(pdb);
+ if(!pdi) break;
+ mHavePdata = true;
+ drewPoints = true;
+ glPointSize(1.5);
+ glBegin(GL_POINTS);
+ for(int i=0; i<(int)bp->size(); i++) {
+ if (!bp->isActive(i)) continue;
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+ mMaxVal = std::max( pdi->get(i), mMaxVal );
+ Real val = pdi->get(i) * scale;
+ glColor3f(0,val,0);
+ glVertex(pos, dx);
+ }
+ glEnd();
+ infoStr << "Pdata '"<<pdi->getName()<<"' #"<<pdNum<<", real\n";
+ } break;
+
+ case ParticleDataBase::DATA_INT: {
+ ParticleDataImpl<int>* pdi = dynamic_cast<ParticleDataImpl<int>*>(pdb);
+ if(!pdi) break;
+ mHavePdata = true;
+ drewPoints = true;
+ glPointSize(1.5);
+ glBegin(GL_POINTS);
+ for(int i=0; i<(int)bp->size(); i++) {
+ if (!bp->isActive(i)) continue;
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+ Real val = pdi->get(i);
+ mMaxVal = std::max( val, mMaxVal );
+ val *= scale;
+ glColor3f(0,val,0);
+ glVertex(pos, dx);
+ }
+ glEnd();
+ infoStr << "Pdata '"<<pdi->getName()<<"' #"<<pdNum<<", int\n";
+ } break;
+
+ case ParticleDataBase::DATA_VEC3: {
+ ParticleDataImpl<Vec3>* pdi = dynamic_cast<ParticleDataImpl<Vec3>*>(pdb);
+ if(!pdi) break;
+ mHavePdata = true;
+
+ // particle vector data can be drawn in different ways...
+ mDisplayMode = mDisplayMode%2;
+
+ switch(mDisplayMode) {
+ case 0: // lines
+ glBegin(GL_LINES);
+ for(int i=0; i<(int)bp->size(); i++) {
+ if (!bp->isActive(i)) continue;
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+ mMaxVal = std::max( norm(pdi->get(i)), mMaxVal );
+ Vec3 val = pdi->get(i) * scale;
+ glColor3f(0.5,0.0,0);
+ glVertex(pos, dx);
+ pos += val;
+ glColor3f(0.5,1.0,0);
+ glVertex(pos, dx);
+ }
+ glEnd();
+ break;
+ case 1:
+ // colored points
+ glPointSize(2.0);
+ glBegin(GL_POINTS);
+ for(int i=0; i<(int)bp->size(); i++) {
+ if (!bp->isActive(i)) continue;
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+ mMaxVal = std::max( norm(pdi->get(i)), mMaxVal );
+ Vec3 val = pdi->get(i) * scale;
+ for(int c=0; c<3; ++c) val[c] = fmod( (Real)val[c], (Real)1.);
+
+ glColor3f(val[0],val[1],val[2]);
+ glVertex(pos, dx);
+ //pos += val;
+ //glColor3f(0.5,1.0,0);
+ //glVertex(pos, dx);
+ }
+ glEnd();
+ drewPoints = true;
+ break;
+ }
+
+ infoStr << "Pdata '"<<pdi->getName()<<"' #"<<pdNum<<", vec3\n";
+ } break;
+
+ default: {
+ // skip...
+ } break;
+ }
+ }
+
+ mPdataInfo = infoStr.str();
+ // enforce refresh upon change
+ if(mLastPdata!=pdataId) {
+ mLastPdata = pdataId;
+ updateText();
+ }
+
+ // otherwise draw center
+ if(!drewPoints) {
+ glPointSize(1.5);
+ glBegin(GL_POINTS);
+
+ for(int i=0; i<(int)bp->size(); i++) {
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+
+ if(!bp->isActive(i) ) {
+ glColor3f(1.0, 0., 0.); // deleted, red
+ } else if(bp->getStatus(i) & ParticleBase::PNEW ) {
+ glColor3f(0.0, 1.0, 0.); // new, greem
+ } else {
+ glColor3f(0, 0.0, 1.0); // regular, blue
+ }
+ glVertex(pos, dx);
+
+ }
+ glEnd();
+ }
+
+ // draw basic part sys done
+}
+
+} // namespace
+
diff --git a/source/blender/python/manta_full/source/gui/particlepainter.h b/source/blender/python/manta_full/source/gui/particlepainter.h
new file mode 100644
index 00000000000..da0a208b3e1
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/particlepainter.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Painting particle systems
+ *
+ ******************************************************************************/
+
+#ifndef _PARTICLEPAINTER_H_
+#define _PARTICLEPAINTER_H_
+
+#include "painter.h"
+#include "particle.h"
+
+namespace Manta {
+
+//! Painter object for Particle Systems
+class ParticlePainter : public LockedObjPainter {
+ Q_OBJECT
+public:
+ ParticlePainter(GridPainter<int>* gridRef, QWidget* par = 0);
+ ~ParticlePainter();
+
+ void paint();
+ void attachWidget(QLayout* layout);
+
+ enum PaintModes { PaintOff=0, PaintVel=1, PaintPos=2 };
+
+protected:
+ std::string getID();
+ Real getScale();
+ void update();
+ void updateText();
+ void processKeyEvent(PainterEvent e, int param);
+
+ GridPainter<int>* mGridRef;
+ ParticleBase* mLocal;
+ QLabel* mInfo;
+
+ //! for standard particle systems, this is used to select the data channel (display is changed with displayMode below)
+ int mMode;
+ //! for BasicParticleSystem , change the way data channels are displayed
+ int mDisplayMode;
+
+ int mLastPdata;
+ bool mHavePdata;
+ Real mMaxVal;
+ std::string mPdataInfo;
+ std::map<PbClass*, Real> mValScale;
+
+ void paintBasicSys();
+};
+
+} // namespace
+
+#endif
diff --git a/source/blender/python/manta_full/source/gui/qtmain.cpp b/source/blender/python/manta_full/source/gui/qtmain.cpp
new file mode 100644
index 00000000000..64ec6f388e6
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/qtmain.cpp
@@ -0,0 +1,150 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * QT threads
+ *
+ ******************************************************************************/
+
+#include "mainwindow.h"
+#include "qtmain.h"
+#include "customctrl.h"
+
+using namespace std;
+
+// execute python script
+// from pymain.cpp
+extern void runScript(vector<string>& args);
+
+namespace Manta {
+
+GuiThread* gGuiThread = NULL;
+MainThread* gMainThread = NULL;
+
+MainThread::MainThread(vector<string>& args) : mFinished(false), mArgs(args) {
+}
+
+void MainThread::run() {
+ runScript(mArgs);
+}
+
+void MainThread::sendAndWait(int e) {
+ mMutex.lock();
+ emit sendToGui(e);
+ while(!mWait.wait(&mMutex, 250))
+ if (gGuiThread->getWindow()->closeRequest()) {
+ mMutex.unlock();
+ throw Error("User interrupt");
+ }
+ mMutex.unlock();
+}
+
+void MainThread::send(int e) {
+ emit sendToGui(e);
+}
+
+void MainThread::killMe() {
+ if (!mFinished) {
+ wait(1000);
+ if (!mFinished) {
+ cout << "worker thread still running, terminate" << endl;
+ terminate();
+ return;
+ }
+ }
+ wait();
+}
+
+void MainThread::wakeUp() {
+ mMutex.lock();
+ mWait.wakeAll();
+ mMutex.unlock();
+}
+
+GuiThread::GuiThread(QApplication& app) : mApp(app), mWnd() {
+}
+
+void GuiThread::sendEvent(int e) {
+ mApp.postEvent(&mWnd, new QEvent((QEvent::Type)e));
+}
+
+void GuiThread::exitApp() {
+ mApp.exit(1);
+}
+
+void guiMain(int argc, char* argv[]) {
+ QApplication app(argc, argv);
+
+ // parse arguments
+ vector<string> args;
+ for (int i=1;i<argc;i++) args.push_back(argv[i]);
+
+ // Show file dialog if no argument is present
+ if (argc <= 1) {
+ QString filename = QFileDialog::getOpenFileName(0, "Open scene file", "", "Python scene files (*.py)");
+ args.push_back(filename.toLatin1().data());
+ }
+
+ GuiThread gui(app);
+ MainThread worker(args);
+
+ gGuiThread = &gui;
+ gMainThread = &worker;
+
+ // connect thread wakeup and termination signals
+ QObject::connect(&worker, SIGNAL(sendToGui(int)), &gui, SLOT(sendEvent(int)));
+ QObject::connect(gui.getWindow(), SIGNAL(wakeMain()), &worker, SLOT(wakeUp()));
+ QObject::connect(gui.getWindow(), SIGNAL(killMain()), &worker, SLOT(killMe()));
+ QObject::connect(gui.getWindow(), SIGNAL(exitApp()), &gui, SLOT(exitApp()));
+ app.setQuitOnLastWindowClosed(true);
+
+ // Start main program threads
+ worker.start();
+ app.exec();
+}
+
+void guiWaitFinish() {
+ gMainThread->setFinished();
+ gMainThread->send((int)MainWnd::EventInstantKill);
+ /*
+ if (gGuiThread->getWindow()->closeRequest())
+ return;
+
+ gMainThread->sendAndWait((int)MainWnd::EventFinalUpdate);
+ gGuiThread->getWindow()->pause();
+ while (gGuiThread->getWindow()->pauseRequest())
+ gMainThread->threadSleep(10); */
+}
+
+//******************************************************************************
+// Python adapter class
+
+
+// external callback functions
+void updateQtGui(bool full, int frame, const string& curPlugin) {
+ if (!gGuiThread->getWindow()->isVisible()) return;
+ if (gGuiThread->getWindow()->closeRequest()) throw Error("User interrupt");
+
+ if (full && frame >= 0) gGuiThread->getWindow()->setFrame(frame);
+ gMainThread->sendAndWait(full ? (int)MainWnd::EventFullUpdate : (int)MainWnd::EventStepUpdate);
+
+ if (gGuiThread->getWindow()->pauseRequest()) {
+ if (!curPlugin.empty()) {
+ cout << "Step: " << curPlugin << endl;
+ }
+ gGuiThread->getWindow()->setPauseStatus(true);
+ while (gGuiThread->getWindow()->pauseRequest()) {
+ gMainThread->threadSleep(10);
+ }
+ if (gGuiThread->getWindow()->closeRequest()) throw Error("User interrupt");
+ gGuiThread->getWindow()->setPauseStatus(false);
+ }
+ gGuiThread->getWindow()->stepReset(full);
+}
+
+} //namespace
diff --git a/source/blender/python/manta_full/source/gui/qtmain.h b/source/blender/python/manta_full/source/gui/qtmain.h
new file mode 100644
index 00000000000..7037b2e2cf1
--- /dev/null
+++ b/source/blender/python/manta_full/source/gui/qtmain.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * QT threads
+ *
+ ******************************************************************************/
+#ifndef _QTMAIN_H_
+#define _QTMAIN_H_
+
+#include <QThread>
+#include <QApplication>
+#include <vector>
+#include <QMutex>
+#include <QWaitCondition>
+#include "mainwindow.h"
+#include "manta.h"
+
+namespace Manta {
+
+//! encapsulates GUI thread
+class GuiThread : public QObject {
+ Q_OBJECT
+public:
+
+ GuiThread(QApplication& app);
+
+ //! obtain window handle
+ inline MainWnd* getWindow() { return &mWnd; }
+
+public slots:
+ void sendEvent(int e);
+ void exitApp();
+
+protected:
+ QApplication& mApp;
+ MainWnd mWnd;
+};
+
+//! encapsulates working/python thread
+class MainThread : public QThread {
+ Q_OBJECT
+public:
+ MainThread(std::vector<std::string>& args);
+
+ //! send event to GUI and wait for completion
+ void sendAndWait(int e);
+ void send(int e);
+
+ //! sleep for given number of milliseconds
+ inline void threadSleep(int msec) { msleep(msec); }
+ inline bool isFinished() { return mFinished; }
+ inline void setFinished() { mFinished = true; }
+
+public slots:
+ void wakeUp();
+ void killMe();
+
+signals:
+ void sendToGui(int event);
+
+protected:
+ QMutex mMutex;
+ QWaitCondition mWait;
+ bool mFinished;
+ std::vector<std::string> mArgs;
+ void run();
+};
+
+} // namespace
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/kernel.cpp b/source/blender/python/manta_full/source/kernel.cpp
new file mode 100644
index 00000000000..f8fdda8d751
--- /dev/null
+++ b/source/blender/python/manta_full/source/kernel.cpp
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Function and macros for defining compution kernels over grids
+ *
+ ******************************************************************************/
+
+#include "kernel.h"
+#include "grid.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),
+ X (base->getStrideX()),
+ Y (base->getStrideY()),
+ Z (base->getStrideZ()),
+ size (base->getSizeX() * base->getSizeY() * base->getSizeZ()),
+ threadId(0),threadNum(1) {}
+
+KernelBase::KernelBase(int sz) :
+ size(sz),
+ threadId(0),threadNum(1) {}
+
+
+} // namespace
diff --git a/source/blender/python/manta_full/source/kernel.h b/source/blender/python/manta_full/source/kernel.h
new file mode 100644
index 00000000000..4c71b090d13
--- /dev/null
+++ b/source/blender/python/manta_full/source/kernel.h
@@ -0,0 +1,80 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Function and macros for defining compution kernels over grids
+ *
+ ******************************************************************************/
+
+#ifndef _KERNEL_H
+#define _KERNEL_H
+
+#ifdef TBB
+# include <tbb/blocked_range3d.h>
+# include <tbb/blocked_range.h>
+# include <tbb/parallel_for.h>
+# include <tbb/parallel_reduce.h>
+#endif
+
+#ifdef OPENMP
+# include <omp.h>
+#endif
+
+namespace Manta {
+// fwd decl
+class GridBase;
+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(int idx=0, total=(grid).getSizeX()*(grid).getSizeY()*(grid).getSizeZ(); idx<total; idx++)
+
+#define FOR_IJK(grid) FOR_IJK_BND(grid, 0)
+
+
+struct KernelBase {
+ int maxX, maxY, maxZ, minZ;
+ int X, Y, Z;
+ int size;
+ //! store thread info for this kernel
+ int threadId, threadNum;
+
+ KernelBase(int num);
+ KernelBase(const GridBase* base, int bnd);
+ //KernelBase(int _maxX, int _maxY, int _maxZ, int _maxC, int _minZ, int _X, int _Y, int _Z);
+
+ // specify in your derived classes:
+
+ // kernel operators
+ // ijk mode: void operator() (size_t idx)
+ // idx mode: void operator() (size_t i, size_t j, size_t k)
+
+ // reduce mode:
+ // void join(classname& other)
+ // void setup()
+};
+
+} // namespace
+
+// Define plugin documentation group
+// all kernels will automatically be added to this group
+/*! @defgroup Kernels Computation Kernels
+ */
+
+#endif
diff --git a/source/blender/python/manta_full/source/levelset.cpp b/source/blender/python/manta_full/source/levelset.cpp
new file mode 100644
index 00000000000..eab16ae7e18
--- /dev/null
+++ b/source/blender/python/manta_full/source/levelset.cpp
@@ -0,0 +1,334 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Levelset
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "fastmarch.h"
+#include "kernel.h"
+#include "mcubes.h"
+#include "mesh.h"
+
+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) };
+
+KERNEL(bnd=1)
+void InitFmIn (FlagGrid& flags, Grid<int>& fmFlags, LevelsetGrid& phi, bool ignoreWalls, int obstacleType) {
+ const int idx = flags.index(i,j,k);
+ const Real v = phi[idx];
+ if (v>=0 && (!ignoreWalls || (flags[idx] & obstacleType) == 0))
+ fmFlags[idx] = FlagInited;
+ else
+ fmFlags[idx] = 0;
+}
+
+KERNEL(bnd=1)
+void InitFmOut (FlagGrid& flags, Grid<int>& fmFlags, LevelsetGrid& phi, bool ignoreWalls, int obstacleType) {
+ const int 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;
+}
+
+KERNEL(bnd=1)
+void SetUninitialized (Grid<int>& fmFlags, LevelsetGrid& phi, const Real val) {
+ if (fmFlags(i,j,k) != FlagInited)
+ phi(i,j,k) = val;
+}
+
+template<bool inward>
+inline bool isAtInterface(Grid<int>& fmFlags, LevelsetGrid& phi, const Vec3i& p) {
+ // check for interface
+ for (int nb=0; nb<6; 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;
+}
+
+// helper function to compute normal
+inline Vec3 getNormal(const Grid<Real>& data, int i, int j, int k) {
+ 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 (i < 1) i = 1;
+ if (j < 1) j = 1;
+ if (k < 1) k = 1;
+ 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+1) - data(i ,j ,k-1) );
+}
+
+//************************************************************************
+// Levelset class def
+
+LevelsetGrid::LevelsetGrid(FluidSolver* parent, bool show)
+ : Grid<Real>(parent, show)
+{
+ mType = (GridType)(TypeLevelset | TypeReal);
+}
+
+Real LevelsetGrid::invalidTimeValue() {
+ return FastMarch<FmHeapEntryOut, 1>::InvalidTime();
+}
+
+//! Kernel: perform levelset union
+KERNEL(idx) void KnJoin(Grid<Real>& a, const Grid<Real>& b) {
+ a[idx] = min(a[idx], b[idx]);
+}
+
+void LevelsetGrid::join(const LevelsetGrid& o) {
+ KnJoin(*this, o);
+}
+
+//! re-init levelset and extrapolate velocities (in & out)
+// note - uses flags to identify border (could also be done based on ls values)
+void LevelsetGrid::reinitMarching(
+ FlagGrid& flags, Real maxTime, MACGrid* velTransport,
+ bool ignoreWalls, bool correctOuterLayer, int obstacleType
+ , Grid<Real>* normSpeed )
+{
+ const int dim = (is3D() ? 3 : 2);
+
+ Grid<int> fmFlags(mParent);
+ LevelsetGrid& phi = *this;
+
+ FastMarch<FmHeapEntryIn, -1> marchIn (flags, fmFlags, phi, maxTime, NULL, NULL);
+
+ // march inside
+ InitFmIn (flags, fmFlags, phi, ignoreWalls, obstacleType);
+
+ FOR_IJK_BND(flags, 1) {
+ if (fmFlags(i,j,k) == FlagInited) continue;
+ if ((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 ((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 (fmFlags, phi, -maxTime - 1.);
+
+ InitFmOut (flags, fmFlags, phi, ignoreWalls, obstacleType);
+
+ FastMarch<FmHeapEntryOut, +1> marchOut(flags, fmFlags, phi, maxTime, velTransport, normSpeed);
+
+ // NT_DEBUG
+ if(normSpeed && velTransport) {
+ FOR_IJK_BND(flags, 1) {
+ Vec3 vel = velTransport->getCentered(i,j,k);
+ Vec3 norm = getNormal(phi, i,j,k); normalize(norm);
+ (*normSpeed)(i,j,k) = dot( norm , vel );
+ }
+ }
+
+ // 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 ((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 ((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 ((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 ((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 (fmFlags, phi, +maxTime + 1.);
+
+}
+
+void LevelsetGrid::initFromFlags(FlagGrid& flags, bool ignoreWalls) {
+ FOR_IDX(*this) {
+ if (flags.isFluid(idx) || (ignoreWalls && flags.isObstacle(idx)))
+ mData[idx] = -0.5;
+ else
+ mData[idx] = 0.5;
+ }
+}
+
+// note - the following functions are experimental, might be removed at some point NT_DEBUG
+KERNEL(idx) void knGridRemapLsMask (Grid<Real>& me, Real min, Real max, Real fac) {
+ me[idx] = (clamp(me[idx], min, max) - min) * fac;
+
+ // now we have 0..1 range, convert to hat around 1/2
+ me[idx] = me[idx] * 2.;
+ if(me[idx]>1.0) me[idx] = 2. - me[idx];
+}
+// remap min/max range to hat function around (min+max)/2
+PYTHON void remapLsMask(Grid<Real>& phi, Real min, Real max) {
+ Real fac = 0.;
+ if ( fabs(max-min) > VECTOR_EPSILON ) fac = 1. / (max-min);
+ knGridRemapLsMask(phi, min, max, fac);
+}
+
+//! 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;
+ vertex.normal = getNormalized(
+ getNormal( *this, i+cubieOffsetX[e1], j+cubieOffsetY[e1], k+cubieOffsetZ[e1]) * (1.0-mu) +
+ getNormal( *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();
+}
+
+
+} //namespace
diff --git a/source/blender/python/manta_full/source/levelset.h b/source/blender/python/manta_full/source/levelset.h
new file mode 100644
index 00000000000..1dd023110ab
--- /dev/null
+++ b/source/blender/python/manta_full/source/levelset.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Levelset
+ *
+ ******************************************************************************/
+
+#ifndef _LEVELSET_H_
+#define _LEVELSET_H_
+
+#include "grid.h"
+
+namespace Manta {
+class Mesh;
+
+//! Special function for levelsets
+PYTHON class LevelsetGrid : public Grid<Real> {
+public:
+ PYTHON LevelsetGrid(FluidSolver* parent, bool show = true);
+
+ //! reconstruct the levelset using fast marching
+ PYTHON void reinitMarching(FlagGrid& flags, Real maxTime=4.0,
+ MACGrid* velTransport=NULL, bool ignoreWalls=false, bool correctOuterLayer=true,
+ int obstacleType = FlagGrid::TypeObstacle, Grid<Real>* scalarTransport = NULL );
+ //! create a triangle mesh from the levelset isosurface
+ PYTHON void createMesh(Mesh& mesh);
+
+ //! union with another levelset
+ PYTHON void join(const LevelsetGrid& o);
+
+ //! initialize levelset from flags (+/- 0.5 heaviside)
+ PYTHON void initFromFlags(FlagGrid& flags, bool ignoreWalls=false);
+
+ static Real invalidTimeValue();
+};
+
+} //namespace
+#endif
diff --git a/source/blender/python/manta_full/source/mesh.cpp b/source/blender/python/manta_full/source/mesh.cpp
new file mode 100644
index 00000000000..1291ec98a95
--- /dev/null
+++ b/source/blender/python/manta_full/source/mesh.cpp
@@ -0,0 +1,775 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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 "fileio.h"
+#include "kernel.h"
+#include "shapes.h"
+#include <stack>
+
+using namespace std;
+namespace Manta {
+
+Mesh::Mesh(FluidSolver* parent) : PbClass(parent) {
+}
+
+Mesh::~Mesh() {
+}
+
+Mesh* Mesh::clone() {
+ Mesh* nm = new Mesh(mParent);
+ *nm = *this;
+ nm->setName(getName());
+ return nm;
+}
+
+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/3.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);
+}
+
+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 == ".obj")
+ readObjFile(name, this, append);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+
+ 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);
+}
+
+
+//! 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());
+}
+
+KERNEL(pts) returns(vector<Vec3> u(size))
+vector<Vec3> KnAdvectMeshInGrid(vector<Node>& nodes, const FlagGrid& flags, const MACGrid& vel, const Real dt) {
+ if (nodes[idx].flags & Mesh::NfFixed)
+ u[idx] = _0;
+ else if (!flags.isInBounds(nodes[idx].pos,1))
+ u[idx] = _0;
+ else
+ u[idx] = vel.getInterpolated(nodes[idx].pos) * dt;
+}
+
+// advection plugin
+void Mesh::advectInGrid(FlagGrid& flaggrid, MACGrid& vel, int integrationMode) {
+ KnAdvectMeshInGrid kernel(mNodes, flaggrid, 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::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());
+ 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");
+ }
+ }
+ }
+ }
+}
+
+ void Mesh::SDFKernel(const int* partStart, const int* partLen, CVec3Ptr pos, CVec3Ptr normal, float* sdf, Vec3i gridRes, int intRadius, float safeRadius2, float cutoff2, float 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);
+ float sum = 0.0f;
+ float 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);
+ float 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);
+ float normSqr = r[0]*r[0] + r[1]*r[1] + r[2]*r[2];
+ float r2 = normSqr;
+ if (r2 < cutoff2) {
+ float 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;
+ }
+ }
+ }
+ }
+
+ inline int _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
+ KERNEL template<class T>
+ void ApplyMeshToGrid (Grid<T>* grid, Grid<Real> sdf, T value, FlagGrid* respectFlags) {
+ if (respectFlags && respectFlags->isObstacle(i,j,k))
+ return;
+ if (sdf(i,j,k) < 0)
+ {
+ (*grid)(i,j,k) = value;
+ }
+ }
+
+ void Mesh::applyToGrid(GridBase* grid, FlagGrid* respectFlags, float cutoff) {
+ FluidSolver dummy(grid->getSize());
+ LevelsetGrid mesh_sdf(&dummy, false);
+ meshSDF(*this, mesh_sdf, 2., _args.get<float>("cutoff"));
+
+ 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");
+ }
+
+ void Mesh::meshSDF(Mesh& mesh, LevelsetGrid & levelset, float sigma, float cutoff)
+ {
+ if (cutoff<0) cutoff = 2*sigma;
+ float maxEdgeLength = 0.75;
+ float 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(size_t 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;
+ }
+
+ short axisA(0), axisB(1);
+ float u(0.),v(0.),w(0.); //barycentric uvw coords
+ Vec3 samplePoint,normal;
+ for (int sample0(0); sample0 < iterA; ++sample0){
+ u = float(1. * sample0 / iterA);
+ for (int sample1(0); sample1 < iterB; ++sample1){
+ v = float(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
+ const int numCells = gridRes.x * gridRes.y * gridRes.z;
+ vector<Real> gridDev(numCells);
+ for (int i=0; i<numCells; i++)
+ gridDev[i] = -cutoff;
+
+ // 1. count sources per cell
+ vector<int> srcPerCell(numCells);
+ for (size_t i=0; i<center.size(); i++) {
+ int cell = _cIndex(center[i], gridRes);
+ if (cell >= 0)
+ srcPerCell[cell]++;
+ }
+
+ // 2. create start index lookup
+ vector<int> srcCellStart(numCells);
+ int cnt=0;
+ for (int i=0; i<numCells; i++) {
+ srcCellStart[i] = cnt;
+ cnt += srcPerCell[i];
+ }
+
+ // 3. reorder nodes
+ CVec3Array reorderPos(center.size());
+ CVec3Array reorderNormal(center.size());
+ {
+ vector<int> curSrcCell(numCells);
+ for (int i=0; i<(int)center.size(); i++) {
+ int cell = _cIndex(center[i], gridRes);
+ if (cell < 0) continue;
+ int idx = srcCellStart[cell] + curSrcCell[cell];
+ reorderPos.set(idx, center[i]);
+ reorderNormal.set(idx, normals[i]);
+ curSrcCell[cell]++;
+ }
+ }
+
+ // construct parameters
+ float safeRadius = cutoff + sqrt(3.0)*0.5;
+ float safeRadius2 = safeRadius*safeRadius;
+ float cutoff2 = cutoff*cutoff;
+ float isigma2 = 1.0/(sigma*sigma);
+ int intRadius = (int)(cutoff+0.5);
+
+ SDFKernel(srcCellStart.data(), srcPerCell.data(),
+ reorderPos.data(), reorderNormal.data(),
+ gridDev.data(),
+ Vec3i(gridRes.x, gridRes.y, gridRes.z), intRadius, safeRadius2, cutoff2, isigma2);
+
+ for (int i=0;i<numCells; i++)
+ levelset[i] = gridDev[i];
+
+ // 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));
+ };
+ }
+
+} //namespace
diff --git a/source/blender/python/manta_full/source/mesh.h b/source/blender/python/manta_full/source/mesh.h
new file mode 100644
index 00000000000..e09c85801b7
--- /dev/null
+++ b/source/blender/python/manta_full/source/mesh.h
@@ -0,0 +1,257 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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 "grid.h"
+#include "vectorbase.h"
+#include <set>
+namespace Manta {
+
+// fwd decl
+class FlagGrid;
+class MACGrid;
+class Shape;
+
+//! 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;
+};
+
+/*!adapted from Cudatools.h
+*/
+struct CVec3Ptr {
+ float *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; };
+};
+
+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<float> x, y, z;
+};
+
+//! 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.*/
+PYTHON class Mesh : public PbClass {
+public:
+ PYTHON Mesh(FluidSolver* parent);
+ 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; }
+
+ void clear();
+ Real computeCenterOfMass(Vec3& cm) const;
+ void computeVertexNormals();
+
+ // plugins
+ PYTHON void load (std::string name, bool append = false);
+ PYTHON void fromShape (Shape& shape, bool append = false);
+ PYTHON void save (std::string name);
+ PYTHON void advectInGrid(FlagGrid& flaggrid, MACGrid& vel, int integrationMode);
+ PYTHON void scale(Vec3 s);
+ PYTHON void offset(Vec3 o);
+
+ // 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(); }
+
+ 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]; }
+
+ 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) { 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) { 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(); }
+ void SDFKernel(const int* partStart, const int* partLen, CVec3Ptr pos, CVec3Ptr normal, float* sdf, Vec3i gridRes, int intRadius, float safeRadius2, float cutoff2, float isigma2);
+ PYTHON void meshSDF(Mesh& mesh, LevelsetGrid& levelset, float sigma, float cutoff=-1);
+ PYTHON void applyToGrid(GridBase* grid, FlagGrid* respectFlags=0, float cutoff=-1);
+
+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;
+};
+
+
+
+
+// ***************************************************************************************************************
+// 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);
+}
+
+
+
+} //namespace
+#endif
diff --git a/source/blender/python/manta_full/source/movingobs.cpp b/source/blender/python/manta_full/source/movingobs.cpp
new file mode 100644
index 00000000000..227c074c823
--- /dev/null
+++ b/source/blender/python/manta_full/source/movingobs.cpp
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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++) {
+ mShapes[i]->_args.clear();
+ mShapes[i]->_args.add("value", FlagGrid::TypeObstacle | mID);
+ mShapes[i]->applyToGrid(&flags, 0);
+ }
+ // 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
diff --git a/source/blender/python/manta_full/source/movingobs.h b/source/blender/python/manta_full/source/movingobs.h
new file mode 100644
index 00000000000..fdaf8a66a03
--- /dev/null
+++ b/source/blender/python/manta_full/source/movingobs.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * moving obstacles
+ *
+ ******************************************************************************/
+
+#ifndef _MOVINGOBS_H
+#define _MOVINGOBS_H
+
+#include "shapes.h"
+#include "particle.h"
+
+namespace Manta {
+
+//! Moving obstacle composed of basic shapes
+PYTHON class MovingObstacle : public PbClass {
+public:
+ PYTHON MovingObstacle(FluidSolver* parent, int emptyType=FlagGrid::TypeEmpty);
+
+ PYTHON void add(Shape* shape);
+ //! If t in [t0,t1], apply linear motion path from p0 to p1
+ PYTHON void moveLinear(Real t, Real t0, Real t1, Vec3 p0, Vec3 p1, FlagGrid& flags, MACGrid& vel, bool smooth=true);
+ //! Compute levelset, and project FLIP particles outside obstacles
+ PYTHON void projectOutside(FlagGrid& flags, BasicParticleSystem& flip);
+
+protected:
+ std::vector<Shape*> mShapes;
+ int mEmptyType;
+ int mID;
+ static int sIDcnt;
+};
+
+
+} //namespace
+#endif
diff --git a/source/blender/python/manta_full/source/noisefield.cpp b/source/blender/python/manta_full/source/noisefield.cpp
new file mode 100644
index 00000000000..50d4b713af7
--- /dev/null
+++ b/source/blender/python/manta_full/source/noisefield.cpp
@@ -0,0 +1,296 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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;
+
+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) return;
+ Real *noise3 = new Real[n3d];
+ if(loadFromFile) {
+ FILE* fp = fopen(TILENAME,"rb");
+ if(fp) {
+ fread(noise3, sizeof(Real), n3d, fp);
+ fclose(fp);
+ debMsg("noise tile loaded from file! " , 1);
+ mNoiseTile = noise3;
+ 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;
+ delete[] temp13;
+ delete[] temp23;
+
+ if(loadFromFile) {
+ FILE* fp = fopen(TILENAME,"wb");
+ if(fp) {
+ fwrite(noise3, sizeof(Real), n3d, fp);
+ fclose(fp);
+ debMsg( "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;
+ }
+}
+
+
+
+
+
+}
diff --git a/source/blender/python/manta_full/source/noisefield.h b/source/blender/python/manta_full/source/noisefield.h
new file mode 100644
index 00000000000..0ee00cb2ba2
--- /dev/null
+++ b/source/blender/python/manta_full/source/noisefield.h
@@ -0,0 +1,393 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Wavelet noise field
+ *
+ ******************************************************************************/
+
+#ifndef _NOISEFIELD_H_
+#define _NOISEFIELD_H_
+
+#include "vectorbase.h"
+#include "manta.h"
+
+namespace Manta {
+
+#define NOISE_TILE_SIZE 128
+
+// wrapper for a parametrized field of wavelet noise
+PYTHON(name=NoiseField)
+class WaveletNoiseField : public PbClass {
+ public:
+ PYTHON WaveletNoiseField( FluidSolver* parent, int fixedSeed=-1 , int loadFromFile=false );
+ ~WaveletNoiseField() {
+ if(mNoiseTile) { delete mNoiseTile; mNoiseTile=NULL; }
+ };
+
+ //! evaluate noise
+ inline Real evaluate(Vec3 pos, int tile=0);
+ //! evaluate noise as a vector
+ inline Vec3 evaluateVec(Vec3 pos, int tile=0);
+ //! evaluate curl noise
+ inline Vec3 evaluateCurl(Vec3 pos);
+
+ //! 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
+ PYTHON(name=posOffset) Vec3 mPosOffset;
+ PYTHON(name=posScale) Vec3 mPosScale;
+ // value offset & scale
+ PYTHON(name=valOffset) Real mValOffset;
+ PYTHON(name=valScale) Real mValScale;
+ // clamp? (default 0-1)
+ PYTHON(name=clamp) bool mClamp;
+ PYTHON(name=clampNeg) Real mClampNeg;
+ PYTHON(name=clampPos) Real mClampPos;
+ // animated over time
+ PYTHON(name=timeAnim) Real mTimeAnim;
+
+ 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() { 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;
+};
+
+
+
+// **************************************************************************
+// 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) {
+ 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) {
+ 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) {
+ // 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
+
+#endif
diff --git a/source/blender/python/manta_full/source/particle.cpp b/source/blender/python/manta_full/source/particle.cpp
new file mode 100644
index 00000000000..ec530b1b7fb
--- /dev/null
+++ b/source/blender/python/manta_full/source/particle.cpp
@@ -0,0 +1,358 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2013 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
+ *
+ * Particle data functionality
+ *
+ ******************************************************************************/
+
+#include <fstream>
+#if NO_ZLIB!=1
+#include <zlib.h>
+#endif
+#include "particle.h"
+#include "levelset.h"
+#include "fileio.h"
+#include <cstring>
+
+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(int i=0; i<(int)mPartData.size(); ++i)
+ mPartData[i]->setParticleSys(NULL);
+
+ if(mFreePdata) {
+ for(int i=0; i<(int)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(int i=0; i<(int)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(int i=0; i<(int)mPartData.size(); ++i) {
+ if(mPartData[i] == pdata) {
+ if(i<(int)mPartData.size()-1)
+ mPartData[i] = mPartData[mPartData.size()-1];
+ mPartData.pop_back();
+ done = true;
+ }
+ }
+ if(!done)
+ errMsg("Invalid pointer given, not registered!");
+}
+
+PbClass* ParticleBase::create(PbType t, PbTypeVec T, const string& name) {
+ _args.add("nocheck",true);
+ if (t.str() == "")
+ errMsg("Specify particle data type to create");
+ //debMsg( "Pdata creating '"<< t.str , 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);
+ }
+
+ return pyObj;
+}
+
+void ParticleBase::registerPdata(ParticleDataBase* pdata) {
+ pdata->setParticleSys(this);
+ mPartData.push_back(pdata);
+
+ if( pdata->getType() == ParticleDataBase::DATA_REAL ) {
+ 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::DATA_VEC3 ) {
+ ParticleDataImpl<Vec3>* pd = dynamic_cast< ParticleDataImpl<Vec3>* >(pdata);
+ if(!pd) errMsg("Invalid pdata object posing as vec3!");
+ this->registerPdataVec3(pd);
+ }
+ else if( pdata->getType() == ParticleDataBase::DATA_INT ) {
+ ParticleDataImpl<int>* pd = dynamic_cast< ParticleDataImpl<int>* >(pdata);
+ if(!pd) errMsg("Invalid pdata object posing as int!");
+ this->registerPdataInt(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(int i=0; i<(int)mPartData.size(); ++i) {
+ mPartData[i]->add();
+ }
+}
+
+std::string ParticleBase::debugInfoPdata()
+{
+ std::ostringstream sstr;
+ sstr << "Particle system "<<mName<<" , size: "<< this->getSizeSlow() <<", data ";
+ for(int i=0; i<(int)mPartData.size(); ++i) {
+ sstr << i<<":" << mPartData[i]->size() <<" ";
+ }
+ sstr << ".";
+ return sstr.str();
+}
+
+
+BasicParticleSystem::BasicParticleSystem(FluidSolver* parent)
+ : ParticleSystem<BasicParticleData>(parent) {
+ this->mAllowCompress = false;
+}
+
+// file io
+
+void BasicParticleSystem::writeParticlesText(string name) {
+ 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(int i=0; i<this->size(); ++i) {
+ ofs << i<<": "<< this->getPos(i) <<" , "<< this->getStatus(i) <<". ";
+ for(int pd=0; pd<(int)mPdataInt.size() ; ++pd) ofs << mPdataInt [pd]->get(i)<<" ";
+ for(int pd=0; pd<(int)mPdataReal.size(); ++pd) ofs << mPdataReal[pd]->get(i)<<" ";
+ for(int pd=0; pd<(int)mPdataVec3.size(); ++pd) ofs << mPdataVec3[pd]->get(i)<<" ";
+ ofs << "\n";
+ }
+ ofs.close();
+}
+
+void BasicParticleSystem::writeParticlesRawPositionsGz(string name) {
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "wb1");
+ if (!gzf) errMsg("can't open file "<<name);
+ for(int 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(string name) {
+# 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(int 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(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<BasicParticleData>(name, this );
+ else
+ errMsg("particle '" + name +"' filetype not supported for loading");
+}
+
+void BasicParticleSystem::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 == ".txt")
+ this->writeParticlesText(name);
+ else if (ext == ".uni")
+ writeParticlesUni<BasicParticleData>(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");
+}
+
+// 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;
+}
+
+template<class T>
+ParticleDataImpl<T>::~ParticleDataImpl() {
+}
+
+template<class T>
+int ParticleDataImpl<T>::size() const {
+ return mData.size();
+}
+template<class T>
+void ParticleDataImpl<T>::add() {
+ // 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(int s) {
+ mData.resize(s);
+}
+template<class T>
+void ParticleDataImpl<T>::copyValueSlow(int from, int 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(int idx, Vec3 pos) {
+ if(!mpGridSource)
+ mData[idx] = 0;
+ else {
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ }
+}
+// special handling needed for velocities
+template<>
+void ParticleDataImpl<Vec3>::initNewValue(int 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
+ 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
+ errMsg("particle data '" + name +"' filetype not supported for saving");
+}
+
+// specializations
+
+template<>
+ParticleDataBase::PdataType ParticleDataImpl<int>::getType() const {
+ return ParticleDataBase::DATA_INT;
+}
+template<>
+ParticleDataBase::PdataType ParticleDataImpl<Real>::getType() const {
+ return ParticleDataBase::DATA_REAL;
+}
+template<>
+ParticleDataBase::PdataType ParticleDataImpl<Vec3>::getType() const {
+ return ParticleDataBase::DATA_VEC3;
+}
+
+// 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.);
+
+// explicit instantiation
+template class ParticleDataImpl<int>;
+template class ParticleDataImpl<Real>;
+template class ParticleDataImpl<Vec3>;
+
+KERNEL(pts) template<class T>
+void knSetPdataConst(ParticleDataImpl<T>& pdata, T value) {
+ pdata[idx] = value;
+}
+PYTHON void setConstPdata (ParticleDataImpl<Real>& pd, Real value=0.) { knSetPdataConst<Real>(pd,value); }
+PYTHON void setConstPdataVec3(ParticleDataImpl<Vec3>& pd, Vec3 value=0.) { knSetPdataConst<Vec3>(pd,value); }
+PYTHON void setConstPdataInt (ParticleDataImpl<int >& pd, int value=0.) { knSetPdataConst<int> (pd,value); }
+
+
+
+} // namespace
+
diff --git a/source/blender/python/manta_full/source/particle.h b/source/blender/python/manta_full/source/particle.h
new file mode 100644
index 00000000000..28528d15e97
--- /dev/null
+++ b/source/blender/python/manta_full/source/particle.h
@@ -0,0 +1,608 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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
+PYTHON class ParticleBase : public PbClass {
+public:
+ enum SystemType { BASE=0, PARTICLE, VORTEX, FILAMENT, FLIP, TURBULENCE, INDEX };
+
+ enum ParticleStatus {
+ PNONE = 0,
+ PNEW = (1<<1), // particles newly created in this step
+ PDELETE = (1<<10), // mark as deleted, will be deleted in next compress() step
+ PINVALID = (1<<30), // unused
+ };
+
+ PYTHON ParticleBase(FluidSolver* parent);
+ 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 int 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);
+
+ //! debug info about pdata
+ std::string debugInfoPdata();
+
+ // particle data functions
+
+ //! create a particle data object
+ PYTHON PbClass* create(PbType type, PbTypeVec T=PbTypeVec(), const std::string& name = "");
+ //! 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?
+ int getNumPdata() const { return mPartData.size(); }
+ //! access one of the fields
+ ParticleDataBase* getPdata(int i) { return mPartData[i]; }
+
+protected:
+ //! new particle candidates
+ std::vector<Vec3> mNewBuffer;
+
+ //! 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;
+};
+
+
+//! Main class for particle systems
+/*! Basetype S must at least contain flag, pos fields */
+PYTHON template<class S> class ParticleSystem : public ParticleBase {
+public:
+ PYTHON ParticleSystem(FluidSolver* parent) : ParticleBase(parent), mDeletes(0), mDeleteChunk(0) {}
+ virtual ~ParticleSystem() {};
+
+ virtual SystemType getType() const { return S::getType(); };
+
+ // accessors
+ inline S& operator[](int idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline const S& operator[](int idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ // return size of container
+ PYTHON inline int size() const { return mData.size(); }
+ // slow virtual function of base class, also returns size
+ virtual int getSizeSlow() const { return size(); }
+
+ // query status
+ inline int getStatus(int idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx].flag; }
+ inline bool isActive(int idx) { DEBUG_ONLY(checkPartIndex(idx)); return (mData[idx].flag & PDELETE) == 0; }
+
+ //! safe accessor for python
+ PYTHON void setPos(int idx, const Vec3& pos) { DEBUG_ONLY(checkPartIndex(idx)); mData[idx].pos = pos; }
+ PYTHON Vec3 getPos(int idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx].pos; }
+ //! copy all positions into pdata vec3 field
+ PYTHON void getPosPdata(ParticleDataImpl<Vec3>& target);
+ PYTHON void setPosPdata(ParticleDataImpl<Vec3>& source);
+ //! 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(int newsize);
+
+ // adding and deleting
+ inline void kill(int idx);
+ int add(const S& data);
+ // remove all particles, init 0 length arrays (also pdata)
+ PYTHON void clear();
+
+ //! Advect particle in grid velocity field
+ PYTHON void advectInGrid(FlagGrid& flags, MACGrid& vel, int integrationMode, bool deleteInObstacle=true );
+
+ //! Project particles outside obstacles
+ PYTHON void projectOutside(Grid<Vec3>& gradient);
+
+ virtual ParticleBase* clone();
+ virtual std::string infoString() const;
+
+ //! debugging
+ inline void checkPartIndex(int idx) const;
+
+protected:
+ //! deletion count , and interval for re-compressing
+ int mDeletes, mDeleteChunk;
+ //! the particle data
+ std::vector<S> mData;
+
+ //! reduce storage , called by doCompress
+ virtual void compress();
+};
+
+//******************************************************************************
+
+//! Simplest data class for particle systems
+struct BasicParticleData {
+public:
+ BasicParticleData() : pos(0.), flag(0) {}
+ BasicParticleData(const Vec3& p) : pos(p), flag(0) {}
+ static ParticleBase::SystemType getType() { return ParticleBase::PARTICLE; }
+
+ //! data
+ Vec3 pos;
+ int flag;
+};
+
+PYTHON class BasicParticleSystem : public ParticleSystem<BasicParticleData> {
+public:
+ PYTHON BasicParticleSystem(FluidSolver* parent);
+
+ //! file io
+ PYTHON void save(std::string name);
+ PYTHON void load(std::string name);
+
+ // save to text file
+ void writeParticlesText(std::string name);
+ // other output formats
+ void writeParticlesRawPositionsGz(std::string name);
+ void writeParticlesRawVelocityGz(std::string name);
+
+ // add particles in python
+ PYTHON void addParticle(Vec3 pos) { add(BasicParticleData(pos)); }
+
+ // dangerous, get low level access - avoid usage, only used in vortex filament advection for now
+ std::vector<BasicParticleData>& getData() { return mData; }
+};
+
+
+//******************************************************************************
+
+//! 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; }
+
+ int 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
+};
+
+PYTHON class ParticleIndexSystem : public ParticleSystem<ParticleIndexData> {
+public:
+ PYTHON ParticleIndexSystem(FluidSolver* parent) : ParticleSystem<ParticleIndexData>(parent) {};
+
+ //! we only need a resize function...
+ void resize(int size) { mData.resize(size); }
+};
+
+
+
+//******************************************************************************
+
+//! Particle set with connectivity
+PYTHON template<class DATA, class CON>
+class ConnectedParticleSystem : public ParticleSystem<DATA> {
+public:
+ PYTHON ConnectedParticleSystem(FluidSolver* parent) : ParticleSystem<DATA>(parent) {}
+
+ // 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();
+};
+
+//******************************************************************************
+
+//! abstract interface for particle data
+PYTHON class ParticleDataBase : public PbClass {
+public:
+ PYTHON ParticleDataBase(FluidSolver* parent);
+ virtual ~ParticleDataBase();
+
+ enum PdataType { UNKNOWN=0, DATA_INT, DATA_REAL, DATA_VEC3 };
+
+ // interface functions, using assert instead of pure virtual for python compatibility
+ virtual int size() const { assertMsg( false , "Dont use, override..."); return 0; }
+ virtual void add() { 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 UNKNOWN; }
+ virtual void resize(int size) { assertMsg( false , "Dont use, override..."); return; }
+ virtual void copyValueSlow(int from, int to) { assertMsg( false , "Dont use, override..."); return; }
+
+ //! set base pointer
+ void setParticleSys(ParticleBase* set) { mpParticleSys = set; }
+
+ //! debugging
+ inline void checkPartIndex(int idx) const;
+
+protected:
+ ParticleBase* mpParticleSys;
+};
+
+
+//! abstract interface for particle data
+PYTHON template<class T>
+class ParticleDataImpl : public ParticleDataBase {
+public:
+ PYTHON ParticleDataImpl(FluidSolver* parent);
+ ParticleDataImpl(FluidSolver* parent, ParticleDataImpl<T>* other);
+ virtual ~ParticleDataImpl();
+
+ //! access data
+ inline T& get(int idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline const T get(int idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline T& operator[](int idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline const T operator[](int 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)
+ PYTHON void clear();
+
+ //! set grid from which to get data...
+ PYTHON void setSource(Grid<T>* grid, bool isMAC=false );
+
+ // particle data base interface
+ virtual int size() const;
+ virtual void add();
+ virtual ParticleDataBase* clone();
+ virtual PdataType getType() const;
+ virtual void resize(int s);
+ virtual void copyValueSlow(int from, int to);
+
+ // fast inlined functions for per particle operations
+ inline void copyValue(int from, int to) { get(to) = get(from); }
+ void initNewValue(int idx, Vec3 pos);
+
+ //! file io
+ PYTHON void save(std::string name);
+ PYTHON void load(std::string name);
+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;
+};
+
+PYTHON alias ParticleDataImpl<int> PdataInt;
+PYTHON alias ParticleDataImpl<Real> PdataReal;
+PYTHON alias ParticleDataImpl<Vec3> PdataVec3;
+
+
+//******************************************************************************
+// Implementation
+//******************************************************************************
+
+const int DELETE_PART = 20; // chunk size for compression
+
+void ParticleBase::addBuffered(const Vec3& pos) {
+ mNewBuffer.push_back(pos);
+}
+
+template<class S>
+void ParticleSystem<S>::clear() {
+ mDeleteChunk = mDeletes = 0;
+ this->resizeAll(0); // instead of mData.clear
+}
+
+template<class S>
+int 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(int 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) {
+ for(int i=0; i<(int)this->size(); ++i) {
+ target[i] = this->getPos(i);
+ }
+}
+template<class S>
+void ParticleSystem<S>::setPosPdata(ParticleDataImpl<Vec3>& target) {
+ for(int i=0; i<(int)this->size(); ++i) {
+ this->getPos(i) = target[i];
+ }
+}
+
+template<class S>
+void ParticleSystem<S>::transformPositions( Vec3i dimOld, Vec3i dimNew )
+{
+ Vec3 factor = calcGridSizeFactor( dimNew, dimOld );
+ for(int i=0; i<(int)this->size(); ++i) {
+ this->setPos(i, this->getPos(i) * factor );
+ }
+}
+
+// check for deletion/invalid position, otherwise return velocity
+KERNEL(pts) template<class S> returns(std::vector<Vec3> u(size))
+std::vector<Vec3> GridAdvectKernel (std::vector<S>& p, const MACGrid& vel, const FlagGrid& flags, Real dt,
+ bool deleteInObstacle )
+{
+ if (p[idx].flag & ParticleBase::PDELETE) {
+ u[idx] =_0;
+ } else if (!flags.isInBounds(p[idx].pos,1) || flags.isObstacle(p[idx].pos)) {
+ 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;
+ } else {
+ u[idx] = vel.getInterpolated(p[idx].pos) * dt;
+ }
+};
+
+// final check after advection to make sure particles haven't escaped
+// (similar to particle advection kernel)
+KERNEL(pts) template<class S>
+void KnDeleteInObstacle(std::vector<S>& p, const FlagGrid& flags) {
+ if (p[idx].flag & ParticleBase::PDELETE) return;
+ if (!flags.isInBounds(p[idx].pos,1) || flags.isObstacle(p[idx].pos)) {
+ p[idx].flag |= ParticleBase::PDELETE;
+ }
+}
+// at least make sure all particles are inside domain
+KERNEL(pts) template<class S>
+void KnClampPositions(std::vector<S>& p, const FlagGrid& flags) {
+ if (p[idx].flag & ParticleBase::PDELETE) return;
+ if (!flags.isInBounds(p[idx].pos,0) ) {
+ p[idx].pos = clamp( p[idx].pos, Vec3(0.), toVec3(flags.getSize())-Vec3(1.) );
+ }
+}
+
+// advection plugin
+template<class S>
+void ParticleSystem<S>::advectInGrid(FlagGrid& flags, MACGrid& vel, int integrationMode, bool deleteInObstacle ) {
+ GridAdvectKernel<S> kernel(mData, vel, flags, getParent()->getDt(), deleteInObstacle );
+ integratePointSet(kernel, integrationMode);
+ if(deleteInObstacle) KnDeleteInObstacle<S>( mData, flags);
+ else KnClampPositions<S> ( mData, flags);
+}
+
+KERNEL(pts, single) // no thread-safe random gen yet
+template<class S>
+void KnProjectParticles(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);
+ }
+}
+
+template<class S>
+void ParticleSystem<S>::projectOutside(Grid<Vec3>& gradient) {
+ KnProjectParticles<S>(*this, gradient);
+}
+
+template<class S>
+void ParticleSystem<S>::resizeAll(int size) {
+ // resize all buffers to target size in 1 go
+ mData.resize(size);
+ for(int i=0; i<(int)mPartData.size(); ++i)
+ mPartData[i]->resize(size);
+}
+
+template<class S>
+void ParticleSystem<S>::compress() {
+ int nextRead = mData.size();
+ for (int i=0; i<(int)mData.size(); i++) {
+ while ((mData[i].flag & PDELETE) != 0) {
+ nextRead--;
+ mData[i] = mData[nextRead];
+ // ugly, but prevent virtual function calls here:
+ for(int pd=0; pd<(int)mPdataReal.size(); ++pd) mPdataReal[pd]->copyValue(nextRead, i);
+ for(int pd=0; pd<(int)mPdataVec3.size(); ++pd) mPdataVec3[pd]->copyValue(nextRead, i);
+ for(int pd=0; pd<(int)mPdataInt .size(); ++pd) mPdataInt [pd]->copyValue(nextRead, i);
+ mData[nextRead].flag = PINVALID;
+ }
+ }
+ if(nextRead<(int)mData.size()) debMsg("Deleted "<<((int)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(mNewBuffer.size()==0) return;
+ int newCnt = mData.size();
+ resizeAll(newCnt + mNewBuffer.size());
+
+ // clear new flag everywhere
+ for(int i=0; i<(int)mData.size(); ++i) mData[i].flag &= ~PNEW;
+
+ for(int i=0; i<(int)mNewBuffer.size(); ++i) {
+ // note, other fields are not initialized here...
+ mData[newCnt].pos = mNewBuffer[i];
+ mData[newCnt].flag = PNEW;
+ // now init pdata fields from associated grids...
+ for(int pd=0; pd<(int)mPdataReal.size(); ++pd)
+ mPdataReal[pd]->initNewValue(newCnt, mNewBuffer[i] );
+ for(int pd=0; pd<(int)mPdataVec3.size(); ++pd)
+ mPdataVec3[pd]->initNewValue(newCnt, mNewBuffer[i] );
+ for(int pd=0; pd<(int)mPdataInt.size(); ++pd)
+ mPdataInt[pd]->initNewValue(newCnt, mNewBuffer[i] );
+ newCnt++;
+ }
+ if(mNewBuffer.size()>0) debMsg("Added & initialized "<<(int)mNewBuffer.size()<<" particles", 1); // debug info
+ mNewBuffer.clear();
+}
+
+
+template<class DATA, class CON>
+void ConnectedParticleSystem<DATA,CON>::compress() {
+ const int sz = ParticleSystem<DATA>::size();
+ int *renumber_back = new int[sz];
+ int *renumber = new int[sz];
+ for (int i=0; i<sz; i++)
+ renumber[i] = renumber_back[i] = -1;
+
+ // reorder elements
+ std::vector<DATA>& data = ParticleSystem<DATA>::mData;
+ int nextRead = sz;
+ for (int 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 (int i=0; i<nextRead; i++)
+ renumber[renumber_back[i]] = i;
+
+ // rename indices in filaments
+ for (int i=0; i<(int)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() << "' [" << size() << " parts";
+ if(this->getNumPdata()>0) s<< " "<< this->getNumPdata()<<" pd";
+ s << "]";
+ return s.str();
+}
+
+template<class S>
+inline void ParticleSystem<S>::checkPartIndex(int idx) const {
+ int mySize = this->size();
+ if (idx<0 || idx > mySize ) {
+ errMsg( "ParticleBase " << " size " << mySize << " : index " << idx << " out of bound " );
+ }
+}
+
+inline void ParticleDataBase::checkPartIndex(int idx) const {
+ int mySize = this->size();
+ 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(int i=0; i<(int)mData.size(); ++i) mData[i] = 0.;
+}
+
+
+} // namespace
+
+#endif
+
diff --git a/source/blender/python/manta_full/source/plugin/advection.cpp b/source/blender/python/manta_full/source/plugin/advection.cpp
new file mode 100644
index 00000000000..a2afaf8125c
--- /dev/null
+++ b/source/blender/python/manta_full/source/plugin/advection.cpp
@@ -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
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * Plugins for pressure correction:
+ * - solve_pressure
+ *
+ ******************************************************************************/
+
+#include "../util/vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+
+using namespace std;
+
+namespace Manta {
+
+static inline bool isNotFluid(FlagGrid& flags, int i, int j, int k)
+{
+ if ( flags.isFluid(i,j,k) ) return false;
+ if ( flags.isFluid(i-1,j,k) ) return false;
+ if ( flags.isFluid(i,j-1,k) ) return false;
+ if ( flags.is3D() ) {
+ if ( flags.isFluid(i,j,k-1) ) return false;
+ }
+ return true;
+}
+
+//! Semi-Lagrange interpolation kernel
+KERNEL(bnd=1) template<class T>
+void SemiLagrange (FlagGrid& flags, MACGrid& vel, Grid<T>& dst, Grid<T>& src, Real dt, bool isLevelset)
+{
+ if (flags.isObstacle(i,j,k)) {
+ dst(i,j,k) = 0;
+ return;
+ }
+ if (!isLevelset && isNotFluid(flags,i,j,k) ) {
+ dst(i,j,k) = src(i,j,k);
+ return;
+ }
+
+ // SL traceback
+ Vec3 pos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getCentered(i,j,k) * dt;
+ dst(i,j,k) = src.getInterpolated(pos);
+}
+
+static inline bool isNotFluidMAC(FlagGrid& flags, int i, int j, int k)
+{
+ if ( flags.isFluid(i,j,k) ) return false;
+ return true;
+}
+
+//! Semi-Lagrange interpolation kernel for MAC grids
+KERNEL(bnd=1)
+void SemiLagrangeMAC(FlagGrid& flags, MACGrid& vel, MACGrid& dst, MACGrid& src, Real dt)
+{
+ if (flags.isObstacle(i,j,k)) {
+ dst(i,j,k) = 0;
+ return;
+ }
+ if ( isNotFluidMAC(flags,i,j,k) ) {
+ dst(i,j,k) = src(i,j,k);
+ return;
+ }
+
+ // 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.getInterpolatedComponent<0>(xpos);
+ Vec3 ypos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACY(i,j,k) * dt;
+ Real vy = src.getInterpolatedComponent<1>(ypos);
+ Vec3 zpos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACZ(i,j,k) * dt;
+ Real vz = src.getInterpolatedComponent<2>(zpos);
+
+ dst(i,j,k) = Vec3(vx,vy,vz);
+}
+
+//! Kernel: Correct based on forward and backward SL steps (for both centered & mac grids)
+KERNEL(idx) template<class T>
+void MacCormackCorrect(FlagGrid& flags, Grid<T>& dst, Grid<T>& old, Grid<T>& fwd, Grid<T>& bwd,
+ Real strength, bool isLevelSet, bool isMAC=false )
+{
+ // note, replacement for isNotFluidMAC and isNotFluid
+ bool skip = false;
+
+ if (!flags.isFluid(idx)) skip = true;
+ if(!isMAC) {
+ if( (idx>=flags.getStrideX()) && (!flags.isFluid(idx-flags.getStrideX()) )) skip = true;
+ if( (idx>=flags.getStrideY()) && (!flags.isFluid(idx-flags.getStrideY()) )) skip = true;
+ if ( flags.is3D() ) {
+ if( (idx>=flags.getStrideZ()) &&(!flags.isFluid(idx-flags.getStrideZ()) )) skip = true;
+ } }
+ if ( skip ) {
+ dst[idx] = isLevelSet ? fwd[idx] : (T)0.0;
+ return;
+ }
+
+ // note, strenth of correction can be modified here
+ dst[idx] = fwd[idx] + strength * 0.5 * (old[idx] - bwd[idx]);
+}
+
+// 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);
+}
+
+
+//! Helper function for clamping non-mac grids
+template<class T>
+inline T doClampComponent(const Vec3i& upperClamp, Grid<T>& orig, T dst, const Vec3i& posFwd) {
+ // clamp forward lookup to grid
+ const int i0 = clamp(posFwd.x, 0, upperClamp.x-1);
+ const int j0 = clamp(posFwd.y, 0, upperClamp.y-1);
+ const int k0 = clamp(posFwd.z, 0, (orig.is3D() ? (upperClamp.z-1) : 1) );
+ const int i1 = i0+1, j1 = j0+1, k1= (orig.is3D() ? (k0+1) : k0);
+
+ if (!orig.isInBounds(Vec3i(i0,j0,k0),1)) {
+ return dst;
+ }
+
+ // find min/max around fwd pos
+ T minv = orig(i0,j0,k0), maxv = minv;
+ getMinMax(minv, maxv, orig(i1,j0,k0));
+ getMinMax(minv, maxv, orig(i0,j1,k0));
+ getMinMax(minv, maxv, orig(i1,j1,k0));
+ getMinMax(minv, maxv, orig(i0,j0,k1));
+ getMinMax(minv, maxv, orig(i1,j0,k1));
+ getMinMax(minv, maxv, orig(i0,j1,k1));
+ getMinMax(minv, maxv, orig(i1,j1,k1));
+
+ // write clamped value
+ return clamp(dst, minv, maxv);
+}
+
+//! Helper function for clamping MAC grids
+template<int c>
+inline Real doClampComponentMAC(const Vec3i& upperClamp, MACGrid& orig, Real dst, const Vec3i& posFwd) {
+ // clamp forward lookup to grid
+ const int i0 = clamp(posFwd.x, 0, upperClamp.x-1);
+ const int j0 = clamp(posFwd.y, 0, upperClamp.y-1);
+ const int k0 = clamp(posFwd.z, 0, (orig.is3D() ? (upperClamp.z-1) : 1) );
+ const int i1 = i0+1, j1 = j0+1, k1= (orig.is3D() ? (k0+1) : k0);
+ if (!orig.isInBounds(Vec3i(i0,j0,k0),1))
+ return dst;
+
+ // find min/max around fwd pos
+ Real minv = orig(i0,j0,k0)[c], maxv = minv;
+ getMinMax(minv, maxv, orig(i1,j0,k0)[c]);
+ getMinMax(minv, maxv, orig(i0,j1,k0)[c]);
+ getMinMax(minv, maxv, orig(i1,j1,k0)[c]);
+ 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]);
+
+ return clamp(dst, minv, maxv);
+}
+
+//! 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)
+KERNEL(bnd=1) template<class T>
+void MacCormackClamp(FlagGrid& flags, MACGrid& vel, Grid<T>& dst, Grid<T>& orig, Grid<T>& fwd, Real dt)
+{
+ if (flags.isObstacle(i,j,k))
+ return;
+ if ( isNotFluid(flags,i,j,k) ) {
+ dst(i,j,k) = fwd(i,j,k);
+ return;
+ }
+
+ T dval = dst(i,j,k);
+ Vec3i upperClamp = flags.getSize() - 1;
+
+ // lookup forward/backward
+ Vec3i posFwd = toVec3i( Vec3(i,j,k) - vel.getCentered(i,j,k) * dt );
+ Vec3i posBwd = toVec3i( Vec3(i,j,k) + vel.getCentered(i,j,k) * dt );
+
+ dval = doClampComponent<T>(upperClamp, orig, dval, posFwd );
+
+ // test if lookups point out of grid or into obstacle
+ if (posFwd.x < 0 || posFwd.y < 0 || posFwd.z < 0 ||
+ posBwd.x < 0 || posBwd.y < 0 || posBwd.z < 0 ||
+ posFwd.x > upperClamp.x || posFwd.y > upperClamp.y || ((posFwd.z > upperClamp.z)&&flags.is3D()) ||
+ posBwd.x > upperClamp.x || posBwd.y > upperClamp.y || ((posBwd.z > upperClamp.z)&&flags.is3D()) ||
+ flags.isObstacle(posFwd) || flags.isObstacle(posBwd) )
+ {
+ dval = fwd(i,j,k);
+ }
+ dst(i,j,k) = dval;
+}
+
+//! Kernel: same as MacCormackClamp above, but specialized version for MAC grids
+KERNEL(bnd=1)
+void MacCormackClampMAC (FlagGrid& flags, MACGrid& vel, MACGrid& dst, MACGrid& orig, MACGrid& fwd, Real dt)
+{
+ if (flags.isObstacle(i,j,k))
+ return;
+ if ( isNotFluidMAC(flags,i,j,k) ) {
+ dst(i,j,k) = fwd(i,j,k);
+ return;
+ }
+
+ Vec3 pos(i,j,k);
+ Vec3 dval = dst(i,j,k);
+ Vec3i upperClamp = flags.getSize() - 1;
+
+ // get total fwd lookup
+ Vec3i posFwd = toVec3i( Vec3(i,j,k) - vel.getCentered(i,j,k) * dt );
+ Vec3i posBwd = toVec3i( Vec3(i,j,k) + vel.getCentered(i,j,k) * dt );
+
+ // clamp individual components
+ dval.x = doClampComponentMAC<0>(upperClamp, orig, dval.x, toVec3i( pos - vel.getAtMACX(i,j,k) * dt) );
+ dval.y = doClampComponentMAC<1>(upperClamp, orig, dval.y, toVec3i( pos - vel.getAtMACY(i,j,k) * dt) );
+ dval.z = doClampComponentMAC<2>(upperClamp, orig, dval.z, toVec3i( pos - vel.getAtMACZ(i,j,k) * dt) );
+
+ // test if lookups point out of grid or into obstacle
+ if (posFwd.x < 0 || posFwd.y < 0 || posFwd.z < 0 ||
+ posBwd.x < 0 || posBwd.y < 0 || posBwd.z < 0 ||
+ posFwd.x > upperClamp.x || posFwd.y > upperClamp.y || ((posFwd.z > upperClamp.z)&&flags.is3D()) ||
+ posBwd.x > upperClamp.x || posBwd.y > upperClamp.y || ((posBwd.z > upperClamp.z)&&flags.is3D())
+ //|| flags.isObstacle(posFwd) || flags.isObstacle(posBwd) // note - this unfortunately introduces asymmetry... TODO update
+ )
+ {
+ dval = fwd(i,j,k);
+ }
+
+ // writeback
+ dst(i,j,k) = dval;
+}
+
+//! template function for performing SL advection
+template<class GridType>
+void fnAdvectSemiLagrange(FluidSolver* parent, FlagGrid& flags, MACGrid& vel, GridType& orig, int order, Real strength) {
+ 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);
+
+ 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);
+
+ // newGrid <- compute correction
+ MacCormackCorrect<T> (flags, newGrid, orig, fwd, bwd, strength, levelset);
+
+ // clamp values
+ MacCormackClamp<T> (flags, vel, newGrid, orig, fwd, dt);
+
+ orig.swap(newGrid);
+ }
+}
+
+//! template function for performing SL advection: specialized version for MAC grids
+template<>
+void fnAdvectSemiLagrange<MACGrid>(FluidSolver* parent, FlagGrid& flags, MACGrid& vel, MACGrid& orig, int order, Real strength) {
+ Real dt = parent->getDt();
+
+ // forward step
+ MACGrid fwd(parent);
+ SemiLagrangeMAC (flags, vel, fwd, orig, dt);
+
+ if (order == 1) {
+ orig.swap(fwd);
+ }
+ else if (order == 2) { // MacCormack
+ MACGrid bwd(parent);
+ MACGrid newGrid(parent);
+
+ // bwd <- backwards step
+ SemiLagrangeMAC (flags, vel, bwd, fwd, -dt);
+
+ // newGrid <- compute correction
+ MacCormackCorrect<Vec3> (flags, newGrid, orig, fwd, bwd, strength, false, true);
+
+ // clamp values
+ MacCormackClampMAC (flags, vel, newGrid, orig, fwd, dt);
+
+ orig.swap(newGrid);
+ }
+}
+
+//! Perform semi-lagrangian advection of target Real- or Vec3 grid
+PYTHON void advectSemiLagrange (FlagGrid* flags, MACGrid* vel, GridBase* grid,
+ int order = 1, Real strength = 1.0)
+{
+ assertMsg(order==1 || order==2, "AdvectSemiLagrange: Only order 1 (regular SL) and 2 (MacCormack) supported");
+
+ // determine type of grid
+ if (grid->getType() & GridBase::TypeReal) {
+ fnAdvectSemiLagrange< Grid<Real> >(flags->getParent(), *flags, *vel, *((Grid<Real>*) grid), order, strength);
+ }
+ else if (grid->getType() & GridBase::TypeMAC) {
+ fnAdvectSemiLagrange< MACGrid >(flags->getParent(), *flags, *vel, *((MACGrid*) grid), order, strength);
+ }
+ else if (grid->getType() & GridBase::TypeVec3) {
+ fnAdvectSemiLagrange< Grid<Vec3> >(flags->getParent(), *flags, *vel, *((Grid<Vec3>*) grid), order, strength);
+ }
+ else
+ errMsg("AdvectSemiLagrange: Grid Type is not supported (only Real, Vec3, MAC, Levelset)");
+}
+
+} // end namespace DDF
+
diff --git a/source/blender/python/manta_full/source/plugin/extforces.cpp b/source/blender/python/manta_full/source/plugin/extforces.cpp
new file mode 100644
index 00000000000..e761e0a6ccf
--- /dev/null
+++ b/source/blender/python/manta_full/source/plugin/extforces.cpp
@@ -0,0 +1,144 @@
+/******************************************************************************
+ *
+ * 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"
+
+using namespace std;
+
+namespace Manta {
+
+//! add Forces between fl/fl and fl/em cells
+KERNEL(bnd=1) void KnAddForceField(FlagGrid& flags, MACGrid& vel, Grid<Vec3>& force) {
+ 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)))
+ vel(i,j,k).x += 0.5*(force(i-1,j,k).x + force(i,j,k).x);
+ if (flags.isFluid(i,j-1,k) || (curFluid && flags.isEmpty(i,j-1,k)))
+ vel(i,j,k).y += 0.5*(force(i,j-1,k).y + force(i,j,k).y);
+ if (vel.is3D() && (flags.isFluid(i,j,k-1) || (curFluid && flags.isEmpty(i,j,k-1))))
+ vel(i,j,k).z += 0.5*(force(i,j,k-1).z + force(i,j,k).z);
+}
+
+//! add Forces between fl/fl and fl/em cells
+KERNEL(bnd=1) void KnAddForce(FlagGrid& flags, MACGrid& vel, Vec3 force) {
+ 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)))
+ vel(i,j,k).x += force.x;
+ if (flags.isFluid(i,j-1,k) || (curFluid && flags.isEmpty(i,j-1,k)))
+ vel(i,j,k).y += force.y;
+ if (vel.is3D() && (flags.isFluid(i,j,k-1) || (curFluid && flags.isEmpty(i,j,k-1))))
+ vel(i,j,k).z += force.z;
+}
+
+//! add gravity forces to all fluid cells
+PYTHON void addGravity(FlagGrid& flags, MACGrid& vel, Vec3 gravity) {
+ Vec3 f = gravity * flags.getParent()->getDt() / flags.getDx();
+ KnAddForce(flags, vel, f);
+}
+
+//! add Buoyancy force based on smoke density
+KERNEL(bnd=1) void KnAddBuoyancy(FlagGrid& flags, Grid<Real>& density, MACGrid& vel, Vec3 strength) {
+ if (!flags.isFluid(i,j,k)) return;
+ if (flags.isFluid(i-1,j,k))
+ vel(i,j,k).x += (0.5 * strength.x) * (density(i,j,k)+density(i-1,j,k));
+ if (flags.isFluid(i,j-1,k))
+ vel(i,j,k).y += (0.5 * strength.y) * (density(i,j,k)+density(i,j-1,k));
+ if (vel.is3D() && flags.isFluid(i,j,k-1))
+ vel(i,j,k).z += (0.5 * strength.z) * (density(i,j,k)+density(i,j,k-1));
+}
+
+//! add Buoyancy force based on smoke density
+PYTHON void addBuoyancy(FlagGrid& flags, Grid<Real>& density, MACGrid& vel, Vec3 gravity) {
+ Vec3 f = - gravity * flags.getParent()->getDt() / flags.getParent()->getDx();
+ KnAddBuoyancy(flags,density, vel, f);
+}
+
+
+//! set no-stick wall boundary condition between ob/fl and ob/ob cells
+KERNEL void KnSetWallBcs(FlagGrid& flags, MACGrid& vel) {
+ bool curFluid = flags.isFluid(i,j,k);
+ bool curObstacle = flags.isObstacle(i,j,k);
+ if (!curFluid && !curObstacle) return;
+
+ // we use i>0 instead of bnd=1 to check outer wall
+ if (i>0 && (flags.isObstacle(i-1,j,k) || (curObstacle && flags.isFluid(i-1,j,k))))
+ vel(i,j,k).x = 0;
+ if (j>0 && (flags.isObstacle(i,j-1,k) || (curObstacle && flags.isFluid(i,j-1,k))))
+ vel(i,j,k).y = 0;
+ if (vel.is2D() || (k>0 && (flags.isObstacle(i,j,k-1) || (curObstacle && flags.isFluid(i,j,k-1)))))
+ vel(i,j,k).z = 0;
+
+ 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;
+ }
+}
+
+//! set no-stick boundary condition on walls
+PYTHON void setWallBcs(FlagGrid& flags, MACGrid& vel) {
+ KnSetWallBcs(flags, vel);
+}
+
+//! Kernel: gradient norm operator
+KERNEL(bnd=1) void KnConfForce(Grid<Vec3>& force, const Grid<Real>& grid, const Grid<Vec3>& curl, Real str) {
+ 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);
+ force(i,j,k) = str * cross(grad, curl(i,j,k));
+}
+
+PYTHON void vorticityConfinement(MACGrid& vel, FlagGrid& flags, Real strength) {
+ 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, strength);
+ KnAddForceField(flags, vel, force);
+}
+
+//! enforce a constant inflow/outflow at the grid boundaries
+KERNEL void KnSetInflow(MACGrid& vel, int dim, int p0, const Vec3& val) {
+ Vec3i p(i,j,k);
+ if (p[dim] == p0 || p[dim] == p0+1)
+ vel(i,j,k) = val;
+}
+
+//! enforce a constant inflow/outflow at the grid boundaries
+PYTHON 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.");
+ }
+}
+
+} // namespace
diff --git a/source/blender/python/manta_full/source/plugin/initplugins.cpp b/source/blender/python/manta_full/source/plugin/initplugins.cpp
new file mode 100644
index 00000000000..69579a1327a
--- /dev/null
+++ b/source/blender/python/manta_full/source/plugin/initplugins.cpp
@@ -0,0 +1,105 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Tools to setup fields and inflows
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "shapes.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include "noisefield.h"
+#include "mesh.h"
+
+using namespace std;
+
+namespace Manta {
+
+//! Apply noise to grid
+KERNEL
+void KnApplyNoise(FlagGrid& flags, Grid<Real>& density, WaveletNoiseField& noise, Grid<Real>& sdf, Real scale, Real sigma)
+{
+ 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;
+}
+
+//! Init noise-modulated density inside shape
+PYTHON void densityInflow(FlagGrid& flags, Grid<Real>& density, WaveletNoiseField& noise, Shape* shape, Real scale=1.0, Real sigma=0)
+{
+ Grid<Real> sdf = shape->computeLevelset();
+ KnApplyNoise(flags, density, noise, sdf, scale, sigma);
+}
+
+
+//! Init noise-modulated density inside mesh
+PYTHON void densityInflowMesh(FlagGrid& flags, Grid<Real>& density, WaveletNoiseField& noise, Mesh* mesh, Real scale=1.0, Real sigma=0)
+{
+ FluidSolver dummy(density.getSize());
+ LevelsetGrid sdf(&dummy, false);
+ mesh->meshSDF(*mesh, sdf, 1.,3);
+ KnApplyNoise(flags, density, noise, sdf, scale, sigma);
+}
+//! sample noise field and set pdata with its values (for convenience, scale the noise values)
+KERNEL(pts) template<class T>
+void knSetPdataNoise(BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, WaveletNoiseField& noise, Real scale) {
+ pdata[idx] = noise.evaluate( parts.getPos(idx) ) * scale;
+}
+KERNEL(pts) template<class T>
+void knSetPdataNoiseVec(BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, WaveletNoiseField& noise, Real scale) {
+ pdata[idx] = noise.evaluateVec( parts.getPos(idx) ) * scale;
+}
+PYTHON void setNoisePdata (BasicParticleSystem& parts, ParticleDataImpl<Real>& pd, WaveletNoiseField& noise, Real scale=1.) { knSetPdataNoise<Real>(parts, pd,noise,scale); }
+PYTHON void setNoisePdataVec3(BasicParticleSystem& parts, ParticleDataImpl<Vec3>& pd, WaveletNoiseField& noise, Real scale=1.) { knSetPdataNoiseVec<Vec3>(parts, pd,noise,scale); }
+PYTHON void setNoisePdataInt (BasicParticleSystem& parts, ParticleDataImpl<int >& pd, WaveletNoiseField& noise, Real scale=1.) { knSetPdataNoise<int> (parts, pd,noise,scale); }
+
+//! SDF gradient from obstacle flags
+PYTHON Grid<Vec3> obstacleGradient(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;
+}
+
+PYTHON LevelsetGrid obstacleLevelset(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);
+
+ return levelset;
+}
+
+
+} // namespace
diff --git a/source/blender/python/manta_full/source/plugin/kepsilon.cpp b/source/blender/python/manta_full/source/plugin/kepsilon.cpp
new file mode 100644
index 00000000000..955d05d53d3
--- /dev/null
+++ b/source/blender/python/manta_full/source/plugin/kepsilon.cpp
@@ -0,0 +1,183 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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
+KERNEL(idx)
+void KnTurbulenceClamp(Grid<Real>& kgrid, Grid<Real>& egrid, Real minK, Real maxK, Real minNu, Real maxNu) {
+ 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;
+}
+
+//! Compute k-epsilon production term P = 2*nu_T*sum_ij(Sij^2) and the turbulent viscosity nu_T=C_mu*k^2/eps
+KERNEL(bnd=1)
+void 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)
+{
+ 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;
+ }
+}
+
+//! Compute k-epsilon production term P = 2*nu_T*sum_ij(Sij^2) and the turbulent viscosity nu_T=C_mu*k^2/eps
+PYTHON void KEpsilonComputeProduction(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);
+}
+
+//! Integrate source terms of k-epsilon equation
+KERNEL(idx)
+void KnAddTurbulenceSource(Grid<Real>& kgrid, Grid<Real>& egrid, const Grid<Real>& pgrid, Real dt) {
+ 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;
+}
+
+
+//! Integrate source terms of k-epsilon equation
+PYTHON 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);
+}
+
+//! Initialize the domain or boundary conditions
+PYTHON void KEpsilonBcs(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;
+ }
+ }
+}
+
+//! 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
+PYTHON 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);
+ }
+ }
+}
+
+
+
+} // namespace \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/plugin/meshplugins.cpp b/source/blender/python/manta_full/source/plugin/meshplugins.cpp
new file mode 100644
index 00000000000..8037447d299
--- /dev/null
+++ b/source/blender/python/manta_full/source/plugin/meshplugins.cpp
@@ -0,0 +1,623 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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"*/
+PYTHON 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);
+ 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/len);
+ totalLen += len;
+ } else {
+ totalLen = _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)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;
+}
+
+//! Subdivide and edgecollapse to guarantee mesh with edgelengths between
+//! min/maxLength and an angle below minAngle
+PYTHON 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();
+
+}
+
+PYTHON 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;
+}
+
+
+} //namespace
+
diff --git a/source/blender/python/manta_full/source/plugin/pressure.cpp b/source/blender/python/manta_full/source/plugin/pressure.cpp
new file mode 100644
index 00000000000..3c826b1d519
--- /dev/null
+++ b/source/blender/python/manta_full/source/plugin/pressure.cpp
@@ -0,0 +1,310 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Plugins for pressure correction: solve_pressure, and ghost fluid helpers
+ *
+ ******************************************************************************/
+#include "vectorbase.h"
+#include "kernel.h"
+#include "conjugategrad.h"
+
+using namespace std;
+namespace Manta {
+
+//! Kernel: Construct the right-hand side of the poisson equation
+KERNEL(bnd=1, reduce=+) returns(int cnt=0) returns(double sum=0)
+void MakeRhs (FlagGrid& flags, Grid<Real>& rhs, MACGrid& vel,
+ Grid<Real>* perCellCorr)
+{
+ if (!flags.isFluid(i,j,k)) {
+ rhs(i,j,k) = 0;
+ return;
+ }
+
+ // compute divergence
+ // no flag checks: assumes vel at obstacle interfaces is set to zero
+ Real 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;
+
+ // per cell divergence correction
+ if(perCellCorr)
+ set += perCellCorr->get(i,j,k);
+
+ // obtain sum, cell count
+ sum += set;
+ cnt++;
+
+ rhs(i,j,k) = set;
+}
+
+
+//! Kernel: Apply velocity update from poisson equation
+KERNEL(bnd=1)
+void CorrectVelocity(FlagGrid& flags, MACGrid& vel, Grid<Real>& pressure)
+{
+ int 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))
+ {
+ 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;
+ }
+ }
+}
+
+//! Kernel: Set matrix stencils and velocities to enable open boundaries
+KERNEL void SetOpenBound(Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak, MACGrid& vel,
+ Vector3D<bool> lowerBound, Vector3D<bool> upperBound)
+{
+ // set velocity boundary conditions
+ if (lowerBound.x && i == 0) vel(0,j,k) = vel(1,j,k);
+ if (lowerBound.y && j == 0) vel(i,0,k) = vel(i,1,k);
+ if (upperBound.x && i == maxX-1) vel(maxX-1,j,k) = vel(maxX-2,j,k);
+ if (upperBound.y && j == maxY-1) vel(i,maxY-1,k) = vel(i,maxY-2,k);
+ if(vel.is3D()) {
+ if (lowerBound.z && k == 0) vel(i,j,0) = vel(i,j,1);
+ if (upperBound.z && k == maxZ-1) vel(i,j,maxZ-1) = vel(i,j,maxZ-2);
+ }
+
+ // set matrix stencils at boundary
+ if ((lowerBound.x && i<=1) || (upperBound.x && i>=maxX-2) ||
+ (lowerBound.y && j<=1) || (upperBound.y && j>=maxY-2) ||
+ (lowerBound.z && k<=1) || (upperBound.z && k>=maxZ-2)) {
+ A0(i,j,k) = vel.is3D() ? 6.0 : 4.0;
+ Ai(i,j,k) = -1.0;
+ Aj(i,j,k) = -1.0;
+ if (vel.is3D()) Ak(i,j,k) = -1.0;
+ }
+}
+
+//! Kernel: Set matrix rhs for outflow
+KERNEL void SetOutflow (Grid<Real>& rhs, Vector3D<bool> lowerBound, Vector3D<bool> upperBound, int height)
+{
+ if ((lowerBound.x && i < height) || (upperBound.x && i >= maxX-1-height) ||
+ (lowerBound.y && j < height) || (upperBound.y && j >= maxY-1-height) ||
+ (lowerBound.z && k < height) || (upperBound.z && k >= maxZ-1-height))
+ rhs(i,j,k) = 0;
+}
+
+
+// *****************************************************************************
+// Ghost fluid helpers
+
+// calculate fraction filled with liquid (note, assumes inside value is < outside!)
+inline static Real thetaHelper(Real inside, Real outside)
+{
+ 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(int idx, int offset, const Grid<Real> &phi, Real gfClamp)
+{
+ Real alpha = thetaHelper(phi[idx], phi[idx+offset]);
+ if (alpha < gfClamp) return alpha = gfClamp;
+ return (1-(1/alpha));
+}
+
+//! Kernel: Adapt A0 for ghost fluid
+KERNEL(bnd=1)
+void ApplyGhostFluidDiagonal(Grid<Real> &A0, const FlagGrid &flags, const Grid<Real> &phi, Real gfClamp)
+{
+ const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ int 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);
+ }
+}
+
+//! Kernel: Apply velocity update: ghost fluid contribution
+KERNEL(bnd=1)
+void CorrectVelocityGhostFluid(MACGrid &vel, const FlagGrid &flags, const Grid<Real> &pressure, const Grid<Real> &phi, Real gfClamp)
+{
+ const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ const int 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))
+ {
+ 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;
+ }
+ }
+}
+
+
+// improve behavior of clamping for large time steps:
+
+inline static Real ghostFluidWasClamped(int idx, int offset, const Grid<Real> &phi, Real gfClamp)
+{
+ Real alpha = thetaHelper(phi[idx], phi[idx+offset]);
+ if (alpha < gfClamp) return true;
+ return false;
+}
+
+KERNEL(bnd=1)
+void ReplaceClampedGhostFluidVels(MACGrid &vel, FlagGrid &flags,
+ const Grid<Real> &pressure, const Grid<Real> &phi, Real gfClamp )
+{
+ const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ const int idx = flags.index(i,j,k);
+ if (flags.isFluid(idx))
+ {
+ if( (flags.isEmpty(i-1,j,k)) && (ghostFluidWasClamped(idx, -X, phi, gfClamp)) )
+ vel[idx-X][0] = vel[idx][0];
+ if( (flags.isEmpty(i,j-1,k)) && (ghostFluidWasClamped(idx, -Y, phi, gfClamp)) )
+ vel[idx-Y][1] = vel[idx][1];
+ if( flags.is3D() &&
+ (flags.isEmpty(i,j,k-1)) && (ghostFluidWasClamped(idx, -Z, phi, gfClamp)) )
+ vel[idx-Z][2] = vel[idx][2];
+ }
+ else if (flags.isEmpty(idx))
+ {
+ if( (i>-1) && (flags.isFluid(i-1,j,k)) && ( ghostFluidWasClamped(idx-X, +X, phi, gfClamp) ) )
+ vel[idx][0] = vel[idx-X][0];
+ if( (j>-1) && (flags.isFluid(i,j-1,k)) && ( ghostFluidWasClamped(idx-Y, +Y, phi, gfClamp) ) )
+ vel[idx][1] = vel[idx-Y][1];
+ if( flags.is3D() &&
+ ( (k>-1) && (flags.isFluid(i,j,k-1)) && ( ghostFluidWasClamped(idx-Z, +Z, phi, gfClamp) ) ))
+ vel[idx][2] = vel[idx-Z][2];
+ }
+}
+
+
+// *****************************************************************************
+// Main pressure solve
+
+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.");
+ }
+}
+
+//! Perform pressure projection of the velocity grid
+PYTHON void solvePressure(MACGrid& vel, Grid<Real>& pressure, FlagGrid& flags,
+ Grid<Real>* phi = 0,
+ Grid<Real>* perCellCorr = 0,
+ Real gfClamp = 1e-04,
+ Real cgMaxIterFac = 1.5,
+ Real cgAccuracy = 1e-3,
+ string openBound = "",
+ string outflow = "",
+ int outflowHeight = 1,
+ bool precondition = true,
+ bool enforceCompatibility = false,
+ bool useResNorm = true )
+{
+ // parse strings
+ Vector3D<bool> loOpenBound, upOpenBound, loOutflow, upOutflow;
+ convertDescToVec(openBound, loOpenBound, upOpenBound);
+ convertDescToVec(outflow, loOutflow, upOutflow);
+ if (vel.is2D() && (loOpenBound.z || upOpenBound.z))
+ errMsg("open boundaries for z specified for 2D grid");
+
+ // 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);
+ Grid<Real> pca0(parent);
+ Grid<Real> pca1(parent);
+ Grid<Real> pca2(parent);
+ Grid<Real> pca3(parent);
+
+ // setup matrix and boundaries
+ MakeLaplaceMatrix (flags, A0, Ai, Aj, Ak);
+ SetOpenBound (A0, Ai, Aj, Ak, vel, loOpenBound, upOpenBound);
+
+ if (phi) {
+ ApplyGhostFluidDiagonal(A0, flags, *phi, gfClamp);
+ }
+
+ // compute divergence and init right hand side
+ MakeRhs kernMakeRhs (flags, rhs, vel, perCellCorr);
+
+ if (!outflow.empty())
+ SetOutflow (rhs, loOutflow, upOutflow, outflowHeight);
+
+ if (enforceCompatibility)
+ rhs += (Real)(-kernMakeRhs.sum / (Real)kernMakeRhs.cnt);
+
+ // CG setup
+ // note: the last factor increases the max iterations for 2d, which right now can't use a preconditioner
+ const int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
+ 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->setUseResNorm( useResNorm );
+
+ // optional preconditioning
+ gcg->setPreconditioner( precondition ? GridCgInterface::PC_mICP : GridCgInterface::PC_None, &pca0, &pca1, &pca2, &pca3);
+
+ for (int iter=0; iter<maxIter; iter++) {
+ if (!gcg->iterate()) iter=maxIter;
+ }
+ debMsg("FluidSolver::solvePressure iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma(), 1);
+ delete gcg;
+
+ CorrectVelocity(flags, vel, pressure);
+ if (phi) {
+ CorrectVelocityGhostFluid (vel, flags, pressure, *phi, gfClamp);
+ // improve behavior of clamping for large time steps:
+ ReplaceClampedGhostFluidVels (vel, flags, pressure, *phi, gfClamp);
+ }
+}
+
+} // end namespace
+
diff --git a/source/blender/python/manta_full/source/plugin/vortexplugins.cpp b/source/blender/python/manta_full/source/plugin/vortexplugins.cpp
new file mode 100644
index 00000000000..fed847ca2bd
--- /dev/null
+++ b/source/blender/python/manta_full/source/plugin/vortexplugins.cpp
@@ -0,0 +1,312 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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
+PYTHON void markAsFixed(Mesh& mesh, 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;
+ }
+}
+
+//! Adapt texture coordinates of mesh inside shape
+//! to obtain an effective inflow effect
+PYTHON void texcoordInflow(VortexSheetMesh& mesh, Shape* shape, MACGrid& vel)
+{
+ static Vec3 t0 = Vec3::Zero;
+
+ // get mean velocity
+ int cnt=0;
+ Vec3 meanV(_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;
+ }
+ }
+};
+
+//! Init smoke density values of the mesh surface inside source shape
+PYTHON void meshSmokeInflow(VortexSheetMesh& mesh, Shape* shape, Real amount)
+{
+ for (int t=0; t<mesh.numTris(); t++) {
+ if (shape->isInside(mesh.getFaceCenter(t)))
+ mesh.sheet(t).smokeAmount = amount;
+ }
+}
+
+KERNEL(idx)
+void KnAcceleration(MACGrid& a, const MACGrid& v1, const MACGrid& v0, const Real idt) {
+ a[idx] = (v1[idx]-v0[idx])*idt;
+}
+
+//! Add vorticity to vortex sheets based on buoyancy
+PYTHON void vorticitySource(VortexSheetMesh& mesh, Vec3 gravity,
+ MACGrid* vel=NULL, 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;
+}
+
+PYTHON 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;
+}
+
+//! Seed Vortex Particles inside shape with K41 characteristics
+PYTHON void VPseedK41(VortexParticleSystem& system, 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));
+ }
+ }
+ }
+}
+
+//! Vortex-in-cell integration
+PYTHON void VICintegration(VortexSheetMesh& mesh, Real sigma, Grid<Vec3>& vel, 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->setUseResNorm(true);
+ gcg->setPreconditioner( (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);
+ }
+}
+
+//! Obtain density field from levelset with linear gradient of size sigma over the interface
+PYTHON void densityFromLevelset(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))), _0, value);
+ }
+}
+
+} // namespace \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/plugin/waveletturbulence.cpp b/source/blender/python/manta_full/source/plugin/waveletturbulence.cpp
new file mode 100644
index 00000000000..2b496da717c
--- /dev/null
+++ b/source/blender/python/manta_full/source/plugin/waveletturbulence.cpp
@@ -0,0 +1,296 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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 {
+
+
+//! Apply vector noise to grid, this is a simplified version - no position scaling or UVs
+KERNEL
+void knApplySimpleNoiseVec(FlagGrid& flags, Grid<Vec3>& target, WaveletNoiseField& noise,
+ Real scale, Grid<Real>* weight )
+{
+ 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) ) * scale * factor;
+}
+PYTHON void applySimpleNoiseVec3(FlagGrid& flags, Grid<Vec3>& target, WaveletNoiseField& noise,
+ Real scale=1.0 , Grid<Real>* weight=NULL )
+{
+ // note - passing a MAC grid here is slightly inaccurate, we should evaluate each component separately
+ knApplySimpleNoiseVec(flags, target, noise, scale , weight );
+}
+
+
+//! Simple noise for a real grid , follows applySimpleNoiseVec3
+KERNEL
+void knApplySimpleNoiseReal(FlagGrid& flags, Grid<Real>& target, WaveletNoiseField& noise,
+ Real scale, Grid<Real>* weight )
+{
+ 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) ) * scale * factor;
+}
+PYTHON void applySimpleNoiseReal(FlagGrid& flags, Grid<Real>& target, WaveletNoiseField& noise,
+ Real scale=1.0 , Grid<Real>* weight=NULL )
+{
+ knApplySimpleNoiseReal(flags, target, noise, scale , weight );
+}
+
+
+
+//! 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.
+KERNEL
+void knApplyNoiseVec(FlagGrid& flags, Grid<Vec3>& target, WaveletNoiseField& noise,
+ Real scale, Real scaleSpatial, Grid<Real>* weight, Grid<Vec3>* uv, bool uvInterpol, const Vec3& sourceFactor )
+{
+ 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);
+ 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;
+}
+PYTHON void applyNoiseVec3(FlagGrid& flags, Grid<Vec3>& target, WaveletNoiseField& noise,
+ Real scale=1.0 , Real scaleSpatial=1.0 , Grid<Real>* weight=NULL , 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
+ knApplyNoiseVec(flags, target, noise, scale, scaleSpatial, weight , uv,uvInterpol,sourceFactor );
+}
+
+
+
+//! Compute energy of a staggered velocity field (at cell center)
+KERNEL
+void KnApplyComputeEnergy( FlagGrid& flags, MACGrid& vel, Grid<Real>& energy )
+{
+ 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;
+}
+
+PYTHON void computeEnergy( FlagGrid& flags, MACGrid& vel, Grid<Real>& energy )
+{
+ KnApplyComputeEnergy( flags, vel, energy );
+}
+
+
+
+//!interpolate grid from one size to another size
+KERNEL
+void KnInterpolateGrid(Grid<Real>& target, Grid<Real>& source, const Vec3& sourceFactor)
+{
+ Vec3 pos = Vec3(i,j,k) * sourceFactor;
+ if(!source.is3D()) pos[2] = 0; // allow 2d -> 3d
+ target(i,j,k) = source.getInterpolated(pos);
+}
+
+PYTHON void interpolateGrid( Grid<Real>& target, Grid<Real>& source )
+{
+ Vec3 sourceFactor = calcGridSizeFactor( source.getSize(), target.getSize() );
+
+ // 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).
+
+ KnInterpolateGrid(target, source, sourceFactor);
+}
+
+
+//!interpolate a mac velocity grid from one size to another size
+KERNEL
+void KnInterpolateMACGrid(MACGrid& target, MACGrid& source, const Vec3& sourceFactor)
+{
+ Vec3 pos = Vec3(i,j,k) * sourceFactor;
+
+ Real vx = source.getInterpolated(pos - Vec3(0.5,0,0))[0];
+ Real vy = source.getInterpolated(pos - Vec3(0,0.5,0))[1];
+ Real vz = 0.f;
+ if(source.is3D()) vz = source.getInterpolated(pos - Vec3(0,0,0.5))[2];
+
+ target(i,j,k) = Vec3(vx,vy,vz);
+}
+
+PYTHON void interpolateMACGrid(MACGrid& target, MACGrid& source)
+{
+ Vec3 sourceFactor = calcGridSizeFactor( source.getSize(), target.getSize() );
+
+ // see interpolateGrid for why the target grid needs to come first in the parameters!
+
+ KnInterpolateMACGrid(target, source, sourceFactor);
+}
+
+PYTHON void computeWaveletCoeffs(Grid<Real>& input)
+{
+ Grid<Real> temp1(input.getParent()), temp2(input.getParent());
+ WaveletNoiseField::computeCoefficients(input, temp1, temp2);
+}
+
+// note - alomst the same as for vorticity confinement
+PYTHON void computeVorticity(MACGrid& vel, Grid<Vec3>& vorticity, Grid<Real>* norm) {
+ Grid<Vec3> velCenter(vel.getParent());
+ GetCentered(velCenter, vel);
+ CurlOp(velCenter, vorticity);
+ if(norm) GridNorm( *norm, vorticity);
+}
+
+// note - very similar to KnComputeProductionStrain, but for use as wavelet turb weighting
+KERNEL(bnd=1)
+void KnComputeStrainRateMag(const MACGrid& vel, const Grid<Vec3>& velCenter, Grid<Real>& prod )
+{
+ // 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;
+}
+PYTHON void computeStrainRateMag(MACGrid& vel, Grid<Real>& mag) {
+ Grid<Vec3> velCenter(vel.getParent());
+ GetCentered(velCenter, vel);
+ KnComputeStrainRateMag(vel, velCenter, mag);
+}
+
+
+// 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 (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
+}
+PYTHON void extrapolateSimpleFlags (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)");
+}
+
+} // namespace
diff --git a/source/blender/python/manta_full/source/preprocessor/code.cpp b/source/blender/python/manta_full/source/preprocessor/code.cpp
new file mode 100644
index 00000000000..9937b37a772
--- /dev/null
+++ b/source/blender/python/manta_full/source/preprocessor/code.cpp
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Preprocessor Code Structs
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <cstdlib>
+#include <algorithm>
+#include "prep.h"
+
+using namespace std;
+
+//*************************************************************
+// Helpers
+
+bool Type::operator==(const Type& a) const {
+ if (a.templateTypes.size() != templateTypes.size()) return false;
+ for (size_t i=0; i<templateTypes.size(); i++)
+ if (templateTypes[i].name != a.templateTypes[i].name) return false;
+ return a.name==name && a.isConst==isConst && a.isRef==isRef && a.isPointer==isPointer;
+}
+
+string Type::build(bool refify) const {
+ string s="";
+ if (isConst) s+= "const ";
+ s += name;
+ if (!templateTypes.empty())
+ s+= templateTypes.minimal;
+ if (isRef || (refify && !isPointer)) s+= "&";
+ if (isPointer) s+= "*";
+ return s;
+}
+
+string Text::linebreaks() const {
+ int num = count(original.begin(), original.end(), '\n') -
+ count(minimal.begin(),minimal.end(), '\n');
+ string s="";
+ for (int i=0; i< num; i++)
+ s += '\n';
+ return s;
+}
+
+string Function::signature() const {
+ string s;
+ if (isTemplated())
+ s = "template " + templateTypes.minimal;
+ if (isVirtual)
+ s += "virtual ";
+ if (isInline)
+ s += "inline ";
+ s+= returnType.minimal + name + arguments.minimal;
+ if (isConst)
+ s += "const ";
+ return s;
+}
+
+template<> std::string List<Argument>::full(bool refify) const {
+ std::stringstream s;
+ for (int i=0; i<(int)_data.size(); i++) {
+ s << "," << _data[i].type.build(refify) << " " << _data[i].name;
+ }
+ return s.str();
+}
+
+template<> std::string List<Argument>::createMembers(bool refify) const {
+ std::stringstream s;
+ for (int i=0; i<(int)_data.size(); i++)
+ s << _data[i].type.build(refify) << ' ' << _data[i].name << "; ";
+ return s.str();
+}
+
+template<> std::string List<Argument>::copier(const std::string& prefix, bool useVal) const {
+ std::stringstream s;
+ for (int i=0; i<(int)_data.size(); i++) {
+ s << ',' << _data[i].name << '(';
+ s << (useVal ? _data[i].value : prefix+_data[i].name);
+ s << ')';
+ }
+ return s.str();
+}
+
+template struct List<Argument>;
+template struct List<Type>;
+
diff --git a/source/blender/python/manta_full/source/preprocessor/code.h b/source/blender/python/manta_full/source/preprocessor/code.h
new file mode 100644
index 00000000000..5dfe76eedfa
--- /dev/null
+++ b/source/blender/python/manta_full/source/preprocessor/code.h
@@ -0,0 +1,134 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Preprocessor Declarations
+ *
+ ******************************************************************************/
+
+#ifndef _CODE_H
+#define _CODE_H
+
+#include <string>
+#include <vector>
+
+struct Text {
+ int line0;
+ std::string minimal, original;
+ void reset() { minimal = original = ""; line0=0; }
+ std::string linebreaks() const;
+ virtual std::string dynamicClass() { return ""; }
+ void prequel(const Text* a) { minimal = a->minimal + minimal; original = a->original + original; }
+ void post(const Text* a) { minimal += a->minimal; original += a->original; }
+};
+
+template <class T>
+struct List : Text {
+ std::vector<T> _data;
+ std::string listText;
+
+ // exposed vector members
+ inline size_t size() const { return _data.size(); }
+ inline T& operator[](int i) { return _data[i]; }
+ inline const T& operator[](int i) const { return _data[i]; }
+ inline bool empty() const { return _data.empty(); }
+ inline T& back() { return _data.back(); }
+ inline void push_back(const T& a) { _data.push_back(a); }
+
+ std::string names() const;
+ std::string full(bool refify=false) const { return ""; };
+ std::string copier(const std::string& prefix, bool useValue) const { return ""; };
+ std::string createMembers(bool refify = false) const { return ""; };
+ virtual std::string dynamicClass() { return "List"; }
+};
+
+struct Type : Text {
+ Type() : isConst(false), isRef(false), isPointer(false) {};
+
+ std::string name;
+ bool isConst, isRef, isPointer;
+ List<Type> templateTypes;
+
+ inline bool isTemplated() const { return !templateTypes.empty(); }
+ bool operator==(const Type& a) const;
+ std::string build(bool refify = false) const;
+ virtual std::string dynamicClass() { return "Type"; }
+};
+
+struct Argument : Text {
+ Argument() : type(),index(-1) {};
+
+ Type type;
+ int index;
+ std::string name, value;
+ std::string completeText, minimalText;
+ virtual std::string dynamicClass() { return "Argument"; }
+};
+
+struct Function : Text {
+ Function() : returnType(),isInline(false),isVirtual(false),isConst(false),noParentheses(false),isOperator(false) {}
+
+ std::string name;
+ Type returnType;
+ bool isInline, isVirtual, isConst, noParentheses, isOperator;
+ List<Type> templateTypes;
+ List<Argument> arguments;
+ std::string signature() const;
+ inline std::string callString() const { return arguments.names(); }
+ inline bool isTemplated() const { return !templateTypes.empty(); }
+ virtual std::string dynamicClass() { return "Function"; }
+};
+
+struct Instantiation {
+ Instantiation(const std::string& c, const std::string& n) :
+ cls(c), name(n) {}
+ std::string cls, name;
+ std::vector<std::string> wrapName;
+ std::vector<Function> func;
+ std::vector<std::string> templates;
+};
+
+struct Class : Text {
+ Class() {};
+
+ std::string name;
+ Type baseClass;
+ List<Type> templateTypes;
+ std::string fullName() const { return isTemplated() ? (name+"<"+templateTypes.names()+">") : name; }
+ inline bool isTemplated() const { return !templateTypes.empty(); }
+ virtual std::string dynamicClass() { return "Class"; }
+};
+
+struct Block : Text {
+ Block() {};
+
+ int line1;
+ std::string initList;
+ Class cls;
+ const Class *parent;
+ Function func;
+ List<Argument> options;
+ List<Argument> locals;
+ virtual std::string dynamicClass() { return "Block"; }
+};
+
+// list functions , notify compiler of specializations in code.cpp
+
+template<class T> std::string List<T>::names() const {
+ std::stringstream s;
+ for (int i=0; i<(int)_data.size(); i++) {
+ s << _data[i].name;
+ if (i != (int)_data.size()-1) s << ',';
+ }
+ return s.str();
+}
+template<> std::string List<Argument>::full(bool refify) const;
+template<> std::string List<Argument>::createMembers(bool refify) const;
+template<> std::string List<Argument>::copier(const std::string& prefix, bool useVal) const;
+
+#endif
diff --git a/source/blender/python/manta_full/source/preprocessor/codegen_kernel.cpp b/source/blender/python/manta_full/source/preprocessor/codegen_kernel.cpp
new file mode 100644
index 00000000000..b7505888ac6
--- /dev/null
+++ b/source/blender/python/manta_full/source/preprocessor/codegen_kernel.cpp
@@ -0,0 +1,365 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Preprocessor: Process replacement text of KERNEL keyword
+ *
+ ******************************************************************************/
+
+#include "prep.h"
+#include <cstdlib>
+#include <set>
+#include <sstream>
+#include <iostream>
+using namespace std;
+
+#define STR(x) #x
+
+//******************************************************
+// Templates for code generation
+
+// TP: why do we need getArg? just directly access the argument via its name...
+const string TmpAccessor = STR(
+inline $TYPE$ getArg$IDX$() { return $NAME$; }
+typedef $TYPE_NOREF$ type$IDX$;
+);
+
+// Single kernel, default
+const string TmpSingleKernel = STR(
+$TEMPLATE$ struct $KERNEL$ : public KernelBase {
+ $KERNEL$($ARGS$) :
+@IF(PTS)
+ KernelBase($BASE$.size()) $INIT$ $LOCALSET$
+@ELSE
+ KernelBase($BASE$,$BND$) $INIT$ $LOCALSET$
+@END
+ {
+ run();
+ }
+@IF(IJK)
+ inline void op(int i, int j, int k, $ARGS$ $LOCALARG$) $CONST$ $CODE$
+@ELSE
+ inline void op(int idx, $ARGS$ $LOCALARG$) $CONST$ $CODE$
+@END
+
+@IF(RET_NAME)
+ inline operator $RET_TYPE$() { return $RET_NAME$; }
+ inline $RET_TYPE$ & getRet() { return $RET_NAME$; }
+@END
+ $ACCESSORS$
+
+ $RUN$
+ $MEMBERS$
+ $LOCALS$
+};
+);
+
+// Necesary for TBB with nontrivial return values
+const string TmpDoubleKernel = STR(
+// inner kernel
+$TEMPLATE$ struct _$KERNEL$ : public KernelBase {
+ _$KERNEL$(const KernelBase& base, $ARGS$ $LOCALARG$) :
+ KernelBase(base) $INIT$ $LOCALINIT${}
+
+@IF(IJK)
+ inline void op(int i, int j, int k, $ARGS$ $LOCALARG$) $CONST$ $CODE$
+@ELSE
+ inline void op(int idx, $ARGS$ $LOCALARG$) $CONST$ $CODE$
+@END
+ $RUN$
+ $MEMBERS$
+ $LOCALS_REF$
+};
+
+// outer kernel with accessors
+$TEMPLATE$ struct $KERNEL$ : public KernelBase {
+ $KERNEL$($ARGS$) :
+@IF(PTS)
+ KernelBase($BASE$.size()) $COMMA$ _inner(KernelBase($BASE$.size()),$CALL$)
+@ELSE
+ KernelBase($BASE$,$BND$) $COMMA$ _inner(KernelBase($BASE$,$BND$),$CALL$)
+@END
+ $INIT$ $LOCALSET$
+ {
+ run();
+ }
+
+ void run() { _inner.run(); }
+
+@IF(RET_NAME)
+ inline operator $RET_TYPE$() { return $RET_NAME$; }
+ inline $RET_TYPE$ & getRet() { return $RET_NAME$; }
+@END
+ $ACCESSORS$
+ _$KERNEL$$TPL$ _inner;
+ $MEMBERS$
+ $LOCALS$
+};
+);
+
+const string TmpRunSimple = STR(
+void run() {
+@IF(IJK)
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ for (int k=minZ; k< maxZ; k++)
+ for (int j=$BND$; j< _maxY; j++)
+ for (int i=$BND$; i< _maxX; i++)
+ op(i,j,k, $CALL$);
+@ELSE
+ const int _sz = size;
+ for (int i=0; i < _sz; i++)
+ op(i, $CALL$);
+@END
+}
+);
+
+const string TmpRunTBB = STR(
+void operator() (const tbb::blocked_range<size_t>& r) $CONST$ {
+@IF(IJK)
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ>1) {
+ for (int k=r.begin(); k!=(int)r.end(); k++)
+ for (int j=$BND$; j<_maxY; j++)
+ for (int i=$BND$; i<_maxX; i++)
+ op(i,j,k,$CALL$);
+ } else {
+ const int k=0;
+ for (int j=r.begin(); j!=(int)r.end(); j++)
+ for (int i=$BND$; i<_maxX; i++)
+ op(i,j,k,$CALL$);
+ }
+@ELSE
+ for (int idx=r.begin(); idx!=(int)r.end(); idx++)
+ op(idx, $CALL$);
+@END
+}
+void run() {
+@IF(IJK)
+ if (maxZ>1)
+ tbb::parallel_$METHOD$ (tbb::blocked_range<size_t>(minZ, maxZ), *this);
+ else
+ tbb::parallel_$METHOD$ (tbb::blocked_range<size_t>($BND$, maxY), *this);
+@ELSE
+ tbb::parallel_$METHOD$ (tbb::blocked_range<size_t>(0, size), *this);
+@END
+}
+@IF(REDUCE)
+ $IKERNEL$ ($IKERNEL$& o, tbb::split) : KernelBase(o) $COPY$ $LOCALSET$ {}
+
+ void join(const $IKERNEL$ & o) {
+ $JOINER$
+ }
+@END
+);
+
+const string TmpRunOMP = STR(
+void run() {
+@IF(IJK)
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ $PRAGMA$ omp parallel $NL$
+ {
+ $OMP_DIRECTIVE$
+ for (int k=minZ; k < maxZ; k++)
+ for (int j=$BND$; j < _maxY; j++)
+ for (int i=$BND$; i < _maxX; i++)
+ op(i,j,k,$CALL$);
+ $OMP_POST$
+ }
+ } else {
+ const int k=0;
+ $PRAGMA$ omp parallel $NL$
+ {
+ $OMP_DIRECTIVE$
+ for (int j=$BND$; j < _maxY; j++)
+ for (int i=$BND$; i < _maxX; i++)
+ op(i,j,k,$CALL$);
+ $OMP_POST$
+ }
+ }
+@ELSE
+ const int _sz = size;
+ $PRAGMA$ omp parallel $NL$
+ {
+ $OMP_DIRECTIVE$
+ for (int i=0; i < _sz; i++)
+ op(i,$CALL$);
+ $OMP_POST$
+ }
+@END
+}
+);
+
+const string TmpOMPDirective = STR (
+this->threadId = omp_get_thread_num();
+this->threadNum = omp_get_num_threads();
+@IF(REDUCE)
+ $OMP_PRE$
+ $PRAGMA$ omp for nowait $NL$
+@ELSE
+ $PRAGMA$ omp for $NL$
+@END
+);
+
+
+#define kernelAssert(x,msg) if(!(x)){errMsg(block.line0,string("KERNEL: ") + msg);}
+
+void processKernel(const Block& block, const string& code, Sink& sink) {
+ const Function& kernel = block.func;
+
+ if (gDocMode) {
+ sink.inplace << "//! \\ingroup Kernels\n" << block.func.minimal << "{}\n";
+ return;
+ }
+
+ // process options
+ bool idxMode = false, reduce = false, pts = false;
+ bool hasLocals = !block.locals.empty(), hasRet = kernel.returnType.name != "void";
+ string bnd = "0", reduceOp="";
+
+ MType mtType = gMTType;
+ for (size_t i=0; i<block.options.size(); i++) {
+ const string& opt = block.options[i].name;
+ if (opt == "ijk")
+ idxMode = false;
+ else if (opt == "index" || opt == "idx")
+ idxMode = true;
+ else if (opt == "st" || opt == "single")
+ mtType = MTNone;
+ else if (opt == "pts" || opt == "particle" || opt == "points")
+ pts = true;
+ else if (opt == "bnd")
+ bnd = block.options[i].value;
+ else if (opt == "reduce") {
+ reduce = true;
+ reduceOp = block.options[i].value;
+ if (!(reduceOp == "+" || reduceOp == "-" || reduceOp == "*" ||
+ reduceOp == "/" || reduceOp == "min" || reduceOp == "max"))
+ errMsg(block.line0, "invalid 'reduce' operator. Expected reduce= +|-|*|/|min|max");
+ } else
+ errMsg(block.line0, "illegal kernel option '"+ opt +
+ "' Supported options are: 'ijk', 'idx', 'bnd=x', 'reduce=x', 'st', 'pts'");
+ }
+
+ // point out illegal paramter combinations
+ kernelAssert (bnd == "0" || !idxMode, "can't combine index mode with bounds iteration.");
+ kernelAssert (!pts || (!idxMode && bnd == "0" ),
+ "KERNEL(opt): Modes 'ijk', 'idx' and 'bnd' can't be applied to particle kernels.");
+
+ // check type consistency of first 'returns' with return type
+ if (hasRet && kernel.returnType.name != "void") {
+ kernelAssert(block.locals.size() == 1, "multiple returns statement only work for 'void' kernels");
+ const Type& rt = block.locals[0].type;
+ kernelAssert(rt == kernel.returnType, "return type does not match type in first 'returns' statement");
+ }
+ kernelAssert(kernel.returnType.name == "void" || hasRet,
+ "return argument specified without matching 'returns' initializer");
+
+ // figure out basegrid
+ string baseGrid;
+ for (int i=0; i<(int)kernel.arguments.size(); i++) {
+ const string& type = kernel.arguments[i].type.name;
+ bool isGrid = type.find("Grid") != string::npos;
+ if (isGrid || pts) {
+ baseGrid = kernel.arguments[i].name;
+ if (isGrid && !kernel.arguments[i].type.isPointer)
+ baseGrid = "&"+baseGrid;
+ break;
+ }
+ }
+ kernelAssert(!baseGrid.empty(), ": use at least one grid to call the kernel.");
+
+ // build accesors
+ stringstream accessors;
+ for (int i=0; i<(int)kernel.arguments.size(); i++) {
+ stringstream num; num << i;
+ Type noref = kernel.arguments[i].type;
+ noref.isPointer = noref.isRef = noref.isConst = false;
+ const string table[] = { "TYPE", kernel.arguments[i].type.build(true),
+ "TYPE_NOREF", noref.build(),
+ "NAME", kernel.arguments[i].name,
+ "IDX", num.str(),
+ "" };
+ accessors << replaceSet(TmpAccessor, table);
+ }
+
+ // build locals, and reduce joiners
+ stringstream joiner, preReduce, postReduce;
+ for (int i=0; i<(int)block.locals.size(); i++) {
+ const string& name = block.locals[i].name;
+ const string type = block.locals[i].type.build();
+ const string& value = block.locals[i].value;
+
+ preReduce << type << " " << name << " = " << value << ";";
+ if (reduceOp == "min" || reduceOp == "max") {
+ joiner << name << " = " << reduceOp << "(" << name << ",o." << name << "); ";
+ postReduce << "this->" << name << " = " << reduceOp << "(" << name << ", this->" << name << "); ";
+ } else {
+ joiner << name << " " << reduceOp << "= o." << name << "; ";
+ postReduce << "this->" << name << " " << reduceOp << "= " << name << "; ";
+ }
+ }
+ const string ompPost = reduce ? "\n#pragma omp critical\n{"+postReduce.str()+"}":"";
+ bool doubleKernel = mtType == MTTBB && hasRet && !reduce;
+
+ const string table[] = { "IDX", idxMode ? "Y":"",
+ "PTS", pts ? "Y":"",
+ "IJK", (!pts && !idxMode) ? "Y":"",
+ "REDUCE", reduce ? "Y":"",
+ "TEMPLATE", kernel.isTemplated() ? "template "+kernel.templateTypes.minimal : "",
+ "TPL", kernel.isTemplated() ? "<"+kernel.templateTypes.names()+">" : "",
+ "KERNEL", kernel.name,
+ "IKERNEL", (doubleKernel ? "_":"") + kernel.name,
+ "ARGS", kernel.arguments.listText,
+ "LOCALARG", block.locals.full(true),
+ "BASE", baseGrid,
+ "INIT", kernel.arguments.copier("", false),
+ "LOCALINIT", block.locals.copier("", false),
+ "LOCALSET", block.locals.copier("", true),
+ "COPY", kernel.arguments.copier("o.", false),
+ "MEMBERS", kernel.arguments.createMembers(),
+ "LOCALS", block.locals.createMembers(false),
+ "LOCALS_REF", block.locals.createMembers(true),
+ "ACCESSORS", accessors.str(),
+ "CONST", (!reduce && mtType==MTTBB) ? "const" : "",
+ "CODE", code,
+ "RET_TYPE", hasRet ? block.locals[0].type.minimal : "",
+ "RET_NAME", hasRet ? block.locals[0].name : "",
+ "BND", bnd,
+ "CALL", kernel.callString() + (hasLocals ? ","+block.locals.names() : ""),
+ "METHOD", reduce ? "reduce" : "for",
+ "PRAGMA", "\n#pragma",
+ "NL", "\n",
+ "COMMA", ",",
+ "JOINER", joiner.str(),
+ "OMP_PRE", preReduce.str(),
+ "OMP_POST", ompPost,
+ "" };
+
+ // generate kernel
+ string templ = doubleKernel ? TmpDoubleKernel : TmpSingleKernel;
+ if (mtType == MTNone)
+ replaceAll(templ, "$RUN$", TmpRunSimple);
+ else if (mtType == MTTBB)
+ replaceAll(templ, "$RUN$", TmpRunTBB);
+ else if (mtType == MTOpenMP) {
+ string ompTempl = TmpRunOMP;
+ replaceAll(ompTempl, "$OMP_DIRECTIVE$", TmpOMPDirective);
+ replaceAll(templ, "$RUN$", ompTempl);
+ }
+
+ // synthesize code
+ sink.inplace << block.linebreaks() << replaceSet(templ, table);
+
+ // adjust lines after OMP block
+ if (mtType == MTOpenMP)
+ sink.inplace << "\n#line " << block.line1 << " \"" << sink.infile << "\"\n" << endl;
+}
diff --git a/source/blender/python/manta_full/source/preprocessor/codegen_python.cpp b/source/blender/python/manta_full/source/preprocessor/codegen_python.cpp
new file mode 100644
index 00000000000..b00d1a15b7e
--- /dev/null
+++ b/source/blender/python/manta_full/source/preprocessor/codegen_python.cpp
@@ -0,0 +1,505 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Preprocessor: Process replacement text of PYTHON keywords
+ *
+ ******************************************************************************/
+
+#include "prep.h"
+#include <cstdlib>
+#include <set>
+#include <sstream>
+#include <iostream>
+using namespace std;
+
+#define STR(x) #x
+
+//******************************************************
+// Templates for code generation
+
+const string TmpFunction = STR(
+$TEMPLATE$ static PyObject* _W_$WRAPPER$ (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ FluidSolver *parent = _args.obtainParent();
+ pbPreparePlugin(parent, "$FUNCNAME$" );
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ $ARGLOADER$
+ @IF(RET_VOID)
+ _retval = getPyNone();
+ $FUNCNAME$($CALLSTRING$);
+ @ELSE
+ _retval = toPy($FUNCNAME$($CALLSTRING$));
+ @END
+ _args.check();
+ }
+ pbFinalizePlugin(parent,"$FUNCNAME$" );
+ return _retval;
+ } catch(std::exception& e) {
+ pbSetError("$FUNCNAME$",e.what());
+ return 0;
+ }
+}
+);
+
+const string TmpMemberFunction = STR(
+$TEMPLATE$ static PyObject* _W_$WRAPPER$ (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ try {
+ PbArgs _args(_linargs, _kwds);
+ $CLASS$* pbo = dynamic_cast<$CLASS$*>(Pb::objFromPy(_self));
+ pbPreparePlugin(pbo->getParent(), "$CLASS$::$FUNCNAME$");
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ $ARGLOADER$
+ pbo->_args.copy(_args);
+ @IF(RET_VOID)
+ _retval = getPyNone();
+ pbo->$FUNCNAME$($CALLSTRING$);
+ @ELSE
+ _retval = toPy(pbo->$FUNCNAME$($CALLSTRING$));
+ @END
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(),"$CLASS$::$FUNCNAME$");
+ return _retval;
+ } catch(std::exception& e) {
+ pbSetError("$CLASS$::$FUNCNAME$",e.what());
+ return 0;
+ }
+});
+
+const string TmpConstructor = STR(
+$TEMPLATE$ static int _W_$WRAPPER$ (PyObject* _self, PyObject* _linargs, PyObject* _kwds) {
+ PbClass* obj = Pb::objFromPy(_self);
+ if (obj) delete obj;
+ try {
+ PbArgs _args(_linargs, _kwds);
+ pbPreparePlugin(0, "$CLASS$::$FUNCNAME$" );
+ {
+ ArgLocker _lock;
+ $ARGLOADER$
+ obj = new $CLASS$($CALLSTRING$);
+ obj->registerObject(_self, &_args);
+ _args.check();
+ }
+ pbFinalizePlugin(obj->getParent(),"$CLASS$::$FUNCNAME$" );
+ return 0;
+ } catch(std::exception& e) {
+ pbSetError("$CLASS$::$FUNCNAME$",e.what());
+ return -1;
+ }
+});
+
+const string TmpBinaryOp = STR(
+$TEMPLATE$ static PyObject* _W_$WRAPPER$ (PyObject* _self, PyObject* o) {
+ try {
+ PbArgs _args(0,0);
+ _args.addLinArg(o);
+ $CLASS$* pbo = dynamic_cast<$CLASS$*>(Pb::objFromPy(_self));
+ pbPreparePlugin(pbo->getParent(), "$CLASS$::$FUNCNAME$");
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ $ARGLOADER$
+ pbo->_args.copy(_args);
+ _retval = toPy(pbo->$FUNCNAME$($CALLSTRING$));
+ pbo->_args.check();
+ }
+ pbFinalizePlugin(pbo->getParent(),"$CLASS$::$FUNCNAME$");
+ return _retval;
+ } catch(std::exception& e) {
+ pbSetError("$CLASS$::$FUNCNAME$",e.what());
+ return 0;
+ }
+});
+
+const string TmpGetSet = STR(
+static PyObject* _GET_$NAME$(PyObject* self, void* cl) {
+ $CLASS$* pbo = dynamic_cast<$CLASS$*>(Pb::objFromPy(self));
+ return toPy(pbo->$NAME$);
+}
+static int _SET_$NAME$(PyObject* self, PyObject* val, void* cl) {
+ $CLASS$* pbo = dynamic_cast<$CLASS$*>(Pb::objFromPy(self));
+ pbo->$NAME$ = fromPy<$TYPE$ >(val);
+ return 0;
+});
+
+const string TmpRegisterMethod = STR(
+@IF(CTPL)
+ static const Pb::Register _R_$IDX$ ("$CLASS$<$CT$>","$FUNCNAME$",$CLASS$<$CT$>::_W_$REGWRAPPER$);
+@ELIF(CLASS)
+ static const Pb::Register _R_$IDX$ ("$CLASS$","$FUNCNAME$",$CLASS$::_W_$REGWRAPPER$);
+@ELSE
+ static const Pb::Register _RP_$FUNCNAME$ ("","$FUNCNAME$",_W_$REGWRAPPER$);
+@END
+);
+
+const string TmpRegisterGetSet = STR(
+@IF(CTPL)
+ static const Pb::Register _R_$IDX$ ("$CLASS$<$CT$>$","$PYNAME$",$CLASS$<$CT$>::_GET_$NAME$,$CLASS$<$CT$>::_SET_$NAME$);
+@ELSE
+ static const Pb::Register _R_$IDX$ ("$CLASS$","$PYNAME$",$CLASS$::_GET_$NAME$,$CLASS$::_SET_$NAME$);
+@END
+);
+
+const string TmpRegisterClass = STR(
+@IF(CTPL)
+ static const Pb::Register _R_$IDX$ ("$CLASS$<$CT$>","$PYNAME$<$CT$>","$BASE$$BTPL$");
+ template<> const char* Namify<$CLASS$<$CT$> >::S = "$CLASS$<$CT$>";
+@ELSE
+ static const Pb::Register _R_$IDX$ ("$CLASS$","$PYNAME$","$BASE$$BTPL$");
+ template<> const char* Namify<$CLASS$ >::S = "$CLASS$";
+@END
+);
+
+const string TmpAlias = STR(
+static const Pb::Register _R_$IDX$ ("$CLASS$","$PYNAME$","");
+);
+
+const string TmpTemplateWrapper = STR(
+static $RET$ _W_$WRAPPER$ (PyObject* s, PyObject* l, PyObject* kw) {
+ PbArgs args(l, kw);
+ int hits=0;
+ $RET$ (*call)(PyObject*,PyObject*,PyObject*);
+
+ $TEMPLATE_CHECK$
+
+ if (hits == 1)
+ return call(s,l,kw);
+ if (hits == 0)
+ pbSetError("$FUNCNAME$", "Can't deduce template parameters");
+ else
+ pbSetError("$FUNCNAME$", "Argument matches multiple templates");
+ return @IF(CONSTRUCTOR) -1 @ELSE 0 @END ;
+}
+);
+const string TmpTemplateWrapperOp = STR(
+static PyObject* _W_$WRAPPER$ (PyObject* _self, PyObject* o) {
+ PbArgs args(0,0);
+ args.addLinArg(o);
+ int hits=0;
+ PyObject* (*call)(PyObject*,PyObject*);
+
+ $TEMPLATE_CHECK$
+
+ if (hits == 1)
+ return call(_self, o);
+ if (hits == 0)
+ pbSetError("$FUNCNAME$", "Can't deduce template parameters");
+ else
+ pbSetError("$FUNCNAME$", "Argument matches multiple templates");
+ return 0;
+}
+);
+
+const string TmpTemplateChecker = STR(
+template $TEMPLATE$
+static bool $NAME$ (PbArgs& A) {
+ return $CHK$;
+}
+);
+
+//******************************************************
+// Code generation functions
+
+string generateLoader(const Argument& arg) {
+ bool integral = isIntegral(arg.type.name);
+ Type ptrType = arg.type;
+ string optCall = string("_args.") + (arg.value.empty() ? "get" : "getOpt");
+
+ ptrType.isConst = false;
+ if (integral) {
+ ptrType.isPointer = false;
+ ptrType.isRef = false;
+ } else if (arg.type.isPointer) {
+ ptrType.isPointer = false;
+ ptrType.isRef = false;
+ optCall = string("_args.") + (arg.value.empty() ? "getPtr" : "getPtrOpt");
+ } else if (arg.type.isRef) {
+ ptrType.isPointer = false;
+ ptrType.isRef = false;
+ optCall = string("*_args.") + (arg.value.empty() ? "getPtr" : "getPtrOpt");
+ }
+
+ stringstream loader;
+ loader << arg.type.build() << " " << arg.name << " = " << optCall;
+
+ loader << "<" << ptrType.build() << " >";
+ loader << "(\"" << arg.name << "\"," << arg.index << ",";
+ if (!arg.value.empty())
+ loader << arg.value << ",";
+ loader << "&_lock); ";
+
+ return loader.str();
+}
+
+// global for tracking state between python class and python function registrations
+bool gFoundConstructor = false;
+
+void processPythonFunction(const Block& block, const string& code, Sink& sink, vector<Instantiation>& inst) {
+ const Function& func = block.func;
+
+ // PYTHON(...) keyword options
+ for (size_t i=0; i<block.options.size(); i++) {
+ if (block.options[i].name == "only") {
+ ((Function&)func).name = makeSafe(func.name);
+ }
+ else
+ errMsg(block.line0, "unknown keyword " + block.options[i].name);
+ }
+
+ bool isConstructor = func.returnType.minimal.empty();
+ bool isPlugin = !block.parent;
+ bool doRegister = true;
+ string className = isPlugin ? "" : block.parent->name;
+ if (isConstructor) gFoundConstructor = true;
+ if (isPlugin && sink.isHeader)
+ errMsg(block.line0,"plugin python functions can't be defined in headers.");
+
+ // replicate function
+ if (gDocMode) {
+ // document free plugins
+ if (isPlugin)
+ sink.inplace << "//! \\ingroup Plugins\n";
+ sink.inplace << "PYTHON " << func.signature() << "{}\n";
+ return;
+ }
+ sink.inplace << block.linebreaks() << func.signature() << block.initList << code;
+
+ // generate variable loader
+ string loader = "";
+ for (int i=0; i<(int)func.arguments.size(); i++)
+ loader += generateLoader(func.arguments[i]);
+
+ // wrapper name
+ static int idx;
+ stringstream wrapper;
+ wrapper << idx++;
+
+ // generate glue layer function
+ const string table[] = { "FUNCNAME", func.name,
+ "ARGLOADER", loader,
+ "TEMPLATE", func.isTemplated() ? "template "+func.templateTypes.minimal : "",
+ "WRAPPER", (func.isTemplated() ? "T_":"") + wrapper.str(),
+ "REGWRAPPER", wrapper.str(),
+ "CLASS", className,
+ "CTPL", (isPlugin || !block.parent->isTemplated()) ? "" : "$CT$",
+ "CALLSTRING", func.callString(),
+ "RET_VOID", (func.returnType.name=="void") ? "Y" : "",
+ "" };
+ string callerTempl = isPlugin ? TmpFunction : TmpMemberFunction;
+ if (isConstructor) callerTempl = TmpConstructor;
+ else if (func.isOperator) callerTempl = TmpBinaryOp;
+ sink.inplace << replaceSet(callerTempl, table);
+
+ // drop a marker for function template wrapper
+ if (func.isTemplated()) {
+ Instantiation* curInst = 0;
+ for (int i=0; i<(int)inst.size(); i++)
+ if (inst[i].cls == className && inst[i].name == func.name) curInst=&inst[i];
+ if (!curInst) {
+ stringstream num; num << inst.size();
+ sink.inplace << "$" << num.str() << "$";
+ inst.push_back(Instantiation(className,func.name));
+ curInst = &inst.back();
+ } else
+ doRegister = false;
+ curInst->wrapName.push_back(wrapper.str());
+ curInst->func.push_back(func);
+ }
+
+ // register functions
+ if (!doRegister) return;
+ const string reg = replaceSet(TmpRegisterMethod, table);
+ if (isPlugin) {
+ sink.inplace << reg;
+ } else {
+ sink.link << '+' << block.parent->name << '^' << reg << '\n';
+ }
+}
+
+void processPythonVariable(const Block& block, Sink& sink) {
+ const Function& var = block.func;
+
+ if (!block.parent)
+ errMsg(block.line0, "python variables can only be used inside classes");
+
+ // process options
+ string pythonName = var.name;
+ for (size_t i=0; i<block.options.size(); i++) {
+ if (block.options[i].name == "name")
+ pythonName = block.options[i].value;
+ else
+ errMsg(block.line0, "PYTHON(opt): illegal option. Supported options are: 'name'");
+ }
+
+ // generate glue layer function
+ const string table[] = { "NAME", var.name,
+ "CLASS", block.parent->name,
+ "CTPL", !block.parent->isTemplated() ? "" : "$CT$",
+ "PYNAME", pythonName,
+ "TYPE", var.returnType.minimal,
+ "" };
+
+ // output function and accessors
+ sink.inplace << block.linebreaks() << var.minimal << ";";
+ sink.inplace << replaceSet(TmpGetSet, table);
+
+ // register accessors
+ const string reg = replaceSet(TmpRegisterGetSet, table);
+ sink.link << '+' << block.parent->name << '^' << reg << '\n';
+}
+
+void processPythonClass(const Block& block, const string& code, Sink& sink, vector<Instantiation>& inst) {
+ const Class& cls = block.cls;
+ string pythonName = cls.name;
+
+ if (!sink.isHeader)
+ errMsg(block.line0, "PYTHON classes can only be defined in header files.");
+
+ // PYTHON(...) keyword options
+ for (size_t i=0; i<block.options.size(); i++) {
+ if (block.options[i].name == "name")
+ pythonName = block.options[i].value;
+ else
+ errMsg(block.line0, "PYTHON(opt): illegal kernel option. Supported options are: 'name'");
+ }
+
+ if (gDocMode) {
+ sink.inplace << "//! \\ingroup PyClasses\nPYTHON " << cls.minimal;
+ return;
+ }
+
+ // register class
+ const string table[] = { "CLASS", cls.name,
+ "BASE", cls.baseClass.name,
+ "BTPL", cls.baseClass.isTemplated() ? "<$BT$>" : "",
+ "PYNAME", pythonName,
+ "CTPL", cls.isTemplated() ? "CT" : "",
+ "" };
+
+ // register class
+ string reg = replaceSet(TmpRegisterClass, table);
+ sink.link << '+' << cls.name << '^' << reg << '\n';
+ // instantiate directly if not templated
+ if (!cls.isTemplated())
+ sink.link << '>' << cls.name << "^\n";
+ // chain the baseclass instantiation
+ if (cls.baseClass.isTemplated())
+ sink.link << '@' << cls.name << '^' << cls.templateTypes.names() << '^'
+ << cls.baseClass.name << '^' << cls.baseClass.templateTypes.names() << '\n';
+
+ // write signature
+ sink.inplace << block.linebreaks() << cls.minimal << "{";
+
+ // remove first {, and steal two linebreaks so we can add a #define later
+ string ncode = code.substr(1);
+ stealLinebreaks(ncode, 2);
+
+ // scan code for member functions
+ gFoundConstructor = false;
+ processText(ncode.substr(1), block.line0, sink, &cls, inst);
+ if (!gFoundConstructor)
+ errMsg(block.line0, "no PYTHON constructor found in class '" + cls.name + "'");
+
+ // add secret bonus members to class and close
+ sink.inplace << "public: PbArgs _args;";
+ sink.inplace << "}\n";
+ // add a define to make commenting out classes, and #ifdefs work correctly
+ sink.inplace << "#define _C_" << cls.name << '\n';
+}
+
+void processPythonInstantiation(const Block& block, const Type& aliasType, Sink& sink, vector<Instantiation>& inst) {
+ string parent = block.parent ? block.parent->name : "";
+ // for template functions, add to instantiation list
+ bool isFunction = false;
+ for (int i=0; i<(int)inst.size(); i++) {
+ if (inst[i].cls == parent && inst[i].name == aliasType.name) {
+ inst[i].templates.push_back(aliasType.templateTypes.listText);
+ isFunction = true;
+ break;
+ }
+ }
+ // otherwise, assume it's a class, and put down a link-time instantiation request
+ if (!isFunction) {
+ sink.link << '>' << aliasType.name << '^' << aliasType.templateTypes.listText << '\n';
+ }
+}
+
+void processPythonAlias(const Block& block, const Type& aliasType, const string& aliasName, Sink& sink) {
+ const string table[] = {"CLASS", strip(aliasType.build()), "PYNAME", aliasName, ""};
+ if (!aliasName.empty())
+ sink.link << '&' << replaceSet(TmpAlias,table) << '\n';
+}
+
+// build the template argument checker needed for template deduction in the wrapper
+string buildTemplateChecker(string& out, const Function& func) {
+ stringstream chk;
+ for (int k=0; k<(int)func.arguments.size(); k++) {
+ stringstream num; num << k;
+ Type type = func.arguments[k].type;
+ type.isPointer = false;
+ type.isRef = false;
+ type.isConst = false;
+ chk << "A.typeCheck<" << type.build() << " >("
+ << num.str() << ",\"" << func.arguments[k].name << "\")";
+
+ if (k != (int)func.arguments.size()-1)
+ chk << " && ";
+ }
+
+ static int idx = 0;
+ stringstream name;
+ name << "_K_" << idx++;
+ const string table[] = { "TEMPLATE", func.templateTypes.minimal,
+ "NAME", name.str(),
+ "CHK", chk.str(),
+ "" };
+ out+= replaceSet(TmpTemplateChecker,table);
+ return name.str();
+}
+
+// add a wrapper for all templated function
+void postProcessInstantiations(Sink& sink, vector<Instantiation>& inst) {
+ string out = sink.inplace.str();
+ for (int i=0; i<(int)inst.size(); i++) {
+ Instantiation& cur = inst[i];
+ if (cur.templates.size() == 0)
+ errMsg(0, cur.cls + "::" + cur.name + " : templated function without instantiation detected.");
+
+ string wrapper = "";
+ stringstream chkCall;
+ // loop over overloaded functions
+ for (int k=0; k<(int)cur.func.size(); k++) {
+ string chkFunc = buildTemplateChecker(wrapper, cur.func[k]);
+
+ // build argument checker
+ for (int j=0; j<(int)cur.templates.size(); j++) {
+ stringstream num; num << j;
+ chkCall << "if (" << chkFunc << "<" << cur.templates[j] << ">(args)) {";
+ chkCall << "hits++; call = _W_T_" << cur.wrapName[k] << "<" << cur.templates[j] <<">; }";
+ }
+ }
+ const string table[] = { "CONSTRUCTOR", cur.name == cur.cls ? "Y":"",
+ "WRAPPER", cur.wrapName[0],
+ "TEMPLATE_CHECK", chkCall.str(),
+ "FUNCNAME", cur.name,
+ "RET", cur.name == cur.cls ? "int" : "PyObject*",
+ "" };
+ wrapper += replaceSet(cur.func[0].isOperator ? TmpTemplateWrapperOp : TmpTemplateWrapper, table);
+
+ stringstream num;
+ num << "$" << i << "$";
+ replaceAll(out, num.str(), wrapper);
+ }
+ sink.inplace.str(out);
+} \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/preprocessor/main.cpp b/source/blender/python/manta_full/source/preprocessor/main.cpp
new file mode 100644
index 00000000000..02c0c3a0c03
--- /dev/null
+++ b/source/blender/python/manta_full/source/preprocessor/main.cpp
@@ -0,0 +1,120 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Preprocessor Main
+ *
+ ******************************************************************************/
+
+#include <string>
+#include <sstream>
+#include <fstream>
+#include <streambuf>
+#include <iostream>
+#include <cstdlib>
+#include <cstring>
+
+#include "prep.h"
+
+using namespace std;
+
+string gFilename;
+bool gDebugMode = true;
+bool gDocMode;
+bool gIsHeader;
+MType gMTType = MTNone;
+
+
+void usage() {
+ cerr << "preprocessor error: Unknown parameters." << endl;
+ cerr << " Usage : prep generate <dbg_mode> <mt_type> <inputdir> <inputfile> <outputfile>" << endl;
+ cerr << " or : prep docgen <dbg_mode> <mt_type> <inputdir> <inputfile> <outputfile>" << endl;
+ cerr << " or : prep link <regfiles...>" << endl;
+ exit(1);
+}
+
+void doMerge(int argc, char* argv[]) {
+ if (argc < 3) usage();
+
+ generateMerge(argc-2, &argv[2]);
+}
+
+void doGenerate(int argc, char* argv[], bool docs) {
+ gDocMode = docs;
+ gDebugMode = false;
+ gMTType = MTNone;
+ if (argc != 7) usage();
+
+ // set constants
+ const string indir(argv[4]), infile(argv[5]), outfile(argv[6]);
+ bool isPython = infile.size() > 3 && !infile.compare(infile.size()-3, 3, ".py");
+
+ // TP : only enable in cmake's PREP_DEBUG mode (passed via cmd line option dbg_mode)
+ gDebugMode = atoi(argv[2]) != 0;
+ if (!strcmp(argv[3],"TBB")) gMTType = MTTBB;
+ if (!strcmp(argv[3],"OPENMP")) gMTType = MTOpenMP;
+
+ // load complete file into buffer
+ gFilename = indir+infile;
+ string text = readFile(gFilename);
+ if (text.empty()) {
+ cerr << "preprocessor error: Can't read file '" << infile << "'" << endl;
+ exit(1);
+ }
+ // pad text for easier lexing lookups
+ text += "\n\n\n";
+
+ Sink sink(infile,outfile);
+ if (gDocMode) {
+ sink.inplace << "/*! \\file " + infile + " */\n";
+ } else {
+ sink.inplace << "\n\n\n\n\n// DO NOT EDIT !\n";
+ sink.inplace << "// This file is generated using the MantaFlow preprocessor (prep generate).";
+ sink.inplace << "\n\n\n\n\n";
+ }
+
+ if (isPython) {
+ // python file, only registering
+ replaceAll(text, "\n", "\\n");
+ replaceAll(text, "\r", "");
+ replaceAll(text, "\t", "\\t");
+ replaceAll(text, "\"", "<qtm>"); // split into two ops to avoid interference
+ replaceAll(text, "<qtm>", "\\\"");
+ sink.link << "#include \"registry.h\"\n";
+ sink.link << "static const Pb::Register _reg(\"" + infile + "\", \"" + text + "\");\n";
+ } else {
+ if (!gDocMode) {
+ sink.link << "#include \"" + infile + "\"\n";
+ if (!gDebugMode)
+ sink.inplace << "#line 1 \"" << indir << infile << "\"\n";
+ }
+ std::vector<Instantiation> inst;
+ processText(text, 1, sink, 0, inst);
+ postProcessInstantiations(sink, inst);
+ }
+ sink.write();
+}
+
+
+int main(int argc, char* argv[]) {
+ // command line options
+ if (argc < 2) usage();
+
+ // use merger
+ if (!strcmp(argv[1],"link"))
+ doMerge(argc, argv);
+ else if (!strcmp(argv[1],"generate"))
+ doGenerate(argc, argv, false);
+ else if (!strcmp(argv[1],"docgen"))
+ doGenerate(argc, argv, true);
+ else
+ usage();
+
+ return 0;
+}
+
diff --git a/source/blender/python/manta_full/source/preprocessor/merge.cpp b/source/blender/python/manta_full/source/preprocessor/merge.cpp
new file mode 100644
index 00000000000..ae103b76f38
--- /dev/null
+++ b/source/blender/python/manta_full/source/preprocessor/merge.cpp
@@ -0,0 +1,179 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Preprocessor merge file gen
+ *
+ ******************************************************************************/
+
+#include <map>
+#include <iostream>
+#include <sstream>
+#include <cstdlib>
+#include "prep.h"
+using namespace std;
+
+struct Chain {
+ Chain() {};
+ Chain(const string& tpl, const string& target, const string& targetTpl) :
+ tpl(tpl), target(target), targetTpl(targetTpl) {}
+ string tpl, target, targetTpl;
+};
+
+struct Request {
+ Request(const string& c, const string& t) : cls(c), tpl(t), base("") {}
+ string cls, tpl, base;
+};
+
+struct RegFile {
+ RegFile(const string& name) : filename(name),idx(0) {}
+
+ string filename;
+ ostringstream out, header, footer;
+ vector<Request> req;
+ int idx;
+};
+
+struct ClassInfo {
+ map<string,bool> tplDone;
+ vector<string> snippets;
+};
+
+static map<string, ClassInfo> classes;
+static map<string, Chain> chains;
+static vector<RegFile *> regFiles;
+
+// compare template arguments
+string mapArgs(const string& inst, const string& match, const string& target) {
+ vector<string> inArg = split(inst,',');
+ vector<string> maArg = split(match,',');
+ vector<string> taArg = split(target,',');
+ vector<string> destArg = taArg;
+
+ for (int i=0; i<(int)maArg.size(); i++) {
+ for (int j=0; j<(int)taArg.size(); j++) {
+ if (maArg[i] == taArg[j]) {
+ destArg[j] = inArg[i];
+ }
+ }
+ }
+ stringstream s;
+ for (int i=0; i<(int)destArg.size(); i++) {
+ s << destArg[i];
+ if (i != (int)destArg.size()-1) s << ',';
+ }
+ return s.str();
+}
+
+void resolveChains(RegFile& file) {
+ for (int i=0; i<(int)file.req.size(); i++) {
+ Request& req = file.req[i];
+ map<string, Chain>::iterator it = chains.find(req.cls);
+ if (it != chains.end()) {
+ Chain& chain = it->second;
+ string tpl = mapArgs(req.tpl, chain.tpl, chain.targetTpl);
+ req.base = tpl;
+ file.req.push_back(Request(chain.target, tpl));
+ }
+ }
+}
+
+void resolveRequests(RegFile& file) {
+ // sort request by class
+ map<string, vector<Request*> > sortedReqs;
+ for (int i=0; i<(int)file.req.size(); i++) {
+ Request& req = file.req[i];
+ ClassInfo& info = classes[req.cls];
+ if (!info.tplDone[req.tpl]) {
+ info.tplDone[req.tpl] = true;
+ sortedReqs[req.cls].push_back(&req);
+ }
+ }
+
+ // process requests
+ for(map<string,vector<Request*> >::iterator it = sortedReqs.begin(); it != sortedReqs.end(); ++it) {
+ ClassInfo& info = classes[it->first];
+ file.out << "#ifdef _C_" << it->first << '\n';
+ for (int i=0; i<(int)it->second.size(); i++) {
+ Request& req = *(it->second[i]);
+ for (int j=0; j<(int)info.snippets.size(); j++) {
+ stringstream idxStr;
+ idxStr << file.idx++;
+ const string table[] = {"CT", req.tpl, "BT", req.base, "IDX", idxStr.str(), ""};
+ file.out << replaceSet(info.snippets[j], table) << '\n';
+ }
+ }
+ file.out << "#endif\n";
+ }
+}
+
+// create data structure from regfiles
+void parseLine(const string& line, RegFile& file) {
+ if (line.empty()) return;
+
+ vector<string> parts = split(line,'^');
+ string cls = parts[0].substr(1);
+
+ if (line[0] == '+')
+ classes[cls].snippets.push_back(parts[1]);
+ else if (line[0] == '>')
+ file.req.push_back(Request(cls,parts[1]));
+ else if (line[0] == '@')
+ chains[cls] = Chain(parts[1],parts[2],parts[3]);
+ else if (line[0] == '#')
+ file.header << line << '\n';
+ else if (line[0] == '&') {
+ string txt = line.substr(1);
+ stringstream num; num << file.idx++;
+ replaceAll(txt, "$IDX$", num.str());
+ file.footer << txt << '\n';
+ } else {
+ file.out << line << '\n';
+ }
+}
+
+void generateMerge(int num, char* files[]) {
+ // parse files
+ for (int i=0; i<num; i++) {
+ regFiles.push_back(new RegFile(files[i]));
+
+ string text = readFile(files[i]);
+ replaceAll(text,"\r","");
+ vector<string> lines = split(text,'\n');
+
+ for (int j=0; j<(int)lines.size(); j++)
+ parseLine(lines[j], *regFiles.back());
+ }
+
+ // process and save files
+ for (int i=0; i<num; i++) {
+ resolveChains(*regFiles[i]);
+ resolveRequests(*regFiles[i]);
+
+ string text = "", fn = regFiles[i]->filename;
+ bool isPython = fn.compare(fn.size()-7, 7, ".py.reg") == 0;
+
+ if (regFiles[i]->idx > 0) {
+ text = "\n\n\n\n\n// DO NOT EDIT !\n";
+ text += "// This file is generated using the MantaFlow preprocessor (prep link).";
+ text += "\n\n\n\n\n";
+ text += regFiles[i]->header.str();
+ text += "namespace Manta {\n";
+ text += regFiles[i]->out.str();
+ text += regFiles[i]->footer.str();
+ text += "}";
+ } else if (isPython) {
+ text = regFiles[i]->header.str() + regFiles[i]->out.str() + regFiles[i]->footer.str();
+ }
+ string filename = fn + ".cpp";
+ // only write if content is different
+ if (!fileExists(filename) || readFile(filename) != text)
+ writeFile(filename, text);
+ delete regFiles[i];
+ }
+}
diff --git a/source/blender/python/manta_full/source/preprocessor/parse.cpp b/source/blender/python/manta_full/source/preprocessor/parse.cpp
new file mode 100644
index 00000000000..8af4e33f2b6
--- /dev/null
+++ b/source/blender/python/manta_full/source/preprocessor/parse.cpp
@@ -0,0 +1,356 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Preprocessor Parsing
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <cstdlib>
+#include <algorithm>
+#include "prep.h"
+
+using namespace std;
+
+List<Type> parseTypeList(TokenPointer& parentPtr);
+
+//*************************************************************
+// parsers
+
+#define tkAssert(x,msg) {if(!(x)){tk.errorMsg(msg);}}
+#define typeAssert(x) tkAssert(x," is not a valid type.")
+#define argAssert(x) tkAssert(x," is not a valid argument.")
+
+string parseRunaway(TokenPointer& parentPtr) {
+ Text text;
+ TokenPointer tk(parentPtr, &text);
+
+ // don't validate, just track bracket level
+ BracketStack stack;
+ for(;!tk.done();tk.next()) {
+ if (stack.empty() && (tk.curType() == TkComma ||
+ tk.curType() == TkBracketR || tk.curType() == TkTBracketR)) {
+ break;
+ }
+ if (tk.curType() == TkBracketL || tk.curType() == TkTBracketL) {
+ stack.push_back(tk.cur().text[0]);
+ } else if (tk.curType() == TkBracketR) {
+ argAssert(stack.pop() == '(');
+ } else if (tk.curType() == TkTBracketR) {
+ argAssert(stack.pop() == '<');
+ }
+ }
+ argAssert(stack.empty());
+ return text.minimal;
+}
+
+void parsePointer(TokenPointer& tk, Type& cur) {
+ if (tk.done()) return;
+ if (tk.cur().type == TkOperator && tk.cur().text == "*") {
+ cur.isPointer = true;
+ tk.next();
+ } else if (tk.cur().type == TkRef) {
+ cur.isRef = true;
+ tk.next();
+ }
+}
+
+Type parseType(TokenPointer& parentPtr) {
+ Type cur = Type();
+ TokenPointer tk(parentPtr, &cur);
+
+ // constness
+ if (tk.curType() == TkConst) {
+ cur.isConst = true;
+ tk.next();
+ }
+ typeAssert(!tk.done());
+
+ // signed / unsigned
+ if (tk.curType() == TkTypeQualifier) {
+ cur.name = tk.cur().text;
+ tk.next();
+ if (tk.done())
+ return cur;
+ typeAssert(tk.curType() == TkSimpleType);
+ cur.name += " " + tk.cur().text;
+ tk.next();
+ parsePointer(tk, cur);
+ return cur;
+ }
+
+ // template argument
+ if (tk.curType() == TkClass) {
+ tk.next();
+ }
+
+ typeAssert(tk.curType() == TkDescriptor || tk.curType() == TkSimpleType);
+ cur.name = tk.cur().text;
+ tk.next();
+ if (cur.name == "operator") {
+ while (tk.curType() == TkOperator) {
+ cur.name += tk.cur().text;
+ tk.next();
+ }
+ }
+
+ // namespace
+ if (tk.curType() == TkDoubleColon) {
+ cur.name += "::";
+ tk.next();
+ typeAssert(tk.curType() == TkDescriptor || tk.curType() == TkSimpleType);
+ cur.name += tk.cur().text;
+ tk.next();
+ }
+
+ // template
+ if (tk.curType() == TkTBracketL) {
+ cur.templateTypes = parseTypeList(tk);
+ }
+
+ parsePointer(tk, cur);
+ return cur;
+}
+
+Argument parseArgument(TokenPointer& parentPtr, bool requireName, bool requireType) {
+ Argument cur = Argument();
+ TokenPointer tk(parentPtr, &cur);
+
+ if (requireType)
+ cur.type = parseType(tk);
+
+ if (tk.curType() != TkDescriptor && !requireName)
+ return cur;
+
+ argAssert(tk.curType() == TkDescriptor);
+ cur.name = tk.cur().text;
+ tk.next();
+
+ // default value ?
+ if (tk.curType() == TkBracketL || (tk.curType() == TkOperator && tk.cur().text == "=")) {
+ if (tk.curType() == TkOperator)
+ tk.next();
+ cur.value = parseRunaway(tk);
+ }
+ return cur;
+}
+
+List<Type> parseTypeList(TokenPointer& parentPtr) {
+ List<Type> list;
+ TokenPointer tk(parentPtr, &list);
+
+ tkAssert(tk.curType() == TkTBracketL, "expect template opening bracket");
+ tk.next();
+ if (tk.curType() != TkTBracketR) {
+ for(;;) {
+ list.push_back(parseType(tk));
+ if (tk.curType() == TkTBracketR)
+ break;
+ tkAssert(tk.curType() == TkComma, "expect comma or closing bracket");
+ tk.next();
+ }
+ }
+ list.listText = list.minimal.substr(1);
+ tkAssert(tk.curType() == TkTBracketR, "expect template closing bracket");
+ tk.next();
+ return list;
+}
+
+List<Argument> parseArgumentList(TokenPointer& parentPtr, bool requireName, bool requireType) {
+ List<Argument> list;
+ TokenPointer tk(parentPtr, &list);
+
+ tkAssert(tk.curType() == TkBracketL, "expect opening bracket");
+ tk.next();
+ if (tk.curType() != TkBracketR) {
+ for(int idx=0;;idx++) {
+ list.push_back(parseArgument(tk, requireName, requireType));
+ list.back().index = idx;
+ if (tk.curType() == TkBracketR)
+ break;
+ tkAssert(tk.curType() == TkComma, "expect comma or closing bracket");
+ tk.next();
+ }
+ }
+ list.listText = list.minimal.substr(1);
+ tkAssert(tk.curType() == TkBracketR, "expect closing bracket");
+ tk.next();
+ return list;
+}
+
+Function parseFunction(TokenPointer& parentPtr, bool requireNames, bool requireType, bool requireArgs) {
+ Function cur;
+ TokenPointer tk(parentPtr, &cur);
+
+ // templated
+ if (tk.curType() == TkTemplate) {
+ tk.next();
+ cur.templateTypes = parseTypeList(tk);
+ }
+
+ for (;tk.curType() == TkInline || tk.curType() == TkVirtual; tk.next()) {
+ if (tk.curType() == TkInline) cur.isInline = true;
+ if (tk.curType() == TkVirtual) cur.isVirtual = true;
+ }
+
+ if (requireType)
+ cur.returnType = parseType(tk);
+ tkAssert(tk.curType() == TkDescriptor, "malformed function/kernel");
+ cur.name = tk.cur().text;
+ tk.next();
+
+ if (cur.name == "operator") {
+ cur.isOperator = true;
+ while(tk.curType() == TkOperator) {
+ cur.name += tk.cur().text;
+ tk.next();
+ }
+ }
+
+ if (requireArgs || tk.curType() == TkBracketL)
+ cur.arguments = parseArgumentList(tk, requireNames, true);
+ else
+ cur.noParentheses = true;
+
+ if (tk.curType() == TkConst) {
+ cur.isConst = true;
+ tk.next();
+ }
+ return cur;
+}
+
+Class parseClass(TokenPointer& parentPtr) {
+ Class cur;
+ TokenPointer tk(parentPtr, &cur);
+
+ tkAssert(tk.curType() == TkClass, "");
+ tk.next();
+ tkAssert(tk.curType() == TkDescriptor, "malformed preprocessor keyword block. Expected 'PYTHON class name : public X {}'");
+ cur.name = tk.cur().text;
+ tk.next();
+ tkAssert(tk.curType() == TkColon, "PYTHON class must publicly derive from PbClass (or a subclass)");
+ tk.next();
+ tkAssert(tk.curType() == TkPublic, "PYTHON class must publicly derive from PbClass (or a subclass)");
+ tk.next();
+ tkAssert(tk.curType() == TkDescriptor, "PYTHON class must publicly derive from PbClass (or a subclass)");
+ cur.baseClass = parseType(tk);
+
+ return cur;
+}
+
+// Parse syntax KEYWORD(opt1, opt2, ...) STATEMENTS [ {} or ; ]
+void parseBlock(const string& kw, const vector<Token>& tokens, const Class* parent, Sink& sink, vector<Instantiation>& inst) {
+ Block block = Block();
+ block.parent = parent;
+ TokenPointer tk(tokens, &block);
+
+ // parse keyword options
+ if (tk.curType() == TkBracketL)
+ block.options = parseArgumentList(tk, true, false);
+
+ if (kw == "KERNEL") {
+ List<Type> templTypes;
+
+ // templated kernel
+ if (tk.curType() == TkTemplate) {
+ tk.next();
+ templTypes = parseTypeList(tk);
+ }
+
+ // return values
+ while (tk.curType() == TkDescriptor && tk.cur().text == "returns") {
+ tk.next();
+ tkAssert(tk.curType() == TkBracketL, "expext opening bracket");
+ tk.next();
+ block.locals.push_back(parseArgument(tk, true, true));
+ tkAssert(tk.curType() == TkBracketR, "expect closing bracket");
+ tk.next();
+ }
+
+ block.func = parseFunction(tk, true, true, true);
+ if (!templTypes.empty())
+ block.func.templateTypes = templTypes;
+
+ tkAssert(tk.curType() == TkCodeBlock && tk.isLast(),
+ "Malformed KERNEL, expected KERNEL(opts...) ret_type name(args...) { code }");
+
+ block.line1 = tk.cur().line;
+ processKernel(block, tk.cur().text, sink);
+ }
+ else if (kw == "PYTHON")
+ {
+ // template instantiation / alias
+ if (tk.curType() == TkDescriptor && (tk.cur().text == "alias" || tk.cur().text == "instantiate")) {
+ string kw = tk.cur().text;
+ Type aliasType;
+ do {
+ tk.next();
+ aliasType = parseType(tk);
+ processPythonInstantiation(block, aliasType, sink, inst);
+ } while (tk.curType() == TkComma);
+
+ if (kw == "alias") {
+ tkAssert(tk.curType() == TkDescriptor, "malformed preprocessor block. Expected 'PYTHON alias cname pyname;'");
+ string aliasName = tk.cur().text;
+ processPythonAlias(block, aliasType, aliasName, sink);
+ tk.next();
+ }
+ tkAssert(tk.curType() == TkSemicolon && tk.isLast(), "malformed preprocessor block. Expected 'PYTHON alias/instantiate cname [pyname];'");
+ sink.inplace << block.linebreaks();
+
+ return;
+ }
+ List<Type> templTypes;
+
+ // resolve template class
+ Text templText;
+ if (tk.curType() == TkTemplate) {
+ TokenPointer t2(tk, &templText);
+ t2.next();
+ templTypes = parseTypeList(t2);
+ }
+
+ // python class
+ if (tk.curType() == TkClass && tk.cur().text != "typename") {
+ block.cls = parseClass(tk);
+ block.cls.templateTypes = templTypes;
+ block.cls.prequel(&templText);
+ tkAssert(tk.curType() == TkCodeBlock && tk.isLast(), "malformed preprocessor keyword block. Expected 'PYTHON class name : public X {}'");
+ processPythonClass(block, tk.cur().text, sink, inst);
+ }
+ else // function or member
+ {
+ bool isConstructor = parent && tk.curType() == TkDescriptor &&
+ parent->name == tk.cur().text && tk.previewType() == TkBracketL;
+ block.func = parseFunction(tk, false, !isConstructor, false);
+ block.func.templateTypes = templTypes;
+ block.func.prequel(&templText);
+
+ if (isConstructor && tk.curType() == TkColon) {
+ // read till end
+ while(!tk.done() && tk.curType() != TkSemicolon && tk.curType() != TkCodeBlock) {
+ block.initList += tk.cur().text;
+ tk.next();
+ }
+ tkAssert(!tk.done(), "Constructor initializer list not limited");
+ }
+
+ if (tk.curType() == TkSemicolon && block.func.noParentheses) {
+ tkAssert(tk.curType() == TkSemicolon && tk.isLast(),
+ "malformed preprocessor keyword block. Expected 'PYTHON type varname;'");
+ processPythonVariable(block, sink);
+ } else {
+ tkAssert((tk.curType() == TkCodeBlock || tk.curType() == TkSemicolon) && tk.isLast(),
+ "malformed preprocessor keyword block. Expected 'PYTHON type funcname(args) [{}|;]'");
+ processPythonFunction(block, tk.cur().text, sink, inst);
+ }
+ }
+
+ }
+}
diff --git a/source/blender/python/manta_full/source/preprocessor/prep.h b/source/blender/python/manta_full/source/preprocessor/prep.h
new file mode 100644
index 00000000000..f066b4fae65
--- /dev/null
+++ b/source/blender/python/manta_full/source/preprocessor/prep.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Preprocessor Declarations
+ *
+ ******************************************************************************/
+
+#ifndef _PREP_H
+#define _PREP_H
+
+#include "util.h"
+#include "code.h"
+#include "tokenize.h"
+
+// from main.cpp
+enum MType { MTNone = 0, MTTBB, MTOpenMP};
+extern std::string gFilename;
+extern bool gDebugMode;
+extern MType gMTType;
+extern bool gDocMode;
+
+// functions from merge.cpp
+void generateMerge(int num, char* files[]);
+
+// functions from tokenize.cpp
+void processText(const std::string& text, int baseline, Sink& sink, const Class *parent, std::vector<Instantiation>& inst);
+
+// functions from parse.cpp
+void parseBlock(const std::string& kw, const std::vector<Token>& tokens, const Class *parent, Sink& sink, std::vector<Instantiation>& inst);
+
+// functions from codegen_XXX.cpp
+void processKernel(const Block& block, const std::string& code, Sink& sink);
+void processPythonFunction(const Block& block, const std::string& code, Sink& sink, std::vector<Instantiation>& inst);
+void processPythonVariable(const Block& block, Sink& sink);
+void processPythonClass(const Block& block, const std::string& code, Sink& sink, std::vector<Instantiation>& inst);
+void processPythonInstantiation(const Block& block, const Type& aliasType, Sink& sink, std::vector<Instantiation>& inst);
+void processPythonAlias(const Block& block, const Type& aliasType, const std::string& aliasName, Sink& sink);
+void postProcessInstantiations(Sink& sink, std::vector<Instantiation>& inst);
+
+#endif // _PREP_H
diff --git a/source/blender/python/manta_full/source/preprocessor/tokenize.cpp b/source/blender/python/manta_full/source/preprocessor/tokenize.cpp
new file mode 100644
index 00000000000..ae5294b7446
--- /dev/null
+++ b/source/blender/python/manta_full/source/preprocessor/tokenize.cpp
@@ -0,0 +1,348 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Preprocessor Tokenizer
+ *
+ ******************************************************************************/
+
+#include <string>
+#include <iostream>
+#include <vector>
+#include <algorithm>
+
+#include "prep.h"
+
+using namespace std;
+
+//*************************************************************************************
+// TokenPointer class members
+
+TokenType TokenPointer::previewType() {
+ for (int i=ptr+1; i < (int)queue.size(); i++) {
+ if (queue[i].type != TkWhitespace && queue[i].type != TkComment)
+ return queue[i].type;
+ }
+ return TkNone;
+}
+
+void TokenPointer::consumeWhitespace() {
+ if (done()) return;
+ while (cur().type == TkWhitespace || cur().type == TkComment) {
+ string minimal = (!txt->minimal.empty() && *(txt->minimal).rbegin() == ' ') ? "" : " ";
+ forward(minimal,cur().text,1);
+ if (ptr >= (int)queue.size())
+ errMsg(-1, "Preprocessor ran out of tokens. This shouldn't happen.");
+ }
+}
+
+void TokenPointer::next() {
+ forward(cur().text, cur().text, 1);
+ consumeWhitespace();
+}
+
+void TokenPointer::forward(const string& minimal, const string& original, int offset) {
+ txt->minimal += minimal;
+ txt->original += original;
+ ptr += offset;
+ if (parent)
+ parent->forward(minimal, original, offset);
+}
+
+string TokenPointer::backtrace() {
+ string bt = "[" + txt->dynamicClass() + "]: " + txt->original + "\n";
+ if (parent)
+ bt += parent->backtrace();
+ return bt;
+}
+
+void TokenPointer::errorMsg(const string& msg) {
+ string emsg = "'" + txt->original;
+ if (!done()) emsg += cur().text;
+ emsg += "' " + msg + "\n";
+ emsg += " Preprocessor backtrace:\n" + backtrace();
+
+ int line = -1;
+ if (!queue.empty())
+ line = done() ? queue.back().line : cur().line;
+
+ errMsg(line, emsg);
+}
+
+//*************************************************************************************
+// Lexing functions
+
+// tokenize and parse until keyword section ends
+void tokenizeBlock(vector<Token>& tokens, const string& kw, const string& text, size_t& i, int& line) {
+ tokens.push_back(Token(TkWhitespace, line));
+ BracketStack brackets;
+
+ // tokenize loop
+ bool comment=false, slComment=false, define=false, extendLine=false;
+ bool isString=false;
+ int codeblockLevel = 0;
+ for (; i<text.size(); i++) {
+ char c = text[i];
+ if (c=='\r') continue;
+
+ string& curstr = tokens.back().text;
+ bool lastchar = (i == text.size()-1) || (i == text.size()-2 && text[i+1]=='\r');
+
+ // track lines
+ bool isEOL = !extendLine && c=='\n';
+ if (c=='\\')
+ extendLine = true;
+ else if (c!='\n')
+ extendLine = false;
+ if (c=='\n') line++;
+
+ // track comments and defines
+ if (comment) {
+ if (!lastchar && c=='*' && text[i+1]=='/') comment = false;
+ curstr += c;
+ }
+ else if (slComment) {
+ if (isEOL) slComment = false;
+ curstr += c;
+ }
+ else if (define) {
+ if (isEOL) define = false;
+ curstr += c;
+ }
+ else if (!lastchar && c=='/' && text[i+1]=='*') {
+ comment = true;
+ if (codeblockLevel==0)
+ tokens.push_back(Token(TkComment, line, c));
+ else
+ curstr += c;
+ }
+ else if (!lastchar && c=='/' && text[i+1]=='/') {
+ slComment = true;
+ if (codeblockLevel==0)
+ tokens.push_back(Token(TkComment, line, c));
+ else
+ curstr += c;
+ }
+ else if (!isString && c=='\"' && codeblockLevel == 0) {
+ isString = true;
+ tokens.push_back(Token(TkString, line, c));
+ }
+ else if (isString) {
+ if (c=='\"') isString = false;
+ curstr += c;
+ }
+ else if (c=='#') {
+ define = true;
+ if (codeblockLevel==0)
+ tokens.push_back(Token(TkComment, line, c));
+ else
+ curstr += c;
+ }
+
+ // track codeblock
+ else if (codeblockLevel > 0) {
+ curstr += c;
+ if (c == '}') codeblockLevel--;
+ if (c == '{') codeblockLevel++;
+
+ if (codeblockLevel == 0) {
+ // block finished, return to parseText
+ return;
+ }
+ }
+ else if (c=='{') {
+ codeblockLevel++;
+ if (!brackets.empty())
+ errMsg(line, "codeblock {} is not allowed inside brackets.");
+ tokens.push_back(Token(TkCodeBlock, line, c));
+ }
+
+ // track brackets
+ else if (c=='(') {
+ tokens.push_back(Token(TkBracketL, line, c));
+ brackets.push_back(c);
+ }
+ else if (c==')') {
+ if (brackets.pop() != '(')
+ errMsg(line, "bracket mismatch, can't close ')'");
+ tokens.push_back(Token(TkBracketR, line, c));
+ }
+ else if (c=='<') {
+ tokens.push_back(Token(TkTBracketL, line, c));
+ brackets.push_back(c);
+ }
+ else if (c=='>') {
+ if (brackets.pop() != '<')
+ errMsg(line, "bracket mismatch, can't close '>'");
+ tokens.push_back(Token(TkTBracketR, line, c));
+ }
+
+ // track symbol tokens
+ else if (c==' ' || c=='\t' || c=='\n') {
+ tokens.push_back(Token(TkWhitespace, line, c));
+ }
+ else if (c==',') {
+ tokens.push_back(Token(TkComma, line, c));
+ }
+ else if (c=='*' || c=='-' || c=='+' || c=='/' || c=='=') {
+ tokens.push_back(Token(TkOperator, line, c));
+ }
+ else if (c=='&') {
+ tokens.push_back(Token(TkRef, line, c));
+ }
+ else if (c == ':') {
+ if (!lastchar && text[i+1]==':') {
+ tokens.push_back(Token(TkDoubleColon, line));
+ tokens.back().text = "::";
+ i++;
+ } else {
+ tokens.push_back(Token(TkColon, line, c));
+ }
+ }
+ else if (c==';') {
+ if (!brackets.empty())
+ errMsg(line, "Semicolon is not allowed inside brackets.");
+
+ tokens.push_back(Token(TkSemicolon, line, c));
+
+ // block finished, return to parseText
+ return;
+ }
+
+ // track descriptors
+ else if (isNameChar(c)) {
+ if (tokens.back().type != TkDescriptor)
+ tokens.push_back(Token(TkDescriptor, line, c));
+ else
+ curstr += c;
+ }
+ // misc stuff: don't bother with more complex tokens
+ else {
+ if (tokens.back().type != TkNone) {
+ tokens.push_back(Token(TkNone, line, c));
+ } else
+ curstr += c;
+ }
+ }
+
+ // EOF before block end ?
+ errMsg(line, "EOF before block for keyword '" + kw + "' was closed.");
+
+ return;
+}
+
+void convertKeywords(vector<Token>& tokens) {
+ for (size_t i=0; i<tokens.size(); i++) {
+ if (tokens[i].type == TkDescriptor) {
+ const string& t = tokens[i].text;
+ if (t == "const")
+ tokens[i].type = TkConst;
+ else if (t == "unsigned" || t == "signed")
+ tokens[i].type = TkTypeQualifier;
+ else if (t == "char" || t == "int" || t == "short" || t == "long" ||
+ t == "float" || t == "double" || t == "string" || t == "bool" ||
+ t == "Vec3" || t == "Vec3i")
+ tokens[i].type = TkSimpleType;
+ else if (t == "PYTHON" || t == "KERNEL")
+ tokens[i].type = TkManta;
+ else if (t == "struct" || t == "class" || t == "typename")
+ tokens[i].type = TkClass;
+ else if (t == "inline")
+ tokens[i].type = TkInline;
+ else if (t == "public")
+ tokens[i].type = TkPublic;
+ else if (t == "virtual")
+ tokens[i].type = TkVirtual;
+ else if (t == "static")
+ tokens[i].type = TkStatic;
+ else if (t == "template")
+ tokens[i].type = TkTemplate;
+ else {
+ for (int i=0; !unsupportedKeywords[i].empty(); i++) {
+ if (t == unsupportedKeywords[i])
+ tokens[i].type = TkUnsupportedKW;
+ }
+ }
+ }
+ }
+}
+
+// parse complete file.
+// Defer parts to be processed to processTextBlock, and directly copy the rest
+void processText(const string& text, int baseline, Sink& sink, const Class* parent, vector<Instantiation>& inst) {
+ ostream& newText = sink.inplace;
+
+ // no real lexing yet, only track define and comment blocks
+ string word = "";
+ int line=baseline;
+ bool comment=false, slComment=false, define=false, extendLine=false;
+ for (size_t i=0; i<text.size()-1; i++) {
+ char c = text[i];
+ if (c == '\r') continue;
+
+ // track lines
+ bool isEOL = !extendLine && c=='\n';
+ if (c=='\\')
+ extendLine = true;
+ else if (c!='\n')
+ extendLine = false;
+ if (c=='\n') line++;
+
+ // track comments and defines
+ if (comment) {
+ if (c=='*' && text[i+1]=='/') comment = false;
+ newText << c;
+ }
+ else if (slComment) {
+ if (isEOL) slComment = false;
+ newText << c;
+ }
+ else if (define) {
+ if (isEOL) define = false;
+ newText << c;
+ }
+ else if (c=='/' && text[i+1]=='*') {
+ comment = true;
+ newText << word;
+ word = "";
+ newText << c;
+ }
+ else if (c=='/' && text[i+1]=='/') {
+ slComment = true;
+ newText << word;
+ word = "";
+ newText << c;
+ }
+ else if (c=='#') {
+ define = true;
+ newText << word;
+ word = "";
+ newText << c;
+ }
+ else {
+ // tokenize keywords
+ if (isNameChar(c))
+ word += c;
+ else {
+ if (word == "KERNEL" || word == "PYTHON") {
+ vector<Token> tokens;
+ tokenizeBlock(tokens, word, text, i, line);
+ convertKeywords(tokens);
+ parseBlock(word, tokens, parent, sink, inst);
+ } else {
+ newText << word;
+ newText << c;
+ }
+ word = "";
+ }
+ }
+ }
+ newText << word;
+}
+
+
diff --git a/source/blender/python/manta_full/source/preprocessor/tokenize.h b/source/blender/python/manta_full/source/preprocessor/tokenize.h
new file mode 100644
index 00000000000..8785c211bcd
--- /dev/null
+++ b/source/blender/python/manta_full/source/preprocessor/tokenize.h
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Preprocessor Declarations
+ *
+ ******************************************************************************/
+
+#ifndef _P_TOKENIZE_H
+#define _P_TOKENIZE_H
+
+#include <string>
+#include <vector>
+#include "code.h"
+
+enum TokenType { TkNone = 0, TkComment, TkWhitespace, TkCodeBlock, TkDescriptor, TkComma, TkBracketL,
+ TkBracketR, TkTBracketL, TkTBracketR, TkPointer, TkRef, TkDoubleColon, TkSemicolon,
+ TkSimpleType, TkTypeQualifier, TkConst, TkEnd, TkManta, TkUnsupportedKW, TkClass,
+ TkInline, TkTemplate, TkStatic, TkVirtual, TkString, TkPublic, TkColon, TkOperator };
+
+const std::string unsupportedKeywords[] = {"and", "and", "and_eq", "auto", "bitand", "bitor", "break",
+ "catch", "const_cast", "continue", "default", "delete", "do", "dynamic_cast", "else", "enum",
+ "explicit", "export", "extern", "for", "friend", "goto", "if", "mutable", "namespace", "new",
+ "not", "not_eq", "or", "or_eq", "private", "protected", "register",
+ "reinterpret_cast", "return", "sizeof", "static_cast", "switch", "this", "throw", "try", "typedef",
+ "union", "using", "volatile", "while", "xor", "xor_eq", "" };
+
+inline bool isIntegral(const std::string& t) {
+ return t=="int" || t=="char" || t=="unsigned" || t=="bool" || t=="float" || t=="long" ||
+ t=="double" || t=="Real" || t=="Vec3" || t=="Vec3i" || t=="string" || t=="std::string" ||
+ t=="PbType" || t=="PbTypeVec";
+}
+
+struct Token {
+ Token(TokenType t, int l) : type(t), text(""), line(l) {}
+ Token(TokenType t, int l, char c) : type(t), text(""), line(l) { text += c; }
+ TokenType type;
+ std::string text;
+ int line;
+};
+
+// tracks a set of tokens, and the current position in this list
+struct TokenPointer {
+ TokenPointer(const std::vector<Token>& t, Text *track) : parent(0),queue(t),ptr(0),txt(track) { reset(); }
+ TokenPointer(TokenPointer& t, Text *track) : parent(&t),queue(t.queue),ptr(t.ptr),txt(track) { reset(); }
+ TokenPointer *parent;
+ const std::vector<Token>& queue;
+ int ptr;
+ Text *txt;
+
+ inline void reset() { txt->reset(); consumeWhitespace(); if(!done()) txt->line0 = cur().line; }
+ inline TokenType curType() { return done() ? TkEnd : cur().type; }
+ TokenType previewType();
+ inline const Token& cur() { return queue[ptr]; }
+ inline bool done() { return ptr >= (int)queue.size(); }
+ inline bool isLast() { return ptr == (int)queue.size()-1;}
+ void forward(const std::string& minimal, const std::string& original, int offset);
+ void next();
+ void consumeWhitespace();
+ void errorMsg(const std::string& msg);
+ std::string backtrace();
+};
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/preprocessor/util.cpp b/source/blender/python/manta_full/source/preprocessor/util.cpp
new file mode 100644
index 00000000000..ae67f0e4b26
--- /dev/null
+++ b/source/blender/python/manta_full/source/preprocessor/util.cpp
@@ -0,0 +1,217 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Preprocessor merge file gen
+ *
+ ******************************************************************************/
+
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <algorithm>
+#include <stack>
+#include "prep.h"
+using namespace std;
+
+void errMsg(int line, const string& text) {
+ cerr << gFilename << ":" << line << ": error: " << text << endl;
+ exit(1);
+}
+
+void debMsgHelper(int line, const string& text) {
+ cout << gFilename << ":" << line << ": info: " << text << endl;
+}
+
+bool fileExists(const string& name) {
+ ifstream t(name.c_str());
+ if (!t.good()) return false;
+ t.close();
+ return true;
+}
+
+string readFile(const string& name) {
+ ifstream t(name.c_str());
+ if (!t.good()) return "";
+
+ string str;
+
+ t.seekg(0, ios::end);
+ str.reserve((unsigned)t.tellg());
+ t.seekg(0, ios::beg);
+
+ str.assign((istreambuf_iterator<char>(t)),
+ istreambuf_iterator<char>());
+
+ t.close();
+ return str;
+}
+
+void writeFile(const string& name, const string& text) {
+ ofstream ofs(name.c_str(), ios::binary | ios::out);
+ if (!ofs.good()) {
+ cerr << "preprocessor error: Can't write to file '" << name << "'" << endl;
+ exit(1);
+ }
+ ofs << text;
+ ofs.close();
+}
+
+Sink::Sink(const string& infile, const string& outfile):
+ infile(infile), filename(outfile)
+{
+ isHeader = outfile.compare(outfile.size()-3, 3, ".py") == 0 ||
+ outfile.compare(outfile.size()-2, 2, ".h") == 0;
+}
+
+void Sink::write() {
+ writeFile(filename, inplace.str());
+ if (isHeader && !gDocMode) {
+ writeFile(filename + ".reg", link.str());
+ }
+}
+
+vector<string> split(const string& text, char sep) {
+ vector<string> bins;
+ string cur;
+ for (int i=0; i<(int)text.size(); i++) {
+ if (text[i]==sep) {
+ bins.push_back(cur);
+ cur = "";
+ } else
+ cur += text[i];
+ }
+ bins.push_back(cur);
+ return bins;
+}
+
+string strip(const string& s0) {
+ string s = s0;
+ while (s[0] == ' ') s=s.substr(1);
+ while (s[s.size()-1] == ' ') s=s.substr(0,s.size()-1);
+ return s;
+}
+
+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;
+ }
+}
+
+string makeSafe(const string& s) {
+ string t="_X_";
+ string source = "+=-<>!()";
+ string trans = "12345678";
+ for (int i=0; i<(int)s.size(); i++) {
+ size_t idx = source.find(s[i]);
+ t += (idx == string::npos) ? s[i] : trans[idx];
+ }
+ return t;
+}
+
+void stealLinebreaks(string& code, int num) {
+ // list all line breaks
+ vector<int> lb;
+ lb.push_back(-1);
+ for (int i=0; i<(int)code.size(); i++)
+ if (code[i] == '\n')
+ lb.push_back(i);
+ lb.push_back(code.size());
+
+ for (int i=lb.size()-2; i>0; i--) {
+ // make sure we don't mess with comments and defines
+ string curLine = code.substr(lb[i-1]+1,lb[i]-lb[i-1]-1);
+ string nextLine = code.substr(lb[i]+1, lb[i+1]-lb[i]-1);
+ if (curLine.find("//") == string::npos &&
+ curLine.find('#') == string::npos &&
+ nextLine.find('#') == string::npos) {
+ code[lb[i]] = ' ';
+ if (--num == 0)
+ return;
+ }
+ }
+ return;
+}
+
+// Helpers for replaceSet
+static string getBracketArg(const string& a, int &pos) {
+ string ret="";
+ pos++;
+ for (;pos<(int)a.size(); pos++) {
+ if (a[pos]!='(' && a[pos]!=' ' && a[pos]!='$') break;
+ }
+ for (; pos<(int)a.size(); pos++) {
+ if (a[pos]==')' || a[pos]=='$') return ret;
+ ret += a[pos];
+ }
+ return "";
+}
+
+inline bool compareKW(const string& a, int& pos, const string& kw) {
+ if (a.compare(pos+1,kw.size(),kw) == 0) {
+ pos += kw.size() ;
+ return true;
+ }
+ return false;
+}
+
+string replaceSet(const string& templ, const string table[]) {
+ vector<string> key, value;
+ for (int i=0;!table[i].empty();i+=2) {
+ key.push_back(table[i]);
+ value.push_back(table[i+1]);
+ }
+ vector<bool> conditionStack;
+ conditionStack.push_back(true);
+ stringstream s;
+ int elifs = 0;
+ for (int i=0; i<(int)templ.size(); i++) {
+ char c = templ[i];
+ if (c=='@') {
+ if (compareKW(templ,i,"IF")) {
+ string cond = getBracketArg(templ,i);
+ vector<string>::iterator it = find(key.begin(),key.end(),cond);
+ bool res = (it != key.end()) && (!value[it-key.begin()].empty());
+ conditionStack.push_back(res);
+ } else if (compareKW(templ,i,"ELIF")) {
+ conditionStack.back() = !conditionStack.back();
+ string cond = getBracketArg(templ,i);
+ vector<string>::iterator it = find(key.begin(),key.end(),cond);
+ bool res = (it != key.end()) && (!value[it-key.begin()].empty());
+ conditionStack.push_back(res);
+ elifs++;
+ } else if (compareKW(templ,i,"END")) {
+ for (int k=0; k<elifs+1; k++)
+ conditionStack.pop_back();
+ } else if (compareKW(templ,i,"ELSE")) {
+ conditionStack.back() = !conditionStack.back();
+ }
+ continue;
+ }
+ // check condition
+ bool valid = true;
+ for (int k=0; k<(int)conditionStack.size(); k++)
+ if (!conditionStack[k]) valid = false;
+ if (!valid) continue;
+
+ if (c=='$') {
+ string kw = getBracketArg(templ,i);
+ vector<string>::iterator it = find(key.begin(),key.end(),kw);
+ if (it == key.end())
+ s << '$' << kw << '$';
+ else
+ s << value[it - key.begin()];
+ continue;
+ }
+ s << templ[i];
+ }
+ return s.str();
+} \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/preprocessor/util.h b/source/blender/python/manta_full/source/preprocessor/util.h
new file mode 100644
index 00000000000..e7b13726b8a
--- /dev/null
+++ b/source/blender/python/manta_full/source/preprocessor/util.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Preprocessor Declarations
+ *
+ ******************************************************************************/
+
+#ifndef _P_UTIL_H
+#define _P_UTIL_H
+
+#include <string>
+#include <sstream>
+#include <vector>
+
+// warnings, errors
+void errMsg(int line, const std::string& text);
+
+// text tools
+void replaceAll(std::string& text, const std::string& pattern, const std::string& repl);
+std::string replaceSet(const std::string& templ, const std::string table[]);
+std::vector<std::string> split(const std::string& text, char sep);
+void stealLinebreaks(std::string& code, int num);
+std::string strip(const std::string& s);
+std::string makeSafe(const std::string& s);
+inline bool isNameChar(char c) {
+ return (c>='A' && c<='Z') || (c>='a' && c<='z') || (c>='0' && c<='9') || c=='_';
+}
+
+// file tools
+std::string readFile(const std::string&);
+bool fileExists(const std::string& name);
+void writeFile(const std::string& name, const std::string& text);
+
+struct Sink {
+ Sink(const std::string& infile,const std::string& outfile);
+ void write();
+
+ std::ostringstream inplace;
+ std::ostringstream link;
+ bool isHeader;
+ std::string infile;
+private:
+ std::string filename;
+};
+
+// simple string-based stack
+struct BracketStack {
+ bool empty() { return stack.empty(); }
+ char top() { return empty() ? '\0' : *(stack.rbegin()); }
+ void push_back(char c) { stack += c; }
+ char pop() { if (empty()) return '\0'; char c = *(stack.rbegin()); stack.erase(stack.end()-1); return c; }
+
+ std::string stack;
+};
+
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/pwrapper/manta.h b/source/blender/python/manta_full/source/pwrapper/manta.h
new file mode 100644
index 00000000000..87e5c95252d
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/manta.h
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Main
+ *
+ ******************************************************************************/
+
+#ifndef _MANTA_H
+#define _MANTA_H
+
+// Remove preprocessor keywords, so there won't infere with autocompletion etc.
+#define KERNEL
+#define PYTHON
+
+// Define plugin documentation group
+// all plugin functions and classes will automatically be added to this group
+//! @defgroup Plugins Plugins
+//! @defgroup PyClasses Classes exposed to Python
+
+#include "general.h"
+#include "vectorbase.h"
+#include "registry.h"
+#include "pclass.h"
+#include "pconvert.h"
+#include "fluidsolver.h"
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/pwrapper/manta_api.cpp b/source/blender/python/manta_full/source/pwrapper/manta_api.cpp
new file mode 100644
index 00000000000..c14e15472ef
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/manta_api.cpp
@@ -0,0 +1,27 @@
+#include "Python.h"
+//#include "manta_api.h"
+#include "manta.h"
+#include "../general.h"
+
+using namespace std;
+using namespace Manta;
+
+#if PY_MAJOR_VERSION >= 3
+typedef wchar_t pyChar;
+typedef wstring pyString;
+#else
+typedef char pyChar;
+typedef string pyString;
+#endif
+
+//#ifdef __cplusplus
+extern "C" {
+//#endif
+PyObject * PyInit_Manta(void)
+{
+ return Pb::PyInit_Main_Obj();
+}
+
+//#ifdef __cplusplus
+}
+//#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/pwrapper/manta_api.h b/source/blender/python/manta_full/source/pwrapper/manta_api.h
new file mode 100644
index 00000000000..3fbfe6f522c
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/manta_api.h
@@ -0,0 +1,6 @@
+#ifndef _MANTA_API_H_
+#define _MANTA_API_H_
+//#include "pythonInclude.h"
+PyObject * PyInit_Manta(void);
+PyMODINIT_FUNC PyInit_Main_Link(void);
+#endif
diff --git a/source/blender/python/manta_full/source/pwrapper/pclass.cpp b/source/blender/python/manta_full/source/pwrapper/pclass.cpp
new file mode 100644
index 00000000000..13a8240c609
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/pclass.cpp
@@ -0,0 +1,178 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Functions for property setting/getting via python
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include "structmember.h"
+#include "manta.h"
+#include "general.h"
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// Free functions
+
+#ifdef GUI
+ extern void updateQtGui(bool full, int frame, const std::string& curPlugin);
+#else
+ inline void updateQtGui(bool full, int frame, const std::string& curPlugin) {}
+#endif
+
+void pbPreparePlugin(FluidSolver* parent, const string& name) {
+ if (parent)
+ parent->pluginStart(name);
+}
+
+void pbFinalizePlugin(FluidSolver *parent, const string& name) {
+ if (parent) {
+ parent->pluginStop(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, msg.str() );
+
+ // name unnamed PbClass Objects from var name
+ PbClass::renameObjects();
+}
+
+void pbSetError(const string& fn, const string& ex) {
+ cout << "Error in " << fn << endl;
+ 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(), mParent(parent), mPyObject(obj), mName(name), mHidden(false)
+{
+}
+
+PbClass::PbClass(const PbClass& a) : mMutex(), mParent(a.mParent), mPyObject(0), mName("_unnamed"), mHidden(false)
+{
+}
+
+
+PbClass::~PbClass() {
+ for(vector<PbClass*>::iterator it = mInstances.begin(); it != mInstances.end(); ++it) {
+ if (*it == this) {
+ mInstances.erase(it);
+ break;
+ }
+ }
+}
+
+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;
+}
+
+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
diff --git a/source/blender/python/manta_full/source/pwrapper/pclass.h b/source/blender/python/manta_full/source/pwrapper/pclass.h
new file mode 100644
index 00000000000..418d0d8dfaf
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/pclass.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
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * 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>
+
+#ifdef GUI
+# include <QMutex>
+#else
+struct QMutex {
+ void lock() {};
+ void unlock() {};
+ bool tryLock() {return true;};
+};
+#endif
+
+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 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);
+void pbPreparePlugin(FluidSolver* parent, const std::string& name);
+void pbSetError(const std::string& fn, const std::string& ex);
+
+//!\endcond
+
+} // namespace
+
+#endif
+#endif
diff --git a/source/blender/python/manta_full/source/pwrapper/pconvert.cpp b/source/blender/python/manta_full/source/pwrapper/pconvert.cpp
new file mode 100644
index 00000000000..75ad14e60dc
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/pconvert.cpp
@@ -0,0 +1,422 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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;
+struct PbVec3 {
+ PyObject_HEAD
+ float data[3];
+};
+
+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<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<> 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<> 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<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;
+
+ // previous versions returned NULL for different parent solvers of args in the following two loops
+ // NULL pointer for solvers is not allowed anymore (unless explicitly specified with "noparent" keyword)
+ // thus, these checks are disabled for now - future version should also explicitly
+ // allow/disallow multiple solver parents...
+
+ 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();
+ //else if (solver != obj->getParent())
+ //return NULL;
+ }
+ }
+ 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();
+ //else if (solver != obj->getParent())
+ //return NULL;
+ }
+ }
+
+ // allow plugins without solver
+ if (!solver)
+ errMsg("Solver cannot be deduced from arguments, specify using argument 'solver=xxx'");
+ 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
diff --git a/source/blender/python/manta_full/source/pwrapper/pconvert.h b/source/blender/python/manta_full/source/pwrapper/pconvert.h
new file mode 100644
index 00000000000..7b8721254a5
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/pconvert.h
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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))
+ 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);
+
+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))
+ 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? (you shouldn't)");
+}
+
+// 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<> 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);
+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<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 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
+#endif
+#endif
diff --git a/source/blender/python/manta_full/source/pwrapper/pvec3.cpp b/source/blender/python/manta_full/source/pwrapper/pvec3.cpp
new file mode 100644
index 00000000000..0743fe6914b
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/pvec3.cpp
@@ -0,0 +1,286 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Vec3 class extension for python
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include <math.h>
+#include <string>
+#include <sstream>
+#include <limits>
+#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 {
+ 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));
+}
+
+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);
+}
+const static Pb::Register _REG(PbVecInitialize);
+
+} // namespace \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/pwrapper/pymain.cpp b/source/blender/python/manta_full/source/pwrapper/pymain.cpp
new file mode 100644
index 00000000000..5dc763daa63
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/pymain.cpp
@@ -0,0 +1,112 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Main file
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include <stdio.h>
+#include "manta.h"
+#include "general.h"
+#include "wchar.h"
+#include "pymain.h"
+
+namespace Manta {
+ extern void guiMain(int argc, char* argv[]);
+ extern void guiWaitFinish();
+}
+
+using namespace std;
+using namespace Manta;
+
+#if PY_MAJOR_VERSION >= 3
+typedef wchar_t pyChar;
+typedef wstring pyString;
+#else
+typedef char pyChar;
+typedef string pyString;
+#endif
+
+//*****************************************************************************
+// main...
+
+void runScript(vector<string>& args) {
+ string filename = args[0];
+
+ // Initialize extension classes and wrappers
+ srand(0);
+ Pb::setup(filename, args);
+
+ // Pass through the command line arguments
+ // for Py3k compatability, convert to wstring
+ vector<pyString> pyArgs(args.size());
+ const pyChar ** cargs = new const pyChar* [args.size()];
+ for (size_t i=0; i<args.size(); i++) {
+ pyArgs[i] = pyString(args[i].begin(), args[i].end());
+ cargs[i] = pyArgs[i].c_str();
+ }
+ PySys_SetArgv( args.size(), (pyChar**) cargs);
+
+ // Try to load python script
+ FILE* fp = fopen(filename.c_str(),"rb");
+ if (fp == NULL) {
+ debMsg("Cannot open '" << filename << "'", 0);
+ Pb::finalize();
+ return;
+ }
+
+ // Run the python script file
+ debMsg("Loading script '" << filename << "'", 0);
+#if defined(WIN32) || defined(_WIN32)
+ // known bug workaround: use simplestring
+ fseek(fp,0,SEEK_END);
+ long filelen=ftell(fp);
+ fseek(fp,0,SEEK_SET);
+ char* buf = new char[filelen+1];
+ fread(buf,filelen,1,fp);
+ buf[filelen] = '\0';
+ fclose(fp);
+ PyRun_SimpleString(buf);
+ delete[] buf;
+#else
+ // for linux, use this as it produces nicer error messages
+ PyRun_SimpleFileEx(fp, filename.c_str(), 1);
+ fclose(fp);
+#endif
+
+ debMsg("Script finished.", 0);
+#ifdef GUI
+ guiWaitFinish();
+#endif
+
+ // finalize
+ Pb::finalize();
+
+ delete [] cargs;
+}
+
+int manta_main(int argc,char* argv[]) {
+ debMsg("Version: "<< buildInfoString() , 1);
+
+#ifdef GUI
+ guiMain(argc, argv);
+#else
+ if (argc<=1) {
+ cerr << "Usage : Syntax is 'manta <config.py>'" << endl;
+ return 1;
+ }
+
+ vector<string> args;
+ for (int i=1; i<argc; i++) args.push_back(argv[i]);
+ runScript(args);
+#endif
+
+ return 0;
+}
diff --git a/source/blender/python/manta_full/source/pwrapper/pymain.h b/source/blender/python/manta_full/source/pwrapper/pymain.h
new file mode 100644
index 00000000000..50ee6f796be
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/pymain.h
@@ -0,0 +1,8 @@
+#ifndef _MY_PYMAIN_H_
+#define _MY_PYMAIN_H_
+#include <vector>
+#include <string>
+using namespace std;
+using namespace Manta;
+void runScript(vector<string>& args);
+#endif
diff --git a/source/blender/python/manta_full/source/pwrapper/pythonInclude.h b/source/blender/python/manta_full/source/pwrapper/pythonInclude.h
new file mode 100755
index 00000000000..127fb92449f
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/pythonInclude.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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>
+
+ #ifdef _DEBUG
+
+ // special handling for windows
+ // disable linking with debug version of python libs
+ #undef _DEBUG
+ #define NDEBUG
+ #include <Python.h>
+ #define _DEBUG
+ #undef NDEBUG
+
+ #else
+ #include <Python.h>
+ #endif
+#else
+ #include <Python.h>
+#endif
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/pwrapper/registry.cpp b/source/blender/python/manta_full/source/pwrapper/registry.cpp
new file mode 100644
index 00000000000..6eebc8c5e32
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/registry.cpp
@@ -0,0 +1,682 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Auto python registry
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include "structmember.h"
+#include "manta.h"
+
+using namespace std;
+
+const string gDefaultModuleName = "manta";
+
+namespace Pb {
+//PR FULL MANTA
+//******************************************************************************
+// 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 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 construct_lite();
+ void cleanup();
+ void renameObjects();
+ void runPreInit();
+ PyObject* initModule();
+ ClassData* lookup(const std::string& name);
+ bool canConvert(ClassData* from, ClassData* to);
+ void addScriptData(const std::string& scriptname, const vector<string>& args);
+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;
+};
+
+//******************************************************************************
+// 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) {
+ // don't delete top-level objects
+ if (self->instance->getParent() != self->instance)
+ delete self->instance;
+ }
+ 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) {
+#if PY_MAJOR_VERSION >= 3
+ WrapperRegistry::instance().construct_lite();
+ return WrapperRegistry::instance().initModule();
+#else
+ WrapperRegistry::instance().construct_lite();
+ WrapperRegistry::instance().initModule();
+#endif
+}
+
+PyMODINIT_FUNC PyInit_Main_Link(void) {
+#if PY_MAJOR_VERSION >= 3
+ return PyInit_Main();
+#else
+ PyInit_Main();
+#endif
+
+}
+
+PyObject *PyInit_Main_Obj(void)
+{
+ return PyInit_Main();
+}
+
+//******************************************************
+// 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::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,"CUDA",Manta::toPy(mScriptName));
+
+ // expose compile flags
+#ifdef CUDA
+ PyModule_AddObject(module,"CUDA",Manta::toPy<bool>(true));
+#else
+ PyModule_AddObject(module,"CUDA",Manta::toPy<bool>(false));
+#endif
+#ifdef DEBUG
+ PyModule_AddObject(module,"DEBUG",Manta::toPy<bool>(true));
+#else
+ PyModule_AddObject(module,"DEBUG",Manta::toPy<bool>(false));
+#endif
+#ifdef 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
+}
+
+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();
+
+ // load main extension module
+ PyImport_AppendInittab((char*)gDefaultModuleName.c_str(), PyInit_Main);
+}
+void WrapperRegistry::addScriptData(const std::string &scriptname, const vector<string> &args)
+{
+ mScriptName = scriptname;
+ this->args = args;
+}
+
+void WrapperRegistry::construct_lite() {
+ registerBaseclasses();
+ registerMeta();
+ registerDummyTypes();
+}
+
+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().addScriptData(filename, args);
+ 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& file, const string& pythonCode) {
+ WrapperRegistry::instance().addPythonCode(file, pythonCode);
+}
+Register::Register(InitFunc func) {
+ WrapperRegistry::instance().addExternalInitializer(func);
+}
+
+} // namespace \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/pwrapper/registry.h b/source/blender/python/manta_full/source/pwrapper/registry.h
new file mode 100644
index 00000000000..4be636b01a4
--- /dev/null
+++ b/source/blender/python/manta_full/source/pwrapper/registry.h
@@ -0,0 +1,87 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * 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;
+}
+
+// **************************************************
+// 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 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);
+
+// callback type
+typedef void (*InitFunc)(PyObject*);
+PyObject *PyInit_Main_Obj(void);
+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 python code
+ Register(const std::string& file, const std::string& pythonCode);
+ //! register external code
+ Register(InitFunc func);
+};
+
+}
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/python/defines.py b/source/blender/python/manta_full/source/python/defines.py
new file mode 100644
index 00000000000..6bf5ee0ef57
--- /dev/null
+++ b/source/blender/python/manta_full/source/python/defines.py
@@ -0,0 +1,27 @@
+################################################################################
+#
+# 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
+#
+# Defines some constants for use in python subprograms
+#
+#################################################################################
+
+# mantaflow conventions
+Real = float
+
+# grid flags
+FlagFluid = 1
+FlagObstacle = 2
+FlagEmpty = 4
+FlagStick = 128
+FlagReserved = 256
+
+# integration mode
+IntEuler = 0
+IntRK2 = 1
+IntRK4 = 2
diff --git a/source/blender/python/manta_full/source/shapes.cpp b/source/blender/python/manta_full/source/shapes.cpp
new file mode 100644
index 00000000000..eaba1f3fda0
--- /dev/null
+++ b/source/blender/python/manta_full/source/shapes.cpp
@@ -0,0 +1,381 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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
+KERNEL template<class T>
+void ApplyShapeToGrid (Grid<T>* grid, Shape* shape, T value, FlagGrid* respectFlags) {
+ if (respectFlags && respectFlags->isObstacle(i,j,k))
+ return;
+ if (shape->isInsideGrid(i,j,k))
+ (*grid)(i,j,k) = value;
+}
+
+//! Kernel: Apply a shape to a grid, setting value inside (scaling by SDF value)
+KERNEL template<class T>
+void ApplyShapeToGridSmooth (Grid<T>* grid, Grid<Real>& phi, Real sigma, Real shift, T value, FlagGrid* respectFlags) {
+ 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));
+}
+
+//! Kernel: Apply a shape to a MAC grid, setting value inside
+KERNEL void ApplyShapeToMACGrid (MACGrid* grid, Shape* shape, Vec3 value, FlagGrid* respectFlags)
+{
+ 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;
+}
+
+void Shape::applyToGrid(GridBase* grid, FlagGrid* respectFlags) {
+ 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");
+}
+
+void Shape::applyToGridSmooth(GridBase* grid, Real sigma, Real shift, FlagGrid* respectFlags) {
+ Grid<Real> phi(grid->getParent());
+ generateLevelset(phi);
+
+ 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");
+}
+
+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
+KERNEL void BoxSDF(Grid<Real>& phi, const Vec3& p1, const Vec3& p2) {
+ 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);
+ 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;
+ }
+}
+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);
+}
+
+KERNEL void SphereSDF(Grid<Real>& phi, Vec3 center, Real radius, Vec3 scale) {
+ phi(i,j,k) = norm((Vec3(i+0.5,j+0.5,k+0.5)-center)/scale)-radius;
+}
+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);
+}
+
+KERNEL void
+CylinderSDF(Grid<Real>& phi, Vec3 center, Real radius, Vec3 zaxis, Real maxz) {
+ 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));
+ }
+}
+void Cylinder::generateLevelset(Grid<Real>& phi) {
+ CylinderSDF(phi, mCenter, mRadius, mZDir, mZ);
+}
+
+} //namespace
diff --git a/source/blender/python/manta_full/source/shapes.h b/source/blender/python/manta_full/source/shapes.h
new file mode 100644
index 00000000000..0f5ac32dcae
--- /dev/null
+++ b/source/blender/python/manta_full/source/shapes.h
@@ -0,0 +1,130 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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
+PYTHON class Shape : public PbClass {
+public:
+ enum GridType { TypeNone = 0, TypeBox = 1, TypeSphere = 2, TypeCylinder };
+
+ PYTHON Shape(FluidSolver* parent);
+
+ //! Get the type of grid
+ inline GridType getType() const { return mType; }
+
+ //! Apply shape to flag grid, set inside cells to <value>
+ PYTHON void applyToGrid(GridBase* grid, FlagGrid* respectFlags=0);
+ PYTHON void applyToGridSmooth(GridBase* grid, Real sigma=1.0, Real shift=0, FlagGrid* respectFlags=0);
+ PYTHON LevelsetGrid computeLevelset();
+ PYTHON void collideMesh(Mesh& mesh);
+ PYTHON virtual Vec3 getCenter() const { return Vec3::Zero; }
+ PYTHON virtual void setCenter(const Vec3& center) {}
+ PYTHON virtual Vec3 getExtent() const { return Vec3::Zero; }
+
+ //! 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;
+};
+
+//! Dummy shape
+PYTHON class NullShape : public Shape {
+public:
+ PYTHON NullShape (FluidSolver* parent) : Shape(parent) {}
+
+ 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 ); }
+};
+
+//! Box shape
+PYTHON class Box : public Shape {
+public:
+ PYTHON Box(FluidSolver* parent, Vec3 center = Vec3::Invalid, Vec3 p0 = Vec3::Invalid, Vec3 p1 = Vec3::Invalid, Vec3 size = Vec3::Invalid);
+
+ 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;
+};
+
+//! Spherical shape
+PYTHON class Sphere : public Shape {
+public:
+ PYTHON Sphere (FluidSolver* parent, Vec3 center, Real radius, Vec3 scale=Vec3(1,1,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;
+};
+
+//! Cylindrical shape
+PYTHON class Cylinder : public Shape {
+public:
+ PYTHON Cylinder (FluidSolver* parent, Vec3 center, Real radius, Vec3 z);
+
+ PYTHON void setRadius(Real r) { mRadius = r; }
+ PYTHON void setZ(Vec3 z) { mZDir=z; mZ=normalize(mZDir); }
+
+ 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;
+};
+
+
+
+} //namespace
+#endif
diff --git a/source/blender/python/manta_full/source/test.cpp b/source/blender/python/manta_full/source/test.cpp
new file mode 100644
index 00000000000..c08c8b2fdac
--- /dev/null
+++ b/source/blender/python/manta_full/source/test.cpp
@@ -0,0 +1,151 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Use this file to test new functionality
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include <cmath>
+
+using namespace std;
+
+namespace Manta {
+
+
+PYTHON template<class S>
+void addToGrid(Grid<S>& a, S v) {
+ FOR_IDX(a) a[idx] += v;
+}
+PYTHON instantiate addToGrid<int>, addToGrid<Real>, addToGrid<Vec3>;
+
+//! Kernel: get component (not shifted)
+/*KERNEL(idx) returns(Grid<Real> ret(parent))
+Grid<Real> GetComponent2(const Grid<Vec3>& grid, int dim) {
+ ret[idx] = grid[idx][dim];
+};
+
+PYTHON void testp(Grid<Vec3>& b) {
+ Grid<Real> d(b.getParent());
+ b(20,20,20) = Vec3(21,22,23);
+ {
+ cout <<"middle" << endl;
+ Grid<Real> a = GetComponent2(b,0);
+ cout << a(20,20,20) << endl;
+ cout <<"middle" << endl;
+ }
+ cout << "end" << endl;errMsg("f");
+}
+*/
+
+KERNEL(idx, reduce=+) returns (double sum=0)
+double ddtest(const Grid<Real>& v)
+{
+ sum += v[idx];
+}
+
+KERNEL(idx, reduce=min) returns (double sum=0)
+double detest(const Grid<Real>& v)
+{
+ if (sum < v[idx])
+ sum = v[idx];
+}
+
+PYTHON void checkGrids(Grid<int>& flags1, Grid<int>& flags2, Grid<Real>& phi1, Grid<Real>& phi2, Grid<Vec3>& vel1, Grid<Vec3>& vel2) {
+ FOR_IJK(flags1) {
+ assertMsg(flags1(i,j,k) == flags2(i,j,k), "flags mismatch");
+ assertMsg(norm(vel1(i,j,k)-vel2(i,j,k)) < 1e-1, "vel mismatch");
+ assertMsg( fabs(phi1(i,j,k)-phi2(i,j,k)) < 1e-4, "phi mismatch");
+ }
+}
+
+
+struct myvec {
+ myvec(int n) : x(n) { cout << "constructor" << endl; };
+ myvec(const myvec& a) : x(a.x) { cout << "copy constructor" << endl; }
+ myvec& operator=(const myvec& a) { x=a.x; cout << "copy operator" << endl; return *this;}
+ int& operator[](int idx) { return x[idx]; }
+
+ vector<int> x;
+};
+
+KERNEL(pts) returns(myvec vec(size))
+myvec testy(vector<int>& a) {
+ vec[idx] = a[idx];
+}
+
+PYTHON void kernelTest() {
+ cout << "kernel test" << endl;
+ vector<int> a(10);
+ for (int i=0;i<10;i++) a[i]=i;
+
+ //testy xx(a);
+ myvec b = testy(a);
+ for (int i=0;i<10;i++) cout << b[i] << endl;
+ cout << "kernel end" << endl;
+}
+
+PYTHON void getCurl(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);
+}
+
+PYTHON void setinflow(FlagGrid& flags, MACGrid& vel, LevelsetGrid& phi, Real h) {
+ FOR_IJK(vel) {
+ if (i<=2) {
+ if (j < h*flags.getSizeY()) {
+ vel(i,j,k).x = 1;
+ if (!flags.isObstacle(i,j,k)) {
+ flags(i,j,k) = 1;
+ phi(i,j,k) = -1;
+ }
+ } else {
+ vel(i,j,k).x = 0;
+ if (!flags.isObstacle(i,j,k)) {
+ flags(i,j,k) = 4;
+ phi(i,j,k) = 1;
+ }
+ }
+ }
+ else if (i>=flags.getSizeX()-2) {
+ vel(i,j,k).x = 1;
+ /*if (j < 30-12) {
+ vel(i,j,k).x = 1;
+ if (!flags.isObstacle(i,j,k)) {
+ flags(i,j,k) = 1;
+ phi(i,j,k) = -1;
+ }
+ } else {
+ vel(i,j,k).x = 0;
+ if (!flags.isObstacle(i,j,k)) {
+ flags(i,j,k) = 4;
+ phi(i,j,k) = 1;
+ }
+ }*/
+ }
+ }
+}
+
+PYTHON void testDiscardNth (BasicParticleSystem& parts, int skip=1) {
+ //knSetPdataConst<Real>(pd,value);
+ for(int i=0; i<parts.size(); ++i) {
+ if(i%(skip+1) == skip) { // keep
+ } else {
+ parts.setPos(i, Vec3(-100000) );
+ }
+ }
+}
+
+} //namespace
+
diff --git a/source/blender/python/manta_full/source/turbulencepart.cpp b/source/blender/python/manta_full/source/turbulencepart.cpp
new file mode 100644
index 00000000000..5a9bf7c7bfe
--- /dev/null
+++ b/source/blender/python/manta_full/source/turbulencepart.cpp
@@ -0,0 +1,141 @@
+/******************************************************************************
+ *
+ * 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.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;
+ }
+}
+
+
+KERNEL(pts)
+void KnSynthesizeTurbulence(TurbulenceParticleSystem& p, FlagGrid& flags, WaveletNoiseField& noise, Grid<Real>& kGrid,
+ Real alpha, Real dt, int octaves, Real scale, Real invL0, Real kmin) {
+ 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;
+ }
+}
+
+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
diff --git a/source/blender/python/manta_full/source/turbulencepart.h b/source/blender/python/manta_full/source/turbulencepart.h
new file mode 100644
index 00000000000..2e5542e97b1
--- /dev/null
+++ b/source/blender/python/manta_full/source/turbulencepart.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Turbulence particles
+ *
+ ******************************************************************************/
+
+#ifndef _TURBULENCEPART_H_
+#define _TURBULENCEPART_H_
+
+#include "particle.h"
+#include "noisefield.h"
+
+namespace Manta {
+class Shape;
+
+
+
+struct TurbulenceParticleData {
+ TurbulenceParticleData() : pos(_0),color(1.),tex0(_0),tex1(_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
+PYTHON class TurbulenceParticleSystem : public ParticleSystem<TurbulenceParticleData> {
+public:
+ PYTHON TurbulenceParticleSystem(FluidSolver* parent, WaveletNoiseField& noise);
+
+ PYTHON void resetTexCoords(int num, const Vec3& inflow);
+ PYTHON void seed(Shape* source, int num);
+ PYTHON 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);
+ PYTHON void deleteInObstacle(FlagGrid& flags);
+
+ virtual ParticleBase* clone();
+
+private:
+ WaveletNoiseField& noise;
+};
+
+} // namespace
+
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/util/integrator.h b/source/blender/python/manta_full/source/util/integrator.h
new file mode 100644
index 00000000000..378a890c0ab
--- /dev/null
+++ b/source/blender/python/manta_full/source/util/integrator.h
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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 + (_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
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/util/interpol.h b/source/blender/python/manta_full/source/util/interpol.h
new file mode 100644
index 00000000000..073df798ffa
--- /dev/null
+++ b/source/blender/python/manta_full/source/util/interpol.h
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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, int idx) {
+ if (idx<0 || idx > 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
+ int idx = xi + Y * yi + 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
+ int idx = xi + Y * yi + 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
+ int idx = xi + Y * yi + 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*size.y+yi)*size.x+xi));
+ DEBUG_ONLY(checkIndexInterpol(size,(s_zi*size.y+s_yi)*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*size.y+yi)*size.x+xi));
+ DEBUG_ONLY(checkIndexInterpol(size,(s_zi*size.y+s_yi)*size.x+s_xi+X+Y+Z));
+
+ // process individual components
+ { // X
+ const int idx = (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 int idx = (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 int idx = (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
+
+#endif
diff --git a/source/blender/python/manta_full/source/util/interpolHigh.h b/source/blender/python/manta_full/source/util/interpolHigh.h
new file mode 100644
index 00000000000..6778e5f7d27
--- /dev/null
+++ b/source/blender/python/manta_full/source/util/interpolHigh.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Helper functions for higher order interpolation
+ *
+ ******************************************************************************/
+
+#ifndef _INTERPOLHIGH_H
+#define _INTERPOLHIGH_H
+
+#include "vectorbase.h"
+
+namespace Manta {
+
+// copied from interpol.h
+#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 interpolCubic(const T* data, const Vec3i& size, const int Z, const Vec3& pos) {
+ BUILD_INDEX
+ int idx = xi + Y * yi + 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;
+}
+
+#undef BUILD_INDEX
+
+} //namespace
+
+#endif
+
+
diff --git a/source/blender/python/manta_full/source/util/mcubes.h b/source/blender/python/manta_full/source/util/mcubes.h
new file mode 100644
index 00000000000..39bd5970791
--- /dev/null
+++ b/source/blender/python/manta_full/source/util/mcubes.h
@@ -0,0 +1,323 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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/source/blender/python/manta_full/source/util/quaternion.h b/source/blender/python/manta_full/source/util/quaternion.h
new file mode 100644
index 00000000000..1808bb582a6
--- /dev/null
+++ b/source/blender/python/manta_full/source/util/quaternion.h
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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
+
+#endif
diff --git a/source/blender/python/manta_full/source/util/randomstream.h b/source/blender/python/manta_full/source/util/randomstream.h
new file mode 100644
index 00000000000..23380a4c10f
--- /dev/null
+++ b/source/blender/python/manta_full/source/util/randomstream.h
@@ -0,0 +1,377 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Random numbers
+ *
+ * Based on GPL code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
+ * Richard J. Wagner v0.5 7 November 2000 rjwagner@writeme.com
+ *
+ ******************************************************************************/
+
+#ifndef _RANDOMSTREAM_H
+#define _RANDOMSTREAM_H
+
+namespace Manta {
+
+#include <iostream>
+#include <limits.h>
+#include <stdio.h>
+#include <time.h>
+#include <math.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;
+
+ register 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;
+ register int i = 1;
+ register uint32 j = 0;
+ register 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];
+ register uint32 *s = bigSeed;
+ register int i = N;
+ register 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.
+ register uint32 *s = state;
+ register uint32 *r = state;
+ register 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)
+ register uint32 *p = state;
+ register 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
+{
+ register uint32 *sa = saveArray;
+ register const uint32 *s = state;
+ register int i = N;
+ for( ; i--; *sa++ = *s++ ) {}
+ *sa = left;
+}
+
+
+inline void MTRand::load( uint32 *const loadArray )
+{
+ register uint32 *s = state;
+ register uint32 *la = loadArray;
+ register int i = N;
+ for( ; i--; *s++ = *la++ ) {}
+ left = *la;
+ pNext = &state[N-left];
+}
+
+
+inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )
+{
+ register const MTRand::uint32 *s = mtrand.state;
+ register int i = mtrand.N;
+ for( ; i--; os << *s++ << "\t" ) {}
+ return os << mtrand.left;
+}
+
+
+inline std::istream& operator>>( std::istream& is, MTRand& mtrand )
+{
+ register MTRand::uint32 *s = mtrand.state;
+ register 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
+
+#endif
diff --git a/source/blender/python/manta_full/source/util/solvana.h b/source/blender/python/manta_full/source/util/solvana.h
new file mode 100644
index 00000000000..c9c8167bceb
--- /dev/null
+++ b/source/blender/python/manta_full/source/util/solvana.h
@@ -0,0 +1,176 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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/source/blender/python/manta_full/source/util/vectorbase.cpp b/source/blender/python/manta_full/source/util/vectorbase.cpp
new file mode 100644
index 00000000000..5f7dee46f59
--- /dev/null
+++ b/source/blender/python/manta_full/source/util/vectorbase.cpp
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Basic vector class
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include <limits>
+#include <math.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<> const Vector3D<int> Vector3D<int>::Invalid( -1, -1, -1 );
+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); }
+//template<> bool Vector3D<int>::isValid() const { return x!=-1 || y!=-1 || z!=-1; }
+
+
+
+
+} \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/util/vectorbase.h b/source/blender/python/manta_full/source/util/vectorbase.h
new file mode 100644
index 00000000000..9fca17703ba
--- /dev/null
+++ b/source/blender/python/manta_full/source/util/vectorbase.h
@@ -0,0 +1,585 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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 <stdlib.h>
+#include <string>
+#include <cmath>
+#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 FP_REAL_MAX __FLT_MAX__
+# define VECTOR_EPSILON (1e-6f)
+# define _0 0.0f
+# define _1 1.0f
+#else
+ typedef double Real;
+# define FP_REAL_MAX __DBL_MAX__
+# define VECTOR_EPSILON (1e-10)
+# define _0 0.0
+# define _1 1.0
+#endif
+
+// windos, 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
+# 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 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;
+
+protected:
+
+};
+
+//************************************************************************
+// 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
+//************************************************************************
+
+//! 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
+template<class S>
+inline S norm ( const Vector3D<S>& v ) {
+ S l = v.x*v.x + v.y*v.y + v.z*v.z;
+ 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;
+}
+
+//! 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 );
+}
+
+//! 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
+
+
+#endif
diff --git a/source/blender/python/manta_full/source/vortexfilament.cpp b/source/blender/python/manta_full/source/vortexfilament.cpp
new file mode 100644
index 00000000000..77d467313cd
--- /dev/null
+++ b/source/blender/python/manta_full/source/vortexfilament.cpp
@@ -0,0 +1,340 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Vortex filament
+ *
+ ******************************************************************************/
+
+#include "vortexfilament.h"
+#include "integrator.h"
+#include "interpol.h"
+#include "mesh.h"
+#include "quaternion.h"
+
+using namespace std;
+namespace Manta {
+
+void VortexRing::renumber(int *_renumber) {
+ for (size_t i=0; i<indices.size(); i++)
+ indices[i] = _renumber[indices[i]];
+}
+
+inline Vec3 FilamentKernel(const Vec3& pos, const vector<VortexRing>& rings, const vector<BasicParticleData>& fp, Real reg, Real cutoff, Real scale) {
+ const Real strength = 0.25 / M_PI * scale;
+ const Real a2 = square(reg);
+ const Real cutoff2 = square(cutoff);
+ const Real mindist = 1e-6;
+ Vec3 u(_0);
+
+ for (size_t i=0; i<rings.size(); i++) {
+ const VortexRing& r = rings[i];
+ if (r.flag & ParticleBase::PDELETE) continue;
+
+ const int N = r.isClosed ? (r.size()) : (r.size()-1);
+ const Real str = strength * r.circulation;
+ for (int j=0; j<N; j++) {
+ const Vec3 r0 = fp[r.idx0(j)].pos - pos;
+ const Vec3 r1 = fp[r.idx1(j)].pos - pos;
+ const Real r0_2 = normSquare(r0), r1_2 = normSquare(r1);
+ if (r0_2 > cutoff2 || r1_2 > cutoff2 || r0_2 < mindist || r1_2 < mindist)
+ continue;
+
+ const Vec3 e = getNormalized(r1-r0);
+ const Real r0n = 1.0f/sqrt(a2+r0_2);
+ const Real r1n = 1.0f/sqrt(a2+r1_2);
+ const Vec3 cp = cross(r0,e);
+ const Real A = str * (dot(r1,e)*r1n - dot(r0,e)*r0n) / (a2 + normSquare(cp));
+ u += A * cp;
+ }
+ }
+ return u;
+}
+
+KERNEL(pts) returns(vector<Vec3> u(size))
+vector<Vec3> KnFilamentAdvectParts(vector<BasicParticleData>& nodes, vector<BasicParticleData>& fp, const vector<VortexRing>& rings, Real reg, Real cutoff, Real scale) {
+ if (nodes[idx].flag & ParticleBase::PDELETE)
+ u[idx] = _0;
+ else
+ u[idx] = FilamentKernel(nodes[idx].pos, rings, fp, reg, cutoff, scale);
+}
+
+KERNEL(pts) returns(vector<Vec3> u(size))
+vector<Vec3> KnFilamentAdvectMesh(vector<Node>& nodes, const vector<VortexRing>& rings, const vector<BasicParticleData>& fp, Real reg, Real cutoff, Real scale) {
+ if (nodes[idx].flags & Mesh::NfFixed)
+ u[idx] = _0;
+ else
+ u[idx] = FilamentKernel(nodes[idx].pos, rings, fp, reg, cutoff, scale);
+}
+
+void VortexFilamentSystem::advectSelf(Real scale, Real regularization, int integrationMode) {
+ KnFilamentAdvectParts kernel(mData, mData, mSegments , regularization, 1e10, scale * getParent()->getDt());
+ integratePointSet( kernel, integrationMode);
+}
+
+void VortexFilamentSystem::advectMesh(Mesh& mesh, Real scale, Real regularization, int integrationMode) {
+ KnFilamentAdvectMesh kernel(mesh.getNodeData(), mSegments, mData, regularization, 1e10, scale * getParent()->getDt());
+ integratePointSet( kernel, integrationMode);
+}
+
+void VortexFilamentSystem::advectParticles(BasicParticleSystem& sys, Real scale, Real regularization, int integrationMode) {
+ KnFilamentAdvectParts kernel(sys.getData(), mData, mSegments, regularization, 1e10, scale * getParent()->getDt());
+ integratePointSet( kernel, integrationMode);
+}
+
+void VortexFilamentSystem::remesh(Real maxLen, Real minLen) {
+ const Real maxLen2 = maxLen*maxLen, minLen2 = minLen*minLen;
+
+ for (int i=0; i < segSize(); i++) {
+ VortexRing& r = mSegments[i];
+
+ // insert edges
+ for(;;) {
+ const int oldLen = r.size();
+ map<int,int> insert;
+ int offset = 1;
+
+ for (int j=0; j<oldLen; j++) {
+ const Vec3 p0 = mData[r.idx0(j)].pos;
+ const Vec3 p1 = mData[r.idx1(j)].pos;
+ const Real l2 = normSquare(p1-p0);
+
+ if (l2 > maxLen2) {
+ // insert midpoint
+ const Vec3 p_1 = mData[r.idx(j-1)].pos;
+ const Vec3 p2 = mData[r.idx(j+2)].pos;
+ const Vec3 mp = hermiteSpline(p0,p1,crTangent(p_1,p0,p1),crTangent(p0,p1,p2), 0.5);
+ insert.insert(pair<int,int>(j+offset, add(mp)));
+ offset++;
+ }
+ }
+ if (insert.empty())
+ break;
+
+ // renumber indices
+ const int newLen = oldLen + insert.size();
+ int num=oldLen-1;
+ r.indices.resize(newLen);
+ for (int j=newLen-1; j>=0; j--) {
+ map<int,int>::const_iterator f = insert.find(j);
+ if (f==insert.end())
+ r.indices[j] = r.indices[num--];
+ else
+ r.indices[j] = f->second;
+ }
+ }
+
+ // remove edges
+ for(;;) {
+ const int oldLen = r.size();
+ const int N = r.isClosed ? oldLen : (oldLen-1);
+ std::vector<bool> deleted(r.size());
+
+ int newLen=oldLen;
+ for (int j=0; j<N; j++) {
+ if (mData[r.idx0(j)].flag & PDELETE || mData[r.idx1(j)].flag & PDELETE) continue;
+ const Vec3 p0 = mData[r.idx0(j)].pos;
+ const Vec3 p1 = mData[r.idx1(j)].pos;
+ const Real l2 = normSquare(p1-p0);
+
+ if (l2 < minLen2) {
+ // kill edge
+ mData[r.idx0(j)].flag |= PDELETE;
+ mData[r.idx1(j)].pos = 0.5*(p0+p1);
+ deleted[j] = true;
+ newLen--;
+ j++;
+ }
+ }
+ if (newLen == oldLen)
+ break;
+
+ // renumber indices
+ for (int j=0, copyFrom=0; j<newLen; j++,copyFrom++) {
+ while (deleted[copyFrom])
+ copyFrom++;
+ if (j!=copyFrom)
+ r.indices[j] = r.indices[copyFrom];
+ }
+ r.indices.resize(newLen);
+ }
+ }
+
+ // remove deleted particles
+ compress();
+}
+
+VortexFilamentSystem::VortexFilamentSystem(FluidSolver* parent) :
+ ConnectedParticleSystem<BasicParticleData, VortexRing>(parent)
+{
+}
+
+ParticleBase* VortexFilamentSystem::clone() {
+ VortexFilamentSystem* nm = new VortexFilamentSystem(getParent());
+ compress();
+
+ nm->mData = mData;
+ nm->mSegments = mSegments;
+ nm->setName(getName());
+ return nm;
+}
+
+// ------------------------------------------------------------------------------
+// Functions needed for doubly-discrete smoke flow using Darboux transforms
+// see [Weissmann,Pinkall 2009]
+// doesn't really work yet (can't reverse rotation dir)
+// ------------------------------------------------------------------------------
+
+Real evaluateRefU(int N, Real L, Real circ, Real reg) {
+ // construct regular n-polygon
+ const Real l = L/(Real)N;
+ const Real r = 0.5*l/sin(M_PI/(Real)N);
+ cout << r << " " << l << endl;
+ // build vortex ring
+ VortexRing ring (circ);
+ vector<BasicParticleData> pos(N);
+ for(int i=0; i<N; i++) {
+ pos[i].pos = Vec3( r*cos(2.0*M_PI*(Real)i/N), r*sin(2.0*M_PI*(Real)i/N), 0);
+ pos[i].flag =0;
+ ring.indices.push_back(i);
+ }
+
+ // Build kernel
+ vector<VortexRing> rings;
+ rings.push_back(ring);
+
+ // evaluate impact on pos[0]
+ return norm(FilamentKernel(pos[0].pos, rings, pos, reg, 1e10, 1.0));
+}
+
+Vec3 darbouxStep(const Vec3& Si, const Vec3& lTi, Real r) {
+ Quaternion rlTS (lTi - Si, -r);
+ Quaternion lT (lTi, 0);
+ Quaternion lTnext = rlTS * lT * rlTS.inverse();
+ return lTnext.imag();
+}
+
+Vec3 monodromy(const vector<Vec3>& gamma, const Vec3& lT_1, Real r) {
+ const int N = gamma.size();
+ Vec3 lT (lT_1);
+
+ for (int i=0; i<N; i++) {
+ Vec3 Si = gamma[(i+1)%N]-gamma[i];
+ lT = darbouxStep(Si, lT, r);
+ }
+ return lT;
+}
+
+bool powerMethod(const vector<Vec3>& gamma, Real l, Real r, Vec3& lT) {
+ const int maxIter = 100;
+ const Real epsilon = 1e-4;
+
+ for (int i=0; i<maxIter; i++) {
+ Vec3 lastLT (lT);
+ lT = monodromy(gamma, lT, r);
+ //if ((i%1) == 0) cout << "iteration " << i << " residual: " << norm(lT-lastLT) << endl;
+ if (norm(lT-lastLT) < epsilon)
+ return true;
+ }
+ return false;
+}
+
+bool darboux(const vector<Vec3>& from, vector<Vec3>& to, Real l, Real r) {
+ const int N = from.size();
+ Vec3 lT(0,0,l);
+ if (!powerMethod(from, l, r, lT))
+ return false;
+ cout << "iniLT " << lT << " norm " << lT/l<< endl;
+
+ for (int i=0; i<N; i++) {
+ to[i] = from[i] + lT;
+ Vec3 Si = from[(i+1)%N] - from[i];
+ lT = darbouxStep(Si, lT, r);
+ }
+ return true;
+}
+
+
+void VortexFilamentSystem::doublyDiscreteUpdate(Real reg) {
+ const Real dt = getParent()->getDt();
+
+ for (int rc=0; rc<segSize(); rc++) {
+ if (!isSegActive(rc) || !mSegments[rc].isClosed) continue;
+
+ VortexRing& r = mSegments[rc];
+ int N = r.size();
+
+ // compute arc length
+ Real L=0;
+ for (int i=0; i<N; i++)
+ L += norm(mData[r.idx0(i)].pos - mData[r.idx1(i)].pos);
+
+ // build gamma
+ vector<Vec3> gamma(N);
+ for (int i=0; i<N; i++) gamma[i] = mData[r.indices[i]].pos;
+
+ //N=1000; L=2.0*M_PI; reg=0.1; r.circulation=1;
+
+ // compute reference parameters
+ const Real U = 0.5*r.circulation/L * (log(4.0*L/(M_PI*reg)) - 1.0);
+ const Real Ur = evaluateRefU(N, L, r.circulation, reg);
+ const Real d = 0.5*dt*(U-Ur);
+ const Real l = sqrt( square(L/N) + square(d) );
+ const Real ra = d*tan(M_PI * (0.5 - 1.0/N)); // d*cot(pi/n)
+ cout << U << " <-< " << Ur << endl;
+
+ // fwd darboux transform
+ vector<Vec3> eta(N);
+ if (!darboux(gamma, eta, l, ra)) {
+ cout << "Fwd Darboux correction failed, skipped." << endl;
+ continue;
+ }
+
+ // bwd darboux transform
+ if (!darboux(eta, gamma, l, ra)) {
+ cout << "Bwd Darboux correction failed, skipped." << endl;
+ continue;
+ }
+
+ // copy back
+ for (int i=0; i<N; i++) {
+ mData[r.indices[i]].pos = gamma[i];
+ }
+ }
+}
+
+void VortexFilamentSystem::addLine(const Vec3& p0, const Vec3& p1, Real circulation) {
+ VortexRing ring(circulation, false);
+
+ ring.indices.push_back(add(BasicParticleData(p0)));
+ ring.indices.push_back(add(BasicParticleData(p1)));
+ mSegments.push_back(ring);
+}
+
+void VortexFilamentSystem::addRing(const Vec3& position, Real circulation, Real radius, Vec3 normal, int number) {
+ normalize(normal);
+ Vec3 worldup (0,1,0);
+ if (norm(normal - worldup) < 1e-5) worldup = Vec3(1,0,0);
+
+ Vec3 u = cross(normal, worldup); normalize(u);
+ Vec3 v = cross(normal, u); normalize(v);
+
+ VortexRing ring(circulation, true);
+
+ for (int i=0; i<number; i++) {
+ Real phi = (Real)i/(Real)number * M_PI * 2.0;
+ Vec3 p = position + radius * (u*cos(phi) + v*sin(phi));
+
+ int num = add(BasicParticleData(p));
+ ring.indices.push_back(num);
+ }
+ mSegments.push_back(ring);
+}
+
+
+} // namespace
diff --git a/source/blender/python/manta_full/source/vortexfilament.h b/source/blender/python/manta_full/source/vortexfilament.h
new file mode 100644
index 00000000000..08faf338897
--- /dev/null
+++ b/source/blender/python/manta_full/source/vortexfilament.h
@@ -0,0 +1,72 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Vortex filament
+ *
+ ******************************************************************************/
+
+#ifndef _VORTEXFIL_H
+#define _VORTEXFIL_H
+
+#include "particle.h"
+
+namespace Manta {
+class Mesh;
+
+struct VortexRing {
+ VortexRing() : isClosed(false),circulation(0.),flag(0) {}
+ VortexRing(Real c, bool closed=false) : isClosed(closed),circulation(c),flag(0) {}
+ void renumber(int* _renumber);
+ inline int size() const { return indices.size(); }
+ inline int idx(int i) const { return indices[(i+indices.size()) % indices.size()]; }
+ inline int idx0(int i) const { return indices[i]; }
+ inline int idx1(int i) const { return indices[ (i+1) % indices.size() ]; }
+
+ Real circulation;
+ bool isClosed;
+ int flag;
+ std::vector<int> indices;
+};
+
+//! Vortex filaments
+PYTHON class VortexFilamentSystem : public ConnectedParticleSystem<BasicParticleData, VortexRing> {
+public:
+ virtual SystemType getType() const { return ParticleBase::FILAMENT; };
+
+ PYTHON VortexFilamentSystem(FluidSolver* parent);
+
+ //! self-advect the filament system
+ PYTHON void advectSelf(Real scale=1.0, Real regularization=0.1, int integrationMode=IntRK4);
+ //! advect a particle system
+ PYTHON void advectParticles(BasicParticleSystem& sys, Real scale=1.0, Real regularization=0.1, int integrationMode=IntRK2);
+ //! advect triangle mesh using filaments
+ PYTHON void advectMesh(Mesh& mesh, Real scale=1.0, Real regularization=0.1, int integrationMode=IntRK4);
+ //! perform doubly-discrete smoke ring flow update
+ //! as in [Weissmann,Pinkall 2009]
+ PYTHON void doublyDiscreteUpdate(Real regularization=0.1);
+ //! remesh long or strongly-curved segments
+ PYTHON void remesh(Real maxLen=3.0, Real minLen=1.0);
+
+ //! add a filament ring to the system
+ PYTHON void addRing(const Vec3& position, Real circulation, Real radius, Vec3 normal, int number);
+ //! add a line filament to the system
+ PYTHON void addLine(const Vec3& p0, const Vec3& p1, Real circulation);
+
+
+ virtual ParticleBase* clone();
+protected:
+
+ //! Biot-Savart line integration
+ void integrate(const std::vector<Vec3>& nodesOld, std::vector<Vec3>& nodesNew, Real scale, Real reg, int integrationMode);
+};
+
+} // namespace
+
+
+#endif
diff --git a/source/blender/python/manta_full/source/vortexpart.cpp b/source/blender/python/manta_full/source/vortexpart.cpp
new file mode 100644
index 00000000000..2b297e9f337
--- /dev/null
+++ b/source/blender/python/manta_full/source/vortexpart.cpp
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Vortex particles
+ *
+ ******************************************************************************/
+
+#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);
+ 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;
+}
+
+KERNEL(pts) returns(vector<Vec3> u(size))
+vector<Vec3> KnVpAdvectMesh(vector<Node>& nodes, const vector<VortexParticleData>& vp, Real scale) {
+ if (nodes[idx].flags & Mesh::NfFixed)
+ u[idx] = _0;
+ else
+ u[idx] = VortexKernel(nodes[idx].pos, vp, scale);
+}
+
+KERNEL(pts) returns(vector<Vec3> u(size))
+vector<Vec3> KnVpAdvectSelf(vector<VortexParticleData>& vp, Real scale) {
+ if (vp[idx].flag & ParticleBase::PDELETE)
+ u[idx] = _0;
+ else
+ u[idx] = VortexKernel(vp[idx].pos, vp, scale);
+}
+
+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
diff --git a/source/blender/python/manta_full/source/vortexpart.h b/source/blender/python/manta_full/source/vortexpart.h
new file mode 100644
index 00000000000..c81c1a8f26c
--- /dev/null
+++ b/source/blender/python/manta_full/source/vortexpart.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Vortex particles
+ *
+ ******************************************************************************/
+
+#ifndef _VORTEXPART_H
+#define _VORTEXPART_H
+
+#include "particle.h"
+
+namespace Manta {
+class Mesh;
+
+struct VortexParticleData {
+ VortexParticleData() : pos(_0),vorticity(_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
+PYTHON class VortexParticleSystem : public ParticleSystem<VortexParticleData> {
+public:
+ PYTHON VortexParticleSystem(FluidSolver* parent);
+
+ PYTHON void advectSelf(Real scale=1.0, int integrationMode=IntRK4);
+ PYTHON void applyToMesh(Mesh& mesh, Real scale=1.0, int integrationMode=IntRK4);
+
+ virtual ParticleBase* clone();
+};
+
+} // namespace
+
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_full/source/vortexsheet.cpp b/source/blender/python/manta_full/source/vortexsheet.cpp
new file mode 100644
index 00000000000..dc753e87ff5
--- /dev/null
+++ b/source/blender/python/manta_full/source/vortexsheet.cpp
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Vortex sheets
+ *
+ ******************************************************************************/
+
+#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
diff --git a/source/blender/python/manta_full/source/vortexsheet.h b/source/blender/python/manta_full/source/vortexsheet.h
new file mode 100644
index 00000000000..29dd6b7b887
--- /dev/null
+++ b/source/blender/python/manta_full/source/vortexsheet.h
@@ -0,0 +1,87 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Vortex sheets
+ *
+ ******************************************************************************/
+
+#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
+PYTHON class VortexSheetMesh : public Mesh {
+public:
+ PYTHON VortexSheetMesh(FluidSolver* parent);
+ 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();
+
+ PYTHON void calcCirculation();
+ PYTHON void calcVorticity();
+ PYTHON void reinitTexCoords();
+
+protected:
+ Vec3 mTexOffset;
+ VorticityChannel mVorticity;
+ TexCoord3Channel mTex1, mTex2;
+ TurbulenceChannel mTurb;
+};
+
+}; // namespace
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_pp/CMakeLists.txt b/source/blender/python/manta_pp/CMakeLists.txt
new file mode 100644
index 00000000000..73027c8aa8c
--- /dev/null
+++ b/source/blender/python/manta_pp/CMakeLists.txt
@@ -0,0 +1,137 @@
+#add_definitions(-DGUI=1)
+
+set(INC
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/python
+ ${CMAKE_CURRENT_SOURCE_DIR}/plugin
+ ${CMAKE_CURRENT_SOURCE_DIR}/pwrapper
+ ${CMAKE_CURRENT_SOURCE_DIR}/util
+ #gui
+)
+
+set(INC_SYS
+ ${ZLIB_INCLUDE_DIRS}
+ ${PYTHON_INCLUDE_DIRS}
+)
+
+#message("MANTA_processing ${CMAKE_CURRENT_SOURCE_DIR}/commonkernels.h")
+set(SRC
+#PP SOURCES and HEADERS
+${CMAKE_CURRENT_SOURCE_DIR}/commonkernels.h
+${CMAKE_CURRENT_SOURCE_DIR}/commonkernels.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/commonkernels.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/conjugategrad.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/conjugategrad.h
+${CMAKE_CURRENT_SOURCE_DIR}/conjugategrad.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/conjugategrad.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/edgecollapse.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/edgecollapse.h
+${CMAKE_CURRENT_SOURCE_DIR}/edgecollapse.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/edgecollapse.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/fastmarch.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/fastmarch.h
+${CMAKE_CURRENT_SOURCE_DIR}/fastmarch.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/fastmarch.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/fileio.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/fileio.h
+${CMAKE_CURRENT_SOURCE_DIR}/fileio.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/fileio.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/fluidsolver.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/fluidsolver.h
+${CMAKE_CURRENT_SOURCE_DIR}/fluidsolver.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/fluidsolver.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/general.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/general.h
+${CMAKE_CURRENT_SOURCE_DIR}/general.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/general.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/grid.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/grid.h
+${CMAKE_CURRENT_SOURCE_DIR}/grid.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/grid.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/hginfo.h
+${CMAKE_CURRENT_SOURCE_DIR}/kernel.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/kernel.h
+${CMAKE_CURRENT_SOURCE_DIR}/kernel.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/kernel.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/levelset.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/levelset.h
+${CMAKE_CURRENT_SOURCE_DIR}/levelset.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/levelset.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/mesh.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/mesh.h
+${CMAKE_CURRENT_SOURCE_DIR}/mesh.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/mesh.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/movingobs.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/movingobs.h
+${CMAKE_CURRENT_SOURCE_DIR}/movingobs.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/movingobs.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/noisefield.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/noisefield.h
+${CMAKE_CURRENT_SOURCE_DIR}/noisefield.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/noisefield.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/particle.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/particle.h
+${CMAKE_CURRENT_SOURCE_DIR}/particle.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/particle.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/plugin/advection.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/plugin/extforces.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/plugin/flip.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/plugin/initplugins.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/plugin/kepsilon.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/plugin/meshplugins.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/plugin/pressure.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/plugin/vortexplugins.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/plugin/waveletturbulence.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/plugin/waves.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/python/defines.py
+${CMAKE_CURRENT_SOURCE_DIR}/python/defines.py.reg
+${CMAKE_CURRENT_SOURCE_DIR}/python/defines.py.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/shapes.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/shapes.h
+${CMAKE_CURRENT_SOURCE_DIR}/shapes.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/shapes.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/test.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/timing.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/timing.h
+${CMAKE_CURRENT_SOURCE_DIR}/timing.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/timing.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/turbulencepart.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/turbulencepart.h
+${CMAKE_CURRENT_SOURCE_DIR}/turbulencepart.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/turbulencepart.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/vortexpart.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/vortexpart.h
+${CMAKE_CURRENT_SOURCE_DIR}/vortexpart.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/vortexpart.h.reg.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/vortexsheet.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/vortexsheet.h
+${CMAKE_CURRENT_SOURCE_DIR}/vortexsheet.h.reg
+${CMAKE_CURRENT_SOURCE_DIR}/vortexsheet.h.reg.cpp
+
+${CMAKE_CURRENT_SOURCE_DIR}/pwrapper/pymain.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/pwrapper/pclass.h
+${CMAKE_CURRENT_SOURCE_DIR}/pwrapper/pclass.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/pwrapper/pvec3.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/pwrapper/pconvert.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/pwrapper/pconvert.h
+${CMAKE_CURRENT_SOURCE_DIR}/pwrapper/registry.h
+${CMAKE_CURRENT_SOURCE_DIR}/pwrapper/registry.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/pwrapper/pythonInclude.h
+${CMAKE_CURRENT_SOURCE_DIR}/pwrapper/manta_api.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/pwrapper/manta.h
+${CMAKE_CURRENT_SOURCE_DIR}/pwrapper/manta_api.h
+${CMAKE_CURRENT_SOURCE_DIR}/util/vectorbase.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/util/integrator.h
+${CMAKE_CURRENT_SOURCE_DIR}/util/vectorbase.h
+${CMAKE_CURRENT_SOURCE_DIR}/util/vectorbase.cpp
+${CMAKE_CURRENT_SOURCE_DIR}/util/quaternion.h
+${CMAKE_CURRENT_SOURCE_DIR}/util/interpol.h
+${CMAKE_CURRENT_SOURCE_DIR}/util/interpolHigh.h
+${CMAKE_CURRENT_SOURCE_DIR}/util/mcubes.h
+${CMAKE_CURRENT_SOURCE_DIR}/util/randomstream.h
+${CMAKE_CURRENT_SOURCE_DIR}/util/solvana.h
+)
+list(REMOVE_DUPLICATES "SRC")
+list_assert_duplicates("${SRC}")
+
+blender_add_lib(bf_python_manta "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/python/manta_pp/commonkernels.h b/source/blender/python/manta_pp/commonkernels.h
new file mode 100644
index 00000000000..3d0e7a5d5ff
--- /dev/null
+++ b/source/blender/python/manta_pp/commonkernels.h
@@ -0,0 +1,140 @@
+
+
+
+
+
+// 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
+ *
+ * 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(FlagGrid& flags, Grid<Real>& grid) : KernelBase(&flags,0) ,flags(flags),grid(grid) { run(); } inline void op(int idx, FlagGrid& flags, Grid<Real>& grid ) {
+ if (flags.isFluid(idx) && grid[idx] > 0)
+ grid[idx] = 1.0 / grid[idx];
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Real>& getArg1() { return grid; } typedef Grid<Real> type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, flags,grid); } FlagGrid& flags; Grid<Real>& grid; };
+
+//! Kernel: Squared sum over grid
+
+ struct GridSumSqr : public KernelBase { GridSumSqr(Grid<Real>& grid) : KernelBase(&grid,0) ,grid(grid) ,sum(0) { run(); } inline void op(int idx, Grid<Real>& grid ,double& sum) {
+ sum += square((double)grid[idx]);
+} inline operator double () { return sum; } inline double & getRet() { return sum; } inline Grid<Real>& getArg0() { return grid; } typedef Grid<Real> type0; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, grid,sum); } 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) { run(); } inline void op(int i, int j, int k, const Grid<Vec3>& grid, Grid<Vec3>& dst ) {
+ 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, grid,dst); } 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) { run(); } inline void op(int i, int j, int k, Grid<Real>& div, const MACGrid& grid ) {
+ 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, div,grid); } 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) { run(); } inline void op(int i, int j, int k, MACGrid& gradient, const Grid<Real>& grid ) {
+ 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, gradient,grid); } 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) { run(); } inline void op(int i, int j, int k, Grid<Vec3>& gradient, const Grid<Real>& grid ) {
+ 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, gradient,grid); } 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) { run(); } inline void op(int i, int j, int k, Grid<Real>& laplace, const Grid<Real>& grid ) {
+ laplace(i,j,k) = -(6.0*grid(i,j,k)-grid(i+1,j,k)-grid(i-1,j,k)-grid(i,j+1,k)-grid(i,j-1,k)-grid(i,j,k+1)-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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, laplace,grid); } Grid<Real>& laplace; const Grid<Real>& grid; };
+
+//! 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) { run(); } inline void op(int i, int j, int k, const Grid<Vec3>& grid, Grid<Real>& comp, int dim ) {
+ 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, grid,comp,dim); } 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) { run(); } inline void op(int idx, const Grid<Vec3>& grid, Grid<Real>& comp, int dim ) {
+ 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, grid,comp,dim); } 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) { run(); } inline void op(int idx, Grid<Real>& n, const Grid<Vec3>& grid ) {
+ 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, n,grid); } 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) { run(); } inline void op(int idx, Grid<Vec3>& grid, const Grid<Real>& comp, int dim ) {
+ 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, grid,comp,dim); } 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) { run(); } inline void op(int i, int j, int k, Grid<Vec3>& center, const MACGrid& vel ) {
+ 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, center,vel); } 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) { run(); } inline void op(int i, int j, int k, MACGrid& vel, const Grid<Vec3>& center ) {
+ 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, vel,center); } 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) { run(); } inline void op(int i, int j, int k, Grid<Vec3>& grid, int g ) {
+ 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 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, grid,g); } Grid<Vec3>& grid; int g; };
+
+} // namespace
+#endif
+
diff --git a/source/blender/python/manta_pp/commonkernels.h.reg b/source/blender/python/manta_pp/commonkernels.h.reg
new file mode 100644
index 00000000000..2609f03504f
--- /dev/null
+++ b/source/blender/python/manta_pp/commonkernels.h.reg
@@ -0,0 +1 @@
+#include "commonkernels.h"
diff --git a/source/blender/python/manta_pp/commonkernels.h.reg.cpp b/source/blender/python/manta_pp/commonkernels.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/commonkernels.h.reg.cpp
diff --git a/source/blender/python/manta_pp/conjugategrad.cpp b/source/blender/python/manta_pp/conjugategrad.cpp
new file mode 100644
index 00000000000..95caa18b63c
--- /dev/null
+++ b/source/blender/python/manta_pp/conjugategrad.cpp
@@ -0,0 +1,316 @@
+
+
+
+
+
+// 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
+ *
+ * Conjugate gradient solver
+ *
+ ******************************************************************************/
+
+#include "conjugategrad.h"
+#include "commonkernels.h"
+
+using namespace std;
+namespace Manta {
+
+const int CG_DEBUGLEVEL = 4;
+
+//*****************************************************************************
+// Precondition helpers
+
+//! Preconditioning a la Wavelet Turbulence (needs 4 add. grids)
+void InitPreconditionIncompCholesky(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 int 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(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 );
+ }
+};
+
+//! Apply WT-style ICP
+void ApplyPreconditionIncompCholesky(Grid<Real>& dst, Grid<Real>& Var1, 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 int 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, 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 int 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);
+ }
+}
+
+
+//*****************************************************************************
+// 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) { run(); } inline void op(int 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, a,b,result); } const Grid<Real>& a; const Grid<Real>& b; double result; };;
+
+//! Kernel: compute residual (init) and add to sigma
+
+
+ struct InitSigma : public KernelBase { InitSigma(FlagGrid& flags, Grid<Real>& dst, Grid<Real>& rhs, Grid<Real>& temp) : KernelBase(&flags,0) ,flags(flags),dst(dst),rhs(rhs),temp(temp) ,sigma(0) { run(); } inline void op(int idx, 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 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, flags,dst,rhs,temp,sigma); } 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) { run(); } inline void op(int idx, Grid<Real>& dst, Grid<Real>& src, Real factor ) {
+ 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, dst,src,factor); } 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, 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(pA0), mpPCAi(pAi), mpPCAj(pAj), mpPCAk(pAk), mSigma(0.), mAccuracy(VECTOR_EPSILON), mResNorm(1e20)
+{
+ dst.clear();
+ residual.clear();
+ search.clear();
+ tmp.clear();
+}
+
+template<class APPLYMAT>
+void GridCg<APPLYMAT>::doInit() {
+ mInited = true;
+
+ 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 {
+ 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
+ mTmp.copyFrom( mResidual );
+
+ // compute norm of the residual?
+ if(this->mUseResNorm) {
+ mResNorm = GridSumSqr(mResidual).sum;
+ } else {
+ mResNorm = mResidual.getMaxAbsValue();
+ }
+ //if(mIterations % 10 == 9) debMsg("GridCg::Iteration i="<<mIterations<<", resNorm="<<mResNorm<<" accuracy="<<mAccuracy, 1);
+
+ // 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("PB-Cg::iter i="<<mIterations<<" sigmaNew="<<sigmaNew<<" sigmaLast="<<mSigma<<" alpha="<<alpha<<" beta="<<beta<<" ", CG_DEBUGLEVEL);
+ mSigma = sigmaNew;
+
+ //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>::setPreconditioner(PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak) {
+ mPcMethod = method;
+ if( (!A0->is3D()) && (mPcMethod!=PC_None) ) {
+ if(gPrint2dWarning) {
+ debMsg("Pre-conditioning only supported in 3D for now, disabling it.", 1);
+ gPrint2dWarning = false;
+ }
+ mPcMethod=PC_None;
+ }
+ mpPCA0 = A0;
+ mpPCAi = Ai;
+ mpPCAj = Aj;
+ mpPCAk = Ak;
+}
+
+// explicit instantiation
+template class GridCg<ApplyMatrix>;
+template class GridCg<ApplyMatrix2D>;
+
+}; // DDF
+
+
diff --git a/source/blender/python/manta_pp/conjugategrad.h b/source/blender/python/manta_pp/conjugategrad.h
new file mode 100644
index 00000000000..ccf5983e808
--- /dev/null
+++ b/source/blender/python/manta_pp/conjugategrad.h
@@ -0,0 +1,181 @@
+
+
+
+
+
+// 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
+ *
+ * Conjugate gradient solver
+ *
+ ******************************************************************************/
+
+#ifndef _CONJUGATEGRADIENT_H
+#define _CONJUGATEGRADIENT_H
+
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+
+namespace Manta {
+
+static const bool CG_DEBUG = false;
+
+//! Basic CG interface
+class GridCgInterface {
+ public:
+ enum PreconditionType { PC_None=0, PC_ICP, PC_mICP };
+
+ GridCgInterface() : mUseResNorm(true) {};
+ virtual ~GridCgInterface() {};
+
+ // solving functions
+ virtual bool iterate() = 0;
+ virtual void solve(int maxIter) = 0;
+
+ // precond
+ virtual void setPreconditioner(PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak) = 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;
+
+ void setUseResNorm(bool set) { mUseResNorm = set; }
+
+ protected:
+
+ // use norm of residual, or max value for threshold?
+ bool mUseResNorm;
+};
+
+
+//! 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, 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 setPreconditioner(PreconditionType method, Grid<Real> *A0, Grid<Real> *Ai, Grid<Real> *Aj, Grid<Real> *Ak);
+
+ // 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;
+ FlagGrid& mFlags;
+ Grid<Real>& mTmp;
+
+ Grid<Real> *mpA0, *mpAi, *mpAj, *mpAk;
+
+ PreconditionType mPcMethod;
+ //! preconditioning grids
+ Grid<Real> *mpPCA0, *mpPCAi, *mpPCAj, *mpPCAk;
+
+ //! 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(FlagGrid& flags, Grid<Real>& dst, 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) { run(); } inline void op(int idx, FlagGrid& flags, Grid<Real>& dst, Grid<Real>& src, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak ) {
+ 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 FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Real>& getArg1() { return dst; } typedef Grid<Real> type1;inline 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, flags,dst,src,A0,Ai,Aj,Ak); } FlagGrid& flags; Grid<Real>& dst; 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(FlagGrid& flags, Grid<Real>& dst, 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) { run(); } inline void op(int idx, FlagGrid& flags, Grid<Real>& dst, Grid<Real>& src, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak ) {
+ 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 FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Real>& getArg1() { return dst; } typedef Grid<Real> type1;inline 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, flags,dst,src,A0,Ai,Aj,Ak); } FlagGrid& flags; Grid<Real>& dst; 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(FlagGrid& flags, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak) : KernelBase(&flags,1) ,flags(flags),A0(A0),Ai(Ai),Aj(Aj),Ak(Ak) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak ) {
+ if (!flags.isFluid(i,j,k))
+ return;
+
+ // center
+ 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.;
+
+ 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.;
+} inline 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; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, flags,A0,Ai,Aj,Ak); } FlagGrid& flags; Grid<Real>& A0; Grid<Real>& Ai; Grid<Real>& Aj; Grid<Real>& Ak; };
+
+
+
+
+} // namespace
+
+#endif
+
diff --git a/source/blender/python/manta_pp/conjugategrad.h.reg b/source/blender/python/manta_pp/conjugategrad.h.reg
new file mode 100644
index 00000000000..90e55a88da4
--- /dev/null
+++ b/source/blender/python/manta_pp/conjugategrad.h.reg
@@ -0,0 +1 @@
+#include "conjugategrad.h"
diff --git a/source/blender/python/manta_pp/conjugategrad.h.reg.cpp b/source/blender/python/manta_pp/conjugategrad.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/conjugategrad.h.reg.cpp
diff --git a/source/blender/python/manta_pp/edgecollapse.cpp b/source/blender/python/manta_pp/edgecollapse.cpp
new file mode 100644
index 00000000000..683349b5343
--- /dev/null
+++ b/source/blender/python/manta_pp/edgecollapse.cpp
@@ -0,0 +1,678 @@
+
+
+
+
+
+// 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
+ *
+ * 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) throw Error("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) throw Error("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)
+ throw Error("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
+
diff --git a/source/blender/python/manta_pp/edgecollapse.h b/source/blender/python/manta_pp/edgecollapse.h
new file mode 100644
index 00000000000..70710a1346a
--- /dev/null
+++ b/source/blender/python/manta_pp/edgecollapse.h
@@ -0,0 +1,48 @@
+
+
+
+
+
+// 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
+ *
+ * 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);
+
+}
+
+#endif
+
diff --git a/source/blender/python/manta_pp/edgecollapse.h.reg b/source/blender/python/manta_pp/edgecollapse.h.reg
new file mode 100644
index 00000000000..9869b6a5c7d
--- /dev/null
+++ b/source/blender/python/manta_pp/edgecollapse.h.reg
@@ -0,0 +1 @@
+#include "edgecollapse.h"
diff --git a/source/blender/python/manta_pp/edgecollapse.h.reg.cpp b/source/blender/python/manta_pp/edgecollapse.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/edgecollapse.h.reg.cpp
diff --git a/source/blender/python/manta_pp/fastmarch.cpp b/source/blender/python/manta_pp/fastmarch.cpp
new file mode 100644
index 00000000000..66612edb7ed
--- /dev/null
+++ b/source/blender/python/manta_pp/fastmarch.cpp
@@ -0,0 +1,438 @@
+
+
+
+
+
+// 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
+ *
+ * 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(FlagGrid& flags, Grid<int>& fmFlags, LevelsetGrid& levelset, Real maxTime,
+ MACGrid* velTransport, Grid<Real>* velMag )
+ : mLevelset(levelset), mFlags(flags), mFmFlags(fmFlags)
+{
+ if (velTransport)
+ mVelTransport.initMarching(velTransport, &flags);
+ if (velMag)
+ mMagTransport.initMarching(velMag, &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:
+ throw Error("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 int 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;
+
+ if (mVelTransport.isInitialized())
+ mVelTransport.transpTouch(p.x, p.y, p.z, mWeights, ttime);
+ if (mMagTransport.isInitialized())
+ mMagTransport.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(LevelsetGrid& phi) : KernelBase(&phi,0) ,phi(phi) { run(); } inline void op(int i, int j, int k, LevelsetGrid& 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 LevelsetGrid& getArg0() { return phi; } typedef LevelsetGrid type0; 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); } LevelsetGrid& 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) { run(); } inline void op(int i, int j, int k, MACGrid& vel, int distance , Grid<int>& tmp , const int d , const int c ) {
+ 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, vel,distance,tmp,d,c); } MACGrid& vel; int distance; Grid<int>& tmp; const int d; const int c; };
+
+
+ struct knExtrapolateIntoBnd : public KernelBase { knExtrapolateIntoBnd(FlagGrid& flags, MACGrid& vel) : KernelBase(&flags,0) ,flags(flags),vel(vel) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel ) {
+ int c=0;
+ Vec3 v(0,0,0);
+ if( i==0 ) {
+ v = vel(i+1,j,k);
+ if(v[0] < 0.) v[0] = 0.;
+ c++;
+ }
+ else if( i==(flags.getSizeX()-1) ) {
+ v = vel(i-1,j,k);
+ if(v[0] > 0.) v[0] = 0.;
+ c++;
+ }
+ if( j==0 ) {
+ v = vel(i,j+1,k);
+ if(v[1] < 0.) v[1] = 0.;
+ c++;
+ }
+ else if( j==(flags.getSizeY()-1) ) {
+ v = vel(i,j-1,k);
+ if(v[1] > 0.) v[1] = 0.;
+ c++;
+ }
+ if(flags.is3D()) {
+ if( k==0 ) {
+ v = vel(i,j,k+1);
+ if(v[2] < 0.) v[2] = 0.;
+ c++;
+ }
+ else if( k==(flags.getSizeY()-1) ) {
+ v = vel(i,j,k-1);
+ if(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; 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,vel); } FlagGrid& flags; MACGrid& vel; };
+
+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, LevelsetGrid& phi, Real maxDist) : KernelBase(&flags,1) ,flags(flags),vel(vel),phi(phi),maxDist(maxDist) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, LevelsetGrid& phi, Real maxDist ) {
+ // 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 LevelsetGrid& getArg2() { return phi; } typedef LevelsetGrid type2;inline Real& getArg3() { return maxDist; } typedef Real type3; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, flags,vel,phi,maxDist); } FlagGrid& flags; MACGrid& vel; LevelsetGrid& phi; Real maxDist; };
+// a simple extrapolation step , used for cases where there's no levelset
+// (note, less accurate than fast marching extrapolation!)
+
+void extrapolateMACSimple(FlagGrid& flags, MACGrid& vel, int distance = 4, LevelsetGrid* phiObs=NULL ) {
+ 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
+ FOR_IJK_BND(flags,1) {
+ Vec3i p(i,j,k);
+ if (flags.isFluid(p) || flags.isFluid(p-dir) ) {
+ tmp(p) = 1;
+ }
+ }
+
+ // debug init! , enable for testing only - set varying velocities inside
+ //FOR_IJK_BND(flags,1) { if (tmp(i,j,k) == 0) continue; vel(i,j,k)[c] = (i+j+k+c+1.)*0.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
+ knExtrapolateIntoBnd(flags, vel);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "extrapolateMACSimple" ); 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); _retval = getPyNone(); extrapolateMACSimple(flags,vel,distance,phiObs); _args.check(); } pbFinalizePlugin(parent,"extrapolateMACSimple" ); return _retval; } catch(std::exception& e) { pbSetError("extrapolateMACSimple",e.what()); return 0; } } static const Pb::Register _RP_extrapolateMACSimple ("","extrapolateMACSimple",_W_0);
+
+
+
+ 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) { run(); } inline void op(int i, int j, int k, MACGrid& vel, Grid<Vec3>& weight, int distance , const int d, const int c ) {
+ 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, vel,weight,distance,d,c); } 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(); pbPreparePlugin(parent, "extrapolateMACFromWeight" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("extrapolateMACFromWeight",e.what()); return 0; } } static const Pb::Register _RP_extrapolateMACFromWeight ("","extrapolateMACFromWeight",_W_1);
+
+} // namespace
+
+
diff --git a/source/blender/python/manta_pp/fastmarch.h b/source/blender/python/manta_pp/fastmarch.h
new file mode 100644
index 00000000000..9e8cf22c8c5
--- /dev/null
+++ b/source/blender/python/manta_pp/fastmarch.h
@@ -0,0 +1,197 @@
+
+
+
+
+
+// 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
+ *
+ * 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, 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;
+ 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(FlagGrid& flags, Grid<int>& fmFlags, LevelsetGrid& levelset, Real maxTime,
+ MACGrid* velTransport = NULL, Grid<Real>* velMag = 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:
+ LevelsetGrid& mLevelset;
+ FlagGrid& mFlags;
+ Grid<int>& mFmFlags;
+
+ //! velocity extrpolation
+ FmValueTransportVec3<MACGrid , Vec3> mVelTransport;
+ FmValueTransportScalar<Grid<Real>, Real> mMagTransport;
+
+ //! 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
+#endif
+
+
+
diff --git a/source/blender/python/manta_pp/fastmarch.h.reg b/source/blender/python/manta_pp/fastmarch.h.reg
new file mode 100644
index 00000000000..7b9296f3580
--- /dev/null
+++ b/source/blender/python/manta_pp/fastmarch.h.reg
@@ -0,0 +1 @@
+#include "fastmarch.h"
diff --git a/source/blender/python/manta_pp/fastmarch.h.reg.cpp b/source/blender/python/manta_pp/fastmarch.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/fastmarch.h.reg.cpp
diff --git a/source/blender/python/manta_pp/fileio.cpp b/source/blender/python/manta_pp/fileio.cpp
new file mode 100644
index 00000000000..fbc9d7adf97
--- /dev/null
+++ b/source/blender/python/manta_pp/fileio.cpp
@@ -0,0 +1,771 @@
+
+
+
+
+
+// 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
+ *
+ * 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 "fileio.h"
+#include "grid.h"
+#include "mesh.h"
+#include "vortexsheet.h"
+#include "particle.h"
+#include <cstring>
+
+using namespace std;
+
+namespace Manta {
+
+//*****************************************************************************
+// 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();
+ 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, ignore
+ } 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();
+}
+
+void writeObjFile(const string& name, Mesh* mesh) {
+ errMsg("obj exporter not yet implemented");
+}
+
+//*****************************************************************************
+// 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("can't open file!");
+ 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("can't open file");
+ 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("can't open file");
+
+ int bytes = sizeof(T)*grid->getSizeX()*grid->getSizeY()*grid->getSizeZ();
+ int 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;
+
+//! uni file header
+typedef struct {
+ int dimX, dimY, dimZ; // grid size
+ int gridType, elementType, bytesPerElement; // data type info
+ char info[256]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+} UniHeader;
+
+//! for test run debugging
+void printUniFileInfoString(const string& name) {
+# 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);
+ if (!strcmp(ID, "MNT2")) {
+ UniHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader), "can't read file, no header present");
+ gzclose(gzf);
+ debMsg("File '"<<name<<"' info: "<< head.info ,1);
+ return; // all good!
+ }
+ gzclose(gzf);
+ }
+# endif
+ debMsg("File '"<<name<<"', no valid info string found",1);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "printUniFileInfoString" ); PyObject *_retval = 0; { ArgLocker _lock; const string& name = _args.get<string >("name",0,&_lock); _retval = getPyNone(); printUniFileInfoString(name); _args.check(); } pbFinalizePlugin(parent,"printUniFileInfoString" ); return _retval; } catch(std::exception& e) { pbSetError("printUniFileInfoString",e.what()); return 0; } } static const Pb::Register _RP_printUniFileInfoString ("","printUniFileInfoString",_W_0);
+
+//! for auto-init & check of results of test runs
+Vec3 getUniFileSize(const string& name) {
+ Vec3 s(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);
+ if (!strcmp(ID, "MNT2")) {
+ UniHeader head;
+ assertMsg (gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader), "can't read file, no header present");
+ s = Vec3(head.dimX,head.dimY,head.dimZ);
+ }
+ gzclose(gzf);
+ }
+# endif
+ return s;
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "getUniFileSize" ); PyObject *_retval = 0; { ArgLocker _lock; const string& name = _args.get<string >("name",0,&_lock); _retval = toPy(getUniFileSize(name)); _args.check(); } pbFinalizePlugin(parent,"getUniFileSize" ); return _retval; } catch(std::exception& e) { pbSetError("getUniFileSize",e.what()); return 0; } } static const Pb::Register _RP_getUniFileSize ("","getUniFileSize",_W_1);
+
+#if NO_ZLIB!=1
+template <class T>
+void convertDoubleAndWrite(Grid<T>& grid, void* ptr, gzFile& gzf, UniHeader& head) {
+ errMsg("unknown type, not yet supported");
+}
+
+template <>
+void convertDoubleAndWrite(Grid<int>& grid, void* ptr, gzFile& gzf, UniHeader& head) {
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, ptr, sizeof(int)*head.dimX*head.dimY*head.dimZ);
+}
+
+template <>
+void convertDoubleAndWrite(Grid<double>& grid, void* ptr, gzFile& gzf, 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 convertDoubleAndWrite(Grid<Vector3D<double> >& grid, void* ptr, gzFile& gzf, 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(float)*3 *head.dimX*head.dimY*head.dimZ);
+}
+#endif // NO_ZLIB!=1
+
+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] = "MNT2";
+ UniHeader head;
+ head.dimX = grid->getSizeX();
+ head.dimY = grid->getSizeY();
+ head.dimZ = grid->getSizeZ();
+ head.gridType = grid->getType();
+ head.bytesPerElement = sizeof(T);
+ snprintf( head.info, 256, "%s", buildInfoString().c_str() );
+ MuTime stamp; stamp.get();
+ 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("unknown element type");
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file");
+
+ gzwrite(gzf, ID, 4);
+ void* ptr = &((*grid)[0]);
+# 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)
+ //ptr = &(temp[0]);
+ //float* ptrf = (float*)ptr;
+ convertDoubleAndWrite( *grid, &(temp[0]), gzf, head);
+# endif
+ gzwrite(gzf, &head, sizeof(UniHeader));
+ gzwrite(gzf, ptr, sizeof(T)*head.dimX*head.dimY*head.dimZ);
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+// grid conversion functions for double precision
+template <class T>
+void convertFloatGridToDouble(Grid<T>& grid, void* ptr, int bytesPerElement) {
+ errMsg("unknown type, not yet supported");
+}
+
+template <>
+void convertFloatGridToDouble<int>(Grid<int>& grid, void* ptr, int bytesPerElement) {
+ 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 convertFloatGridToDouble<double>(Grid<double>& grid, void* ptr, int bytesPerElement) {
+ 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 convertFloatGridToDouble<Vec3>(Grid<Vec3>& grid, void* ptr, int bytesPerElement) {
+ 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;
+ }
+}
+
+// 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;
+}
+
+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("can't open file");
+
+ 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")) {
+ // 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]);
+ gzread(gzf, ptr, sizeof(T)*head.dimX*head.dimY*head.dimZ);
+ convertFloatGridToDouble<T>(*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
+ }
+ 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("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("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);
+};
+
+
+//*****************************************************************************
+// particle data
+//*****************************************************************************
+
+//! in line with grid uni 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[256]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+} UniPartHeader;
+
+template <class T>
+void writeParticlesUni(const std::string& name, 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 = sizeof(T);
+ head.elementType = 0; // 0 for base data
+ snprintf( head.info, 256, "%s", buildInfoString().c_str() );
+ MuTime stamp; stamp.get();
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file");
+
+ gzwrite(gzf, ID, 4);
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &(parts->getData()[0]), sizeof(T)*head.dim);
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+};
+
+template <class T>
+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");
+
+ 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 == sizeof(T)) && (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");
+ int bytes = sizeof(T)*head.dim;
+ int readBytes = gzread(gzf, &(parts->getData()[0]), sizeof(T)*head.dim);
+ assertMsg(bytes==readBytes, "can't read uni file, stream length does not match, "<<bytes<<" vs "<<readBytes );
+
+ 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();
+ head.bytesPerElement = sizeof(T);
+ head.elementType = 1; // 1 for particle data, todo - add sub types?
+ snprintf( head.info, 256, "%s", buildInfoString().c_str() );
+ MuTime stamp; stamp.get();
+ head.timestamp = stamp.time;
+
+ gzFile gzf = gzopen(name.c_str(), "wb1"); // do some compression
+ if (!gzf) errMsg("can't open file");
+
+ gzwrite(gzf, ID, 4);
+ gzwrite(gzf, &head, sizeof(UniPartHeader));
+ gzwrite(gzf, &(pdata->get(0)), sizeof(T)*head.dim);
+ 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");
+
+ 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.bytesPerElement == sizeof(T)) && (head.elementType==1) ), "pdata type doesn't match");
+ assertMsg (head.dim == pdata->size() , "pdata size doesn't match");
+ int bytes = sizeof(T)*head.dim;
+ int 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 );
+ }
+ gzclose(gzf);
+# else
+ debMsg( "file format not supported without zlib" ,1);
+# endif
+}
+
+// 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 writeParticlesUni<BasicParticleData>(const std::string& name, BasicParticleSystem* parts );
+template void readParticlesUni<BasicParticleData> (const std::string& name, BasicParticleSystem* parts );
+
+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 );
+
+#if ENABLE_GRID_TEST_DATATYPE==1
+// dummy functions for test datatype - not really supported right now!
+// but we need some function body for linking
+template<> void writeGridRaw<nbVector>(const string& name, Grid<nbVector>* grid) {assertMsg(false,"Not supported right now.");};
+template<> void writeGridUni<nbVector>(const string& name, Grid<nbVector>* grid) {assertMsg(false,"Not supported right now.");};
+template<> void writeGridVol<nbVector>(const string& name, Grid<nbVector>* grid) {assertMsg(false,"Not supported right now.");};
+template<> void writeGridTxt<nbVector>(const string& name, Grid<nbVector>* grid) {assertMsg(false,"Not supported right now.");};
+template<> void readGridRaw<nbVector> (const string& name, Grid<nbVector>* grid) {assertMsg(false,"Not supported right now.");};
+template<> void readGridUni<nbVector> (const string& name, Grid<nbVector>* grid) {assertMsg(false,"Not supported right now.");};
+#endif // ENABLE_GRID_TEST_DATATYPE
+
+
+} //namespace
+
+
diff --git a/source/blender/python/manta_pp/fileio.h b/source/blender/python/manta_pp/fileio.h
new file mode 100644
index 00000000000..d6c27e382a3
--- /dev/null
+++ b/source/blender/python/manta_pp/fileio.h
@@ -0,0 +1,62 @@
+
+
+
+
+
+// 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
+ *
+ * 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;
+class BasicParticleSystem;
+template<class T> class ParticleDataImpl;
+
+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);
+
+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 writeParticlesUni(const std::string& name, BasicParticleSystem* parts );
+template <class T> 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 );
+
+} // namespace
+
+#endif
+
+
diff --git a/source/blender/python/manta_pp/fileio.h.reg b/source/blender/python/manta_pp/fileio.h.reg
new file mode 100644
index 00000000000..3c1a56af210
--- /dev/null
+++ b/source/blender/python/manta_pp/fileio.h.reg
@@ -0,0 +1 @@
+#include "fileio.h"
diff --git a/source/blender/python/manta_pp/fileio.h.reg.cpp b/source/blender/python/manta_pp/fileio.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/fileio.h.reg.cpp
diff --git a/source/blender/python/manta_pp/fluidsolver.cpp b/source/blender/python/manta_pp/fluidsolver.cpp
new file mode 100644
index 00000000000..3374823bace
--- /dev/null
+++ b/source/blender/python/manta_pp/fluidsolver.cpp
@@ -0,0 +1,137 @@
+
+
+
+
+
+// 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
+ *
+ * Main class for the fluid solver
+ *
+ ******************************************************************************/
+
+#include "fluidsolver.h"
+#include "grid.h"
+#include <sstream>
+#include <fstream>
+
+using namespace std;
+namespace Manta {
+
+#ifdef GUI
+ // defined in qtmain.cpp
+ extern void updateQtGui(bool full, int frame, const std::string& curPlugin);
+#else
+ inline void updateQtGui(bool full, int frame, const std::string& curPlugin) {}
+#endif
+
+//******************************************************************************
+// 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) {
+ grids.push_back(new T[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<> 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);
+}
+
+//******************************************************************************
+// FluidSolver members
+
+FluidSolver::FluidSolver(Vec3i gridsize, int dim)
+ : PbClass(this), mDt(1.0), mGridSize(gridsize), mDim(dim), mTimeTotal(0.), mScale(1.0), mFrame(0)
+{
+ assertMsg(dim==2 || dim==3, "Can only create 2D and 3D solvers");
+ assertMsg(dim!=2 || gridsize.z == 1, "Trying to create 2D solver with size.z != 1");
+}
+
+FluidSolver::~FluidSolver() {
+ mGridsInt.free();
+ mGridsReal.free();
+ mGridsVec.free();
+}
+
+PbClass* FluidSolver::create(PbType t, PbTypeVec T, const string& name) {
+ _args.add("nocheck",true);
+ if (t.str() == "")
+ errMsg("Need to specify object type. Use e.g. Solver.create(FlagGrid, ...) or Solver.create(type=FlagGrid, ...)");
+
+ return PbClass::createPyObject(t.str() + T.str(), name, _args, this);
+}
+
+void FluidSolver::step() {
+ mTimeTotal += mDt;
+ mFrame++;
+ updateQtGui(true, mFrame, "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() <<". ";
+ printf("%s\n", msg.str().c_str() );
+}
+
+void printBuildInfo() {
+ debMsg( "Build info: "<<buildInfoString().c_str()<<" ",1);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "printBuildInfo" ); PyObject *_retval = 0; { ArgLocker _lock; _retval = getPyNone(); printBuildInfo(); _args.check(); } pbFinalizePlugin(parent,"printBuildInfo" ); return _retval; } catch(std::exception& e) { pbSetError("printBuildInfo",e.what()); return 0; } } static const Pb::Register _RP_printBuildInfo ("","printBuildInfo",_W_0);
+
+void setDebugLevel(int level=1) {
+ gDebugLevel = level;
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "setDebugLevel" ); PyObject *_retval = 0; { ArgLocker _lock; int level = _args.getOpt<int >("level",0,1,&_lock); _retval = getPyNone(); setDebugLevel(level); _args.check(); } pbFinalizePlugin(parent,"setDebugLevel" ); return _retval; } catch(std::exception& e) { pbSetError("setDebugLevel",e.what()); return 0; } } static const Pb::Register _RP_setDebugLevel ("","setDebugLevel",_W_1);
+
+} // manta
+
+
+
diff --git a/source/blender/python/manta_pp/fluidsolver.h b/source/blender/python/manta_pp/fluidsolver.h
new file mode 100644
index 00000000000..6cea45f2907
--- /dev/null
+++ b/source/blender/python/manta_pp/fluidsolver.h
@@ -0,0 +1,92 @@
+
+
+
+
+
+// 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
+ *
+ * Main class for the fluid solver
+ *
+ ******************************************************************************/
+
+#ifndef _FLUIDSOLVER_H
+#define _FLUIDSOLVER_H
+
+#include "manta.h"
+#include "vectorbase.h"
+#include <vector>
+#include <map>
+
+namespace Manta {
+
+//! Encodes grid size, timstep etc.
+
+class FluidSolver : public PbClass {public:
+ FluidSolver(Vec3i gridSize, int dim=3); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "FluidSolver::FluidSolver" ); { ArgLocker _lock; Vec3i gridSize = _args.get<Vec3i >("gridSize",0,&_lock); int dim = _args.getOpt<int >("dim",1,3,&_lock); obj = new FluidSolver(gridSize,dim); obj->registerObject(_self, &_args); _args.check(); } pbFinalizePlugin(obj->getParent(),"FluidSolver::FluidSolver" ); 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)); pbPreparePlugin(pbo->getParent(), "FluidSolver::getGridSize"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getGridSize()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"FluidSolver::getGridSize"); return _retval; } catch(std::exception& e) { pbSetError("FluidSolver::getGridSize",e.what()); return 0; } }
+ inline Real getDt() { return mDt; }
+ inline Real getTime() { return mTimeTotal; }
+ inline Real getDx() { return 1.0 / mGridSize.max(); }
+ inline Real getScale() { return mScale; }
+ //! Check dimensionality
+ inline bool is2D() const { return mDim==2; }
+ //! Check dimensionality
+ 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)); pbPreparePlugin(pbo->getParent(), "FluidSolver::printMemInfo"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->printMemInfo(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"FluidSolver::printMemInfo"); 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)); pbPreparePlugin(pbo->getParent(), "FluidSolver::step"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->step(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"FluidSolver::step"); return _retval; } catch(std::exception& e) { pbSetError("FluidSolver::step",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_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver* pbo = dynamic_cast<FluidSolver*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "FluidSolver::create"); 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"); return _retval; } catch(std::exception& e) { pbSetError("FluidSolver::create",e.what()); return 0; } }
+
+ // temp grid and plugin stuff: you shouldn't call this manually
+ template<class T> T* getGridPointer();
+ template<class T> void freeGridPointer(T* ptr);
+
+ 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; }
+protected:
+ //! 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;
+ };
+
+ Vec3i mGridSize;
+ const int mDim;
+ Real mTimeTotal, mScale;
+ int mFrame;
+
+ GridStorage<int> mGridsInt;
+ GridStorage<Real> mGridsReal; GridStorage<Vec3> mGridsVec; public: PbArgs _args;}
+#define _C_FluidSolver
+;
+
+}
+
+#endif
+
+
diff --git a/source/blender/python/manta_pp/fluidsolver.h.reg b/source/blender/python/manta_pp/fluidsolver.h.reg
new file mode 100644
index 00000000000..29bf91caf59
--- /dev/null
+++ b/source/blender/python/manta_pp/fluidsolver.h.reg
@@ -0,0 +1,9 @@
+#include "fluidsolver.h"
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","Solver","PbClass"); template<> const char* Namify<FluidSolver >::S = "FluidSolver";
+>FluidSolver^
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","FluidSolver",FluidSolver::_W_0);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","getGridSize",FluidSolver::_W_1);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","printMemInfo",FluidSolver::_W_2);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","step",FluidSolver::_W_3);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","create",FluidSolver::_W_4);
++FluidSolver^ static const Pb::Register _R_$IDX$ ("FluidSolver","timestep",FluidSolver::_GET_mDt,FluidSolver::_SET_mDt);
diff --git a/source/blender/python/manta_pp/fluidsolver.h.reg.cpp b/source/blender/python/manta_pp/fluidsolver.h.reg.cpp
new file mode 100644
index 00000000000..54d8e7fd2fc
--- /dev/null
+++ b/source/blender/python/manta_pp/fluidsolver.h.reg.cpp
@@ -0,0 +1,23 @@
+
+
+
+
+
+// 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_0 ("FluidSolver","Solver","PbClass"); template<> const char* Namify<FluidSolver >::S = "FluidSolver";
+ static const Pb::Register _R_1 ("FluidSolver","FluidSolver",FluidSolver::_W_0);
+ static const Pb::Register _R_2 ("FluidSolver","getGridSize",FluidSolver::_W_1);
+ static const Pb::Register _R_3 ("FluidSolver","printMemInfo",FluidSolver::_W_2);
+ static const Pb::Register _R_4 ("FluidSolver","step",FluidSolver::_W_3);
+ static const Pb::Register _R_5 ("FluidSolver","create",FluidSolver::_W_4);
+ static const Pb::Register _R_6 ("FluidSolver","timestep",FluidSolver::_GET_mDt,FluidSolver::_SET_mDt);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/general.cpp b/source/blender/python/manta_pp/general.cpp
new file mode 100644
index 00000000000..44f30ee9ef2
--- /dev/null
+++ b/source/blender/python/manta_pp/general.cpp
@@ -0,0 +1,141 @@
+
+
+
+
+
+// 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
+ *
+ * Globally used macros and functions
+ *
+ ******************************************************************************/
+
+#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 "hginfo.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;
+ infoStr << "mantaflow";
+
+ // 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_HG_VERSION
+# define MANTA_HG_VERSION "<unknown-commit>"
+# endif
+ infoStr << " "<< MANTA_HG_VERSION;
+
+ infoStr << " from "<< __DATE__<<", "<<__TIME__;
+ return infoStr.str();
+}
+
+} // namespace
+
+
diff --git a/source/blender/python/manta_pp/general.h b/source/blender/python/manta_pp/general.h
new file mode 100644
index 00000000000..45958d73324
--- /dev/null
+++ b/source/blender/python/manta_pp/general.h
@@ -0,0 +1,151 @@
+
+
+
+
+
+// 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
+ *
+ * Globally used macros and functions
+ *
+ ******************************************************************************/
+
+#ifndef _GENERAL_H
+#define _GENERAL_H
+
+#include <iostream>
+#include <sstream>
+#include <cmath>
+
+namespace Manta {
+
+// 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) )
+
+// 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;
+}
+
+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
+
+#endif
+
+
diff --git a/source/blender/python/manta_pp/general.h.reg b/source/blender/python/manta_pp/general.h.reg
new file mode 100644
index 00000000000..65a276295d5
--- /dev/null
+++ b/source/blender/python/manta_pp/general.h.reg
@@ -0,0 +1 @@
+#include "general.h"
diff --git a/source/blender/python/manta_pp/general.h.reg.cpp b/source/blender/python/manta_pp/general.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/general.h.reg.cpp
diff --git a/source/blender/python/manta_pp/grid.cpp b/source/blender/python/manta_pp/grid.cpp
new file mode 100644
index 00000000000..d47496623f4
--- /dev/null
+++ b/source/blender/python/manta_pp/grid.cpp
@@ -0,0 +1,560 @@
+
+
+
+
+
+// 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
+ *
+ * Grid representation
+ *
+ ******************************************************************************/
+
+#include "grid.h"
+#include "levelset.h"
+#include "kernel.h"
+#include <limits>
+#include <sstream>
+#include <cstring>
+#include "fileio.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)
+{
+ 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(const Grid<T>& a) : GridBase(a.getParent()) {
+ 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() {
+ 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.");
+
+ 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
+ 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);
+ else if (ext == ".txt")
+ writeGridTxt(name, this);
+ else
+ errMsg("file '" + name +"' filetype not supported");
+}
+
+template<class T>
+void Grid<T>::loadIncrement(string name) {
+ Grid<T> temp(*this);
+ temp.load(name);
+ for(int i=0; i< mSize[0] * mSize[1] * mSize[2]; ++i){
+ mData[i] += temp[i];
+ }
+}
+//******************************************************************************
+// Grid<T> operators
+
+//! Kernel: Compute min value of Real grid
+
+ struct CompMinReal : public KernelBase { CompMinReal(Grid<Real>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<Real>::max()) { run(); } inline void op(int idx, Grid<Real>& val ,Real& minVal) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+} inline operator Real () { return minVal; } inline Real & getRet() { return minVal; } inline Grid<Real>& getArg0() { return val; } typedef Grid<Real> type0; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, val,minVal); } Grid<Real>& val; Real minVal; };
+
+//! Kernel: Compute max value of Real grid
+
+ struct CompMaxReal : public KernelBase { CompMaxReal(Grid<Real>& val) : KernelBase(&val,0) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) { run(); } inline void op(int idx, Grid<Real>& val ,Real& maxVal) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+} inline operator Real () { return maxVal; } inline Real & getRet() { return maxVal; } inline Grid<Real>& getArg0() { return val; } typedef Grid<Real> type0; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, val,maxVal); } Grid<Real>& val; Real maxVal; };
+
+//! Kernel: Compute min value of int grid
+
+ struct CompMinInt : public KernelBase { CompMinInt(Grid<int>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<int>::max()) { run(); } inline void op(int idx, Grid<int>& val ,int& minVal) {
+ if (val[idx] < minVal)
+ minVal = val[idx];
+} inline operator int () { return minVal; } inline int & getRet() { return minVal; } inline Grid<int>& getArg0() { return val; } typedef Grid<int> type0; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, val,minVal); } Grid<int>& val; int minVal; };
+
+//! Kernel: Compute max value of int grid
+
+ struct CompMaxInt : public KernelBase { CompMaxInt(Grid<int>& val) : KernelBase(&val,0) ,val(val) ,maxVal(std::numeric_limits<int>::min()) { run(); } inline void op(int idx, Grid<int>& val ,int& maxVal) {
+ if (val[idx] > maxVal)
+ maxVal = val[idx];
+} inline operator int () { return maxVal; } inline int & getRet() { return maxVal; } inline Grid<int>& getArg0() { return val; } typedef Grid<int> type0; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, val,maxVal); } Grid<int>& val; int maxVal; };
+
+//! Kernel: Compute min norm of vec grid
+
+ struct CompMinVec : public KernelBase { CompMinVec(Grid<Vec3>& val) : KernelBase(&val,0) ,val(val) ,minVal(std::numeric_limits<Real>::max()) { run(); } inline void op(int idx, 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 Grid<Vec3>& getArg0() { return val; } typedef Grid<Vec3> type0; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, val,minVal); } Grid<Vec3>& val; Real minVal; };
+
+//! Kernel: Compute max norm of vec grid
+
+ struct CompMaxVec : public KernelBase { CompMaxVec(Grid<Vec3>& val) : KernelBase(&val,0) ,val(val) ,maxVal(-std::numeric_limits<Real>::max()) { run(); } inline void op(int idx, 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 Grid<Vec3>& getArg0() { return val; } typedef Grid<Vec3> type0; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, val,maxVal); } Grid<Vec3>& val; Real maxVal; };
+
+
+template<class T> Grid<T>& Grid<T>::safeDivide (const Grid<T>& a) {
+ gridSafeDiv<T> (*this, a);
+ return *this;
+}
+template<class T> Grid<T>& Grid<T>::copyFrom (const Grid<T>& a) {
+ 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);
+ 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) { run(); } inline void op(int idx, Grid<T>& me, T val ) { me[idx] = val; } inline Grid<T>& getArg0() { return me; } typedef Grid<T> type0;inline T& getArg1() { return val; } typedef T type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,val); } 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) { run(); } inline void op(int idx, Grid<T>& me, T val ) { me[idx] += val; } inline Grid<T>& getArg0() { return me; } typedef Grid<T> type0;inline T& getArg1() { return val; } typedef T type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,val); } 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) { run(); } inline void op(int idx, Grid<T>& me, T val ) { me[idx] *= val; } inline Grid<T>& getArg0() { return me; } typedef Grid<T> type0;inline T& getArg1() { return val; } typedef T type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,val); } Grid<T>& me; T val; };
+template <class T> struct knGridClamp : public KernelBase { knGridClamp(Grid<T>& me, T min, T max) : KernelBase(&me,0) ,me(me),min(min),max(max) { run(); } inline void op(int idx, Grid<T>& me, T min, T max ) { me[idx] = clamp( me[idx], min, max); } inline Grid<T>& getArg0() { return me; } typedef Grid<T> type0;inline T& getArg1() { return min; } typedef T type1;inline T& getArg2() { return max; } typedef T type2; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,min,max); } Grid<T>& me; T min; T max; };
+
+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<> Real Grid<Real>::getMaxValue() {
+ return CompMaxReal (*this);
+}
+template<> Real Grid<Real>::getMinValue() {
+ return CompMinReal (*this);
+}
+template<> Real Grid<Real>::getMaxAbsValue() {
+ Real amin = CompMinReal (*this);
+ Real amax = CompMaxReal (*this);
+ return max( fabs(amin), fabs(amax));
+}
+template<> Real Grid<Vec3>::getMaxValue() {
+ return sqrt(CompMaxVec (*this));
+}
+template<> Real Grid<Vec3>::getMinValue() {
+ return sqrt(CompMinVec (*this));
+}
+template<> Real Grid<Vec3>::getMaxAbsValue() {
+ return sqrt(CompMaxVec (*this));
+}
+template<> Real Grid<int>::getMaxValue() {
+ return (Real) CompMaxInt (*this);
+}
+template<> Real Grid<int>::getMinValue() {
+ return (Real) CompMinInt (*this);
+}
+template<> Real Grid<int>::getMaxAbsValue() {
+ int amin = CompMinInt (*this);
+ int amax = CompMaxInt (*this);
+ return max( fabs((Real)amin), fabs((Real)amax));
+}
+
+// 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(); pbPreparePlugin(parent, "gridMaxDiff" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("gridMaxDiff",e.what()); return 0; } } static const Pb::Register _RP_gridMaxDiff ("","gridMaxDiff",_W_0);
+
+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(); pbPreparePlugin(parent, "gridMaxDiffInt" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("gridMaxDiffInt",e.what()); return 0; } } static const Pb::Register _RP_gridMaxDiffInt ("","gridMaxDiffInt",_W_1);
+
+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(); pbPreparePlugin(parent, "gridMaxDiffVec3" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("gridMaxDiffVec3",e.what()); return 0; } } static const Pb::Register _RP_gridMaxDiffVec3 ("","gridMaxDiffVec3",_W_2);
+
+// simple helper functions to 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 convertMacToVec3(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(); pbPreparePlugin(parent, "convertMacToVec3" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("convertMacToVec3",e.what()); return 0; } } static const Pb::Register _RP_convertMacToVec3 ("","convertMacToVec3",_W_3);
+
+
+void convertLevelsetToReal(LevelsetGrid &source , Grid<Real> &target) {
+ FOR_IJK(target) {
+ target(i,j,k) = source(i,j,k);
+ }
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "convertLevelsetToReal" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("convertLevelsetToReal",e.what()); return 0; } } static const Pb::Register _RP_convertLevelsetToReal ("","convertLevelsetToReal",_W_4);
+
+
+template<class T> void Grid<T>::printGrid(int zSlice, bool printIndex) {
+ std::ostringstream out;
+ out << std::endl;
+ const int bnd = 1;
+ FOR_IJK_BND(*this,bnd) {
+ int idx = (*this).index(i,j,k);
+ if(zSlice>=0 && k==zSlice) {
+ out << " ";
+ if(printIndex) out << " "<<i<<","<<j<<","<<k <<":";
+ out << (*this)[idx];
+ if(i==(*this).getSizeX()-1 -bnd) out << std::endl;
+ }
+ }
+ out << endl; debMsg("Printing " << this->getName() << out.str().c_str() , 1);
+}
+
+
+template<class T> void Grid<T>::writeGridToMemory(const std::string& memLoc, const std::string& sizeAllowed)
+{
+ if (memLoc == "" ||memLoc == "0" ){
+ debMsg("Cant write grid to NULL pointer",1);
+ return;
+ }
+ istringstream iss(sizeAllowed);
+ size_t sizeAllowed_num;
+ iss >> sizeAllowed_num;
+ if (sizeof(T) * mSize.x * mSize.y * mSize.z != sizeAllowed_num){
+ debMsg("Cant write grid with incompatible size",1);
+ return;
+ }
+ stringstream ss(memLoc);
+ void *gridPointer = NULL;
+ ss >> gridPointer;
+ memcpy(gridPointer, mData, sizeAllowed_num);
+}
+
+template<class T> void Grid<T>::readGridFromMemory(const std::string& memLoc, int x, int y, int z)
+{
+ debMsg("Reading grid from " + memLoc,1);
+ if (memLoc == "" ||memLoc == "0" ){
+ debMsg("Can not write grid to NULL pointer",1);
+ return;
+ }
+ if (x != mSize.x || y != mSize.y || z != mSize.z)
+ {
+ debMsg("Can not write grid with different domain size",1);
+ return;
+ }
+ stringstream ss(memLoc);
+ void *gridPointer = NULL;
+ ss >> gridPointer;
+ memcpy(mData, gridPointer, sizeof(T) * x * y * z);
+}
+
+template<class T> void Grid<T>::readAdaptiveGridFromMemory(const std::string& memLoc, Vec3i minSize, Vec3i maxSize)
+{
+ if (memLoc == "" ||memLoc == "0" ){
+ debMsg("Can not write grid to NULL pointer",1);
+ return;
+ }
+ if (minSize.x < 0 || minSize.y < 0 || minSize.z < 0){
+ debMsg("Adaptive grid smaller than 0",1);
+ return;
+ }
+ if (maxSize.x > mSize.x || maxSize.y > mSize.y || maxSize.z > mSize.z){
+ debMsg("Adaptive grid larger than current",1);
+ return;
+ }
+ Vec3i adaptiveSize = maxSize - minSize;
+ stringstream ss(memLoc);
+ void *gridPointer = NULL;
+ ss >> gridPointer;
+ float *data_Array = (float* )gridPointer;
+ for (int x = 0; x < adaptiveSize.x; ++x){
+ for (int y = 0; y < adaptiveSize.y; ++y){
+ for (int z = 0; z < adaptiveSize.z; ++z){
+ get(x + minSize.x, y + minSize.y, z + minSize.z) = data_Array[x + adaptiveSize.x * y + adaptiveSize.x * adaptiveSize.y * z];
+ }
+ }
+ }
+}
+
+template<class T> std::string Grid<T>::getDataPointer()
+{
+ ostringstream ss;
+ ss << mData ;
+ return ss.str();
+}
+
+//! Kernel: Apply a texture to a grid, setting texture(ijk)*value where texture(ijk) > 0
+//note: can not use template kernel here, because of Blender classes
+
+ struct ApplyTextureToRealGrid : public KernelBase { ApplyTextureToRealGrid(Grid<Real> *grid, Grid<Real> *texture, Real value, FlagGrid* respectFlags) : KernelBase(grid,0) ,grid(grid),texture(texture),value(value),respectFlags(respectFlags) { run(); } inline void op(int i, int j, int k, Grid<Real> *grid, Grid<Real> *texture, Real value, FlagGrid* respectFlags ) {
+ if (respectFlags && respectFlags->isObstacle(i,j,k))
+ return;
+ if ((*texture)(i,j,k) > 0)
+ (*grid)(i,j,k) = (*texture)(i,j,k) * value;
+} inline Grid<Real> * getArg0() { return grid; } typedef Grid<Real> type0;inline Grid<Real> * getArg1() { return texture; } typedef Grid<Real> type1;inline Real& getArg2() { return value; } typedef Real type2;inline FlagGrid* getArg3() { return respectFlags; } typedef FlagGrid type3; 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, grid,texture,value,respectFlags); } Grid<Real> * grid; Grid<Real> * texture; Real value; FlagGrid* respectFlags; };
+
+
+ struct ApplyTextureToIntGrid : public KernelBase { ApplyTextureToIntGrid(Grid<int> *grid, Grid<Real> *texture, int value, FlagGrid* respectFlags) : KernelBase(grid,0) ,grid(grid),texture(texture),value(value),respectFlags(respectFlags) { run(); } inline void op(int i, int j, int k, Grid<int> *grid, Grid<Real> *texture, int value, FlagGrid* respectFlags ) {
+ if (respectFlags && respectFlags->isObstacle(i,j,k))
+ return;
+ if ((*texture)(i,j,k) > 0)
+ (*grid)(i,j,k) = value ;
+} inline Grid<int> * getArg0() { return grid; } typedef Grid<int> type0;inline Grid<Real> * getArg1() { return texture; } typedef Grid<Real> type1;inline int& getArg2() { return value; } typedef int type2;inline FlagGrid* getArg3() { return respectFlags; } typedef FlagGrid type3; 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, grid,texture,value,respectFlags); } Grid<int> * grid; Grid<Real> * texture; int value; FlagGrid* respectFlags; };
+
+template<class T> void Grid<T>::applyToGrid(GridBase *grid, FlagGrid* respectFlags)
+{
+ if (this->getType() & GridBase::TypeReal)
+ ApplyTextureToRealGrid((Grid<Real>*)grid, (Grid<Real>*)this, _args.get<Real>("value"), respectFlags);
+ if (this->getType() & GridBase::TypeInt)
+ ApplyTextureToIntGrid((Grid<int>*)grid, (Grid<Real>*)this, _args.get<int>("value"), respectFlags);
+}
+
+// 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_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "getUvWeight" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<Vec3> & uv = *_args.getPtr<Grid<Vec3> >("uv",0,&_lock); _retval = toPy(getUvWeight(uv)); _args.check(); } pbFinalizePlugin(parent,"getUvWeight" ); return _retval; } catch(std::exception& e) { pbSetError("getUvWeight",e.what()); return 0; } } static const Pb::Register _RP_getUvWeight ("","getUvWeight",_W_5);
+
+// 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) : KernelBase(&target,0) ,target(target) { run(); } inline void op(int i, int j, int k, Grid<Vec3>& target ) { target(i,j,k) = Vec3((Real)i,(Real)j,(Real)k); } inline Grid<Vec3>& getArg0() { return target; } typedef Grid<Vec3> type0; 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, target); } Grid<Vec3>& target; };
+
+
+void resetUvGrid(Grid<Vec3> &target) {
+ knResetUvGrid reset(target); // note, llvm complains about anonymous declaration here... ?
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "resetUvGrid" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<Vec3> & target = *_args.getPtr<Grid<Vec3> >("target",0,&_lock); _retval = getPyNone(); resetUvGrid(target); _args.check(); } pbFinalizePlugin(parent,"resetUvGrid" ); return _retval; } catch(std::exception& e) { pbSetError("resetUvGrid",e.what()); return 0; } } static const Pb::Register _RP_resetUvGrid ("","resetUvGrid",_W_6);
+
+void updateUvWeight(Real resetTime, int index, int numUvs, Grid<Vec3> &uv , bool info=false) {
+ 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 );
+
+ // write new weight value to grid
+ uv[0] = Vec3( uvWeight, 0.,0.);
+
+ // print info about uv weights?
+ if(info) debMsg("Uv grid "<<index<<"/"<<numUvs<< " t="<<currt<<" w="<<uvWeight<<", reset:"<<(int)(currt<lastt) , 1);
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "updateUvWeight" ); 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); bool info = _args.getOpt<bool >("info",4,false,&_lock); _retval = getPyNone(); updateUvWeight(resetTime,index,numUvs,uv,info); _args.check(); } pbFinalizePlugin(parent,"updateUvWeight" ); return _retval; } catch(std::exception& e) { pbSetError("updateUvWeight",e.what()); return 0; } } static const Pb::Register _RP_updateUvWeight ("","updateUvWeight",_W_7);
+
+void setBoundaries(Grid<Real>& grid, Real value=0., int boundaryWidth=1) {
+ const int w = boundaryWidth;
+ FOR_IJK(grid) {
+ 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;
+ }
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "setBoundaries" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<Real>& grid = *_args.getPtr<Grid<Real> >("grid",0,&_lock); Real value = _args.getOpt<Real >("value",1,0.,&_lock); int boundaryWidth = _args.getOpt<int >("boundaryWidth",2,1,&_lock); _retval = getPyNone(); setBoundaries(grid,value,boundaryWidth); _args.check(); } pbFinalizePlugin(parent,"setBoundaries" ); return _retval; } catch(std::exception& e) { pbSetError("setBoundaries",e.what()); return 0; } } static const Pb::Register _RP_setBoundaries ("","setBoundaries",_W_8);
+
+//******************************************************************************
+// Specialization classes
+
+void FlagGrid::initDomain(int boundaryWidth) {
+ FOR_IDX(*this)
+ mData[idx] = TypeEmpty;
+ initBoundaries(boundaryWidth);
+ // MLE 2014-06-25
+ bWidth = boundaryWidth;
+}
+
+void FlagGrid::initBoundaries(int boundaryWidth) {
+ const int w = boundaryWidth;
+ FOR_IJK(*this) {
+ bool bnd = (i<=w || i>=mSize.x-1-w || j<=w || j>=mSize.y-1-w || (is3D() && (k<=w || k>=mSize.z-1-w)));
+ if (bnd)
+ mData[index(i,j,k)] = TypeObstacle;
+ }
+}
+
+void FlagGrid::updateFromLevelset(LevelsetGrid& levelset) {
+ FOR_IDX(*this) {
+ if (!isObstacle(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] = (mData[idx] & ~(TypeEmpty | TypeFluid)) | type;
+ }
+}
+
+// explicit instantiation
+template class Grid<int>;
+template class Grid<Real>;
+template class Grid<Vec3>;
+
+
+//******************************************************************************
+// enable compilation of a more complicated test data type
+// enable in grid.h
+
+#if ENABLE_GRID_TEST_DATATYPE==1
+// NT_DEBUG ? template<> const char* Namify<nbVector>::S = "TestDatatype";
+
+template<> Real Grid<nbVector>::getMinValue() { return 0.; }
+template<> Real Grid<nbVector>::getMaxAbsValue() { return 0.; }
+template<> Real Grid<nbVector>::getMaxValue() { return 0.; }
+
+ struct knNbvecTestKernel : public KernelBase { knNbvecTestKernel(Grid<nbVector>& target) : KernelBase(&target,0) ,target(target) { run(); } inline void op(int i, int j, int k, Grid<nbVector>& target ) { target(i,j,k).push_back(i+j+k); } inline Grid<nbVector>& getArg0() { return target; } typedef Grid<nbVector> type0; 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, target); } Grid<nbVector>& target; };
+
+void nbvecTestOp(Grid<nbVector> &target) {
+ knNbvecTestKernel nbvecTest(target);
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "nbvecTestOp" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<nbVector> & target = *_args.getPtr<Grid<nbVector> >("target",0,&_lock); _retval = getPyNone(); nbvecTestOp(target); _args.check(); } pbFinalizePlugin(parent,"nbvecTestOp" ); return _retval; } catch(std::exception& e) { pbSetError("nbvecTestOp",e.what()); return 0; } } static const Pb::Register _RP_nbvecTestOp ("","nbvecTestOp",_W_9);
+
+// instantiate test datatype , not really required for simulations, mostly here for demonstration purposes
+template class Grid<nbVector>;
+#endif // ENABLE_GRID_TEST_DATATYPE
+
+
+} //namespace
+
+
diff --git a/source/blender/python/manta_pp/grid.h b/source/blender/python/manta_pp/grid.h
new file mode 100644
index 00000000000..3bc5326f3f7
--- /dev/null
+++ b/source/blender/python/manta_pp/grid.h
@@ -0,0 +1,508 @@
+
+
+
+
+
+// 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
+ *
+ * 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;
+class FlagGrid;
+
+//! 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); pbPreparePlugin(0, "GridBase::GridBase" ); { 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" ); 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; }
+ //! Get the grids Y dimension
+ inline int getSizeY() const { return mSize.y; }
+ //! Get the grids Z dimension
+ inline int getSizeZ() const { return mSize.z; }
+ //! Get the grids dimensions
+ inline Vec3i getSize() const { return mSize; }
+
+ //! Get Stride in X dimension
+ inline int getStrideX() const { return 1; }
+ //! Get Stride in Y dimension
+ inline int getStrideY() const { return mSize.x; }
+ //! Get Stride in Z dimension
+ inline int getStrideZ() const { return mStrideZ; }
+
+ 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) const;
+ //! Check if indices are within bounds, otherwise error (should only be called when debugging)
+ inline void checkIndex(int 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(int idx) const;
+
+ //! Get the type of grid
+ inline GridType getType() const { return mType; }
+ //! Check dimensionality
+ inline bool is2D() const { return !m3D; }
+ //! Check dimensionality
+ inline bool is3D() const { return m3D; }
+
+ //! Get index into the data
+ inline int index(int i, int j, int k) const { DEBUG_ONLY(checkIndex(i,j,k)); return i + mSize.x * j + mStrideZ * k; }
+ //! Get index into the data
+ inline int index(const Vec3i& pos) const { DEBUG_ONLY(checkIndex(pos.x,pos.y,pos.z)); return pos.x + mSize.x * pos.y + mStrideZ * pos.z; }
+protected:
+
+ GridType mType;
+ Vec3i mSize;
+ Real mDx;
+ bool m3D; // precomputed Z shift: to ensure 2D compatibility, always use this instead of sx*sy !
+ int 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_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "Grid::Grid" ); { 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" ); return 0; } catch(std::exception& e) { pbSetError("Grid::Grid",e.what()); return -1; } }
+ //! create new & copy content from another grid
+ Grid(const Grid<T>& a);
+ //! return memory to solver
+ virtual ~Grid();
+
+ typedef T BASETYPE;
+
+ void save(std::string name); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::save"); 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"); return _retval; } catch(std::exception& e) { pbSetError("Grid::save",e.what()); return 0; } }
+ void load(std::string name); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::load"); 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"); return _retval; } catch(std::exception& e) { pbSetError("Grid::load",e.what()); return 0; } }
+ //! loads values to be added to existing grid
+ void loadIncrement(std::string name); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::loadIncrement"); PyObject *_retval = 0; { ArgLocker _lock; std::string name = _args.get<std::string >("name",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->loadIncrement(name); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Grid::loadIncrement"); return _retval; } catch(std::exception& e) { pbSetError("Grid::loadIncrement",e.what()); return 0; } }
+ //! set all cells to zero
+ void clear(); static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::clear"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Grid::clear"); 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(int 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()(int idx) { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline T operator()(int 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[](int idx) { DEBUG_ONLY(checkIndex(idx)); return mData[idx]; }
+ //! access data
+ inline const T operator[](int 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
+ inline T getInterpolated(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);
+ }
+ }
+
+ // 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); static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::copyFrom"); PyObject *_retval = 0; { ArgLocker _lock; const Grid<T>& a = *_args.getPtr<Grid<T> >("a",0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->copyFrom(a)); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Grid::copyFrom"); return _retval; } catch(std::exception& e) { pbSetError("Grid::copyFrom",e.what()); return 0; } } // { *this = a; }
+
+ // helper functions to work with grids in scene files
+
+ //! add/subtract other grid
+ void add(const Grid<T>& a); static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::add"); 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"); return _retval; } catch(std::exception& e) { pbSetError("Grid::add",e.what()); return 0; } }
+ void sub(const Grid<T>& a); static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::sub"); 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"); 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_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::setConst"); 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"); 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_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::addConst"); 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"); 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_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::addScaled"); 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"); 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_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::mult"); 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"); 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_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::multConst"); 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"); 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_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::clamp"); 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"); return _retval; } catch(std::exception& e) { pbSetError("Grid::clamp",e.what()); return 0; } }
+
+ // common compound operators
+ //! get absolute max value in grid
+ Real getMaxAbsValue(); static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::getMaxAbsValue"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMaxAbsValue()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Grid::getMaxAbsValue"); return _retval; } catch(std::exception& e) { pbSetError("Grid::getMaxAbsValue",e.what()); return 0; } }
+ //! get max value in grid
+ Real getMaxValue(); static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::getMaxValue"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMaxValue()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Grid::getMaxValue"); return _retval; } catch(std::exception& e) { pbSetError("Grid::getMaxValue",e.what()); return 0; } }
+ //! get min value in grid
+ Real getMinValue(); static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::getMinValue"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMinValue()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Grid::getMinValue"); return _retval; } catch(std::exception& e) { pbSetError("Grid::getMinValue",e.what()); return 0; } }
+
+ //! debugging helper, print grid from python
+ void printGrid(int zSlice=-1, bool printIndex=false); static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::printGrid"); PyObject *_retval = 0; { ArgLocker _lock; int zSlice = _args.getOpt<int >("zSlice",0,-1,&_lock); bool printIndex = _args.getOpt<bool >("printIndex",1,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->printGrid(zSlice,printIndex); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Grid::printGrid"); return _retval; } catch(std::exception& e) { pbSetError("Grid::printGrid",e.what()); return 0; } }
+
+ //! write and read grid data to pointed memory
+ void writeGridToMemory(const std::string& memLoc, const std::string& sizeAllowed); static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::writeGridToMemory"); PyObject *_retval = 0; { ArgLocker _lock; const std::string& memLoc = _args.get<std::string >("memLoc",0,&_lock); const std::string& sizeAllowed = _args.get<std::string >("sizeAllowed",1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->writeGridToMemory(memLoc,sizeAllowed); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Grid::writeGridToMemory"); return _retval; } catch(std::exception& e) { pbSetError("Grid::writeGridToMemory",e.what()); return 0; } }
+ void readGridFromMemory(const std::string& memLoc, int x, int y, int z); static PyObject* _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::readGridFromMemory"); PyObject *_retval = 0; { ArgLocker _lock; const std::string& memLoc = _args.get<std::string >("memLoc",0,&_lock); int x = _args.get<int >("x",1,&_lock); int y = _args.get<int >("y",2,&_lock); int z = _args.get<int >("z",3,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->readGridFromMemory(memLoc,x,y,z); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Grid::readGridFromMemory"); return _retval; } catch(std::exception& e) { pbSetError("Grid::readGridFromMemory",e.what()); return 0; } }
+ void readAdaptiveGridFromMemory(const std::string& memLoc, Vec3i min, Vec3i max); static PyObject* _W_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::readAdaptiveGridFromMemory"); PyObject *_retval = 0; { ArgLocker _lock; const std::string& memLoc = _args.get<std::string >("memLoc",0,&_lock); Vec3i min = _args.get<Vec3i >("min",1,&_lock); Vec3i max = _args.get<Vec3i >("max",2,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->readAdaptiveGridFromMemory(memLoc,min,max); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Grid::readAdaptiveGridFromMemory"); return _retval; } catch(std::exception& e) { pbSetError("Grid::readAdaptiveGridFromMemory",e.what()); return 0; } }
+ //! Applies texture to grid, as in Shape::applyToGrid
+ void applyToGrid(GridBase *grid, FlagGrid* respectFlags = 0); static PyObject* _W_22 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::applyToGrid"); 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(),"Grid::applyToGrid"); return _retval; } catch(std::exception& e) { pbSetError("Grid::applyToGrid",e.what()); return 0; } }
+ std::string getDataPointer(); static PyObject* _W_23 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Grid* pbo = dynamic_cast<Grid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Grid::getDataPointer"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getDataPointer()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Grid::getDataPointer"); return _retval; } catch(std::exception& e) { pbSetError("Grid::getDataPointer",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);
+
+protected: T* mData; 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_24 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "MACGrid::MACGrid" ); { 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" ); return 0; } catch(std::exception& e) { pbSetError("MACGrid::MACGrid",e.what()); return -1; } }
+
+ // 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;
+ template<int comp> inline Real getInterpolatedComponent(Vec3 pos) const { return interpolComponent<comp>(mData, mSize, mStrideZ, pos); }
+ inline Vec3 getInterpolated(const Vec3& pos) const { return interpolMAC(mData, mSize, mStrideZ, pos); }
+ inline void setInterpolated(const Vec3& pos, const Vec3& val, Vec3* tmp) { return setInterpolMAC(mData, mSize, mStrideZ, pos, val, tmp); }
+ 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_25 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "FlagGrid::FlagGrid" ); { 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" ); return 0; } catch(std::exception& e) { pbSetError("FlagGrid::FlagGrid",e.what()); return -1; } }
+
+ //! 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,
+ TypeStick = 128,
+ TypeReserved = 256
+ // 2^10 - 2^14 reserved for moving obstacles
+ };
+
+ // MLE 2014-06-25
+ int bWidth;
+ inline int getBoundaryWidth(){return bWidth;};
+
+ //! 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(int 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(int 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(int 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(int 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 isStick(int 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; }
+
+ // Python callables
+ void initDomain(int boundaryWidth=0); static PyObject* _W_26 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FlagGrid* pbo = dynamic_cast<FlagGrid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "FlagGrid::initDomain"); PyObject *_retval = 0; { ArgLocker _lock; int boundaryWidth = _args.getOpt<int >("boundaryWidth",0,0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->initDomain(boundaryWidth); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"FlagGrid::initDomain"); return _retval; } catch(std::exception& e) { pbSetError("FlagGrid::initDomain",e.what()); return 0; } }
+ void initBoundaries(int boundaryWidth=0); static PyObject* _W_27 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FlagGrid* pbo = dynamic_cast<FlagGrid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "FlagGrid::initBoundaries"); PyObject *_retval = 0; { ArgLocker _lock; int boundaryWidth = _args.getOpt<int >("boundaryWidth",0,0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->initBoundaries(boundaryWidth); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"FlagGrid::initBoundaries"); return _retval; } catch(std::exception& e) { pbSetError("FlagGrid::initBoundaries",e.what()); return 0; } }
+ void updateFromLevelset(LevelsetGrid& levelset); static PyObject* _W_28 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FlagGrid* pbo = dynamic_cast<FlagGrid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "FlagGrid::updateFromLevelset"); 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"); return _retval; } catch(std::exception& e) { pbSetError("FlagGrid::updateFromLevelset",e.what()); return 0; } } void fillGrid(int type=TypeFluid); static PyObject* _W_29 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FlagGrid* pbo = dynamic_cast<FlagGrid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "FlagGrid::fillGrid"); 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"); return _retval; } catch(std::exception& e) { pbSetError("FlagGrid::fillGrid",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] );
+}
+
+
+//******************************************************************************
+// enable compilation of a more complicated test data type
+// for grids... note - this also enables code parts in fileio.cpp!
+// the code below is meant only as an example for a grid with a more complex data type
+// and illustrates which functions need to be implemented; it's not needed
+// to run any simulations in mantaflow!
+
+#define ENABLE_GRID_TEST_DATATYPE 0
+
+#if ENABLE_GRID_TEST_DATATYPE==1
+
+typedef std::vector<int> nbVectorBaseType;
+class nbVector : public nbVectorBaseType {
+ public:
+ inline nbVector() : nbVectorBaseType() {};
+ inline ~nbVector() {};
+
+ // grid operators require certain functions
+ inline nbVector(Real v) : nbVectorBaseType() { this->push_back( (int)v ); };
+
+ inline const nbVector& operator+= ( const nbVector &v1 ) {
+ assertMsg(false,"Never call!"); return *this;
+ }
+ inline const nbVector& operator-= ( const nbVector &v1 ) {
+ assertMsg(false,"Never call!"); return *this;
+ }
+ inline const nbVector& operator*= ( const nbVector &v1 ) {
+ assertMsg(false,"Never call!"); return *this;
+ }
+};
+
+template<> inline nbVector* FluidSolver::getGridPointer<nbVector>() {
+ return new nbVector[mGridSize.x * mGridSize.y * mGridSize.z];
+}
+template<> inline void FluidSolver::freeGridPointer<nbVector>(nbVector* ptr) {
+ return delete[] ptr;
+}
+
+inline nbVector operator+ ( const nbVector &v1, const nbVector &v2 ) {
+ assertMsg(false,"Never call!"); return nbVector();
+}
+inline nbVector operator* ( const nbVector &v1, const nbVector &v2 ) {
+ assertMsg(false,"Never call!"); return nbVector();
+}
+template<class S>
+inline nbVector operator* ( const nbVector& v, S s ) {
+ assertMsg(false,"Never call!"); return nbVector();
+}
+template<class S>
+inline nbVector operator* ( S s, const nbVector& v ) {
+ assertMsg(false,"Never call!"); return nbVector();
+}
+
+template<> inline nbVector safeDivide<nbVector>(const nbVector &a, const nbVector& b) {
+ assertMsg(false,"Never call!"); return nbVector();
+}
+
+std::ostream& operator<< ( std::ostream& os, const nbVectorBaseType& i ) {
+ os << " nbVectorBaseType NYI ";
+ return os;
+}
+
+// make data type known to python
+// (python keyword changed here, because the preprocessor does not yet parse #ifdefs correctly)
+PY THON alias Grid<nbVector> TestDataGrid;
+// ? PY THON alias nbVector TestDatatype;
+
+#endif // end ENABLE_GRID_TEST_DATATYPE
+
+
+
+//******************************************************************************
+// Implementation of inline functions
+
+inline void GridBase::checkIndex(int i, int j, int k) const {
+ //if (i<0 || j<0 || i>=mSize.x || j>=mSize.y || (is3D() && (k<0|| k>= mSize.z))) {
+ if (i<0 || j<0 || i>=mSize.x || j>=mSize.y || k<0|| 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(int 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(int 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 int 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 int 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 int 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 int 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) { run(); } inline void op(int idx, Grid<T>& me, const Grid<S>& other ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } 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) { run(); } inline void op(int idx, Grid<T>& me, const Grid<S>& other ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } 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) { run(); } inline void op(int idx, Grid<T>& me, const Grid<S>& other ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } 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) { run(); } inline void op(int idx, Grid<T>& me, const Grid<S>& other ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } 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) { run(); } inline void op(int idx, Grid<T>& me, const S& other ) { me[idx] += other; } inline Grid<T>& getArg0() { return me; } typedef Grid<T> type0;inline const S& getArg1() { return other; } typedef S type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } 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) { run(); } inline void op(int idx, Grid<T>& me, const S& other ) { me[idx] *= other; } inline Grid<T>& getArg0() { return me; } typedef Grid<T> type0;inline const S& getArg1() { return other; } typedef S type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } 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) { run(); } inline void op(int idx, Grid<T>& me, const Grid<T>& other, const S& factor ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other,factor); } Grid<T>& me; const Grid<T>& other; const S& factor; };
+
+template <class T> struct gridSafeDiv : public KernelBase { gridSafeDiv(Grid<T>& me, const Grid<T>& other) : KernelBase(&me,0) ,me(me),other(other) { run(); } inline void op(int idx, Grid<T>& me, const Grid<T>& other ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } Grid<T>& me; const Grid<T>& other; };
+template <class T> struct gridSetConst : public KernelBase { gridSetConst(Grid<T>& grid, T value) : KernelBase(&grid,0) ,grid(grid),value(value) { run(); } inline void op(int idx, Grid<T>& grid, T value ) { grid[idx] = value; } inline Grid<T>& getArg0() { return grid; } typedef Grid<T> type0;inline T& getArg1() { return value; } typedef T type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, grid,value); } 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;
+}
+
+
+
+} //namespace
+#endif
+
+
diff --git a/source/blender/python/manta_pp/grid.h.reg b/source/blender/python/manta_pp/grid.h.reg
new file mode 100644
index 00000000000..bd58e1d1590
--- /dev/null
+++ b/source/blender/python/manta_pp/grid.h.reg
@@ -0,0 +1,46 @@
+#include "grid.h"
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","GridBase","PbClass"); template<> const char* Namify<GridBase >::S = "GridBase";
+>GridBase^
++GridBase^ static const Pb::Register _R_$IDX$ ("GridBase","GridBase",GridBase::_W_0);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","Grid<$CT$>","GridBase"); template<> const char* Namify<Grid<$CT$> >::S = "Grid<$CT$>";
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","Grid",Grid<$CT$>::_W_1);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","save",Grid<$CT$>::_W_2);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","load",Grid<$CT$>::_W_3);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","loadIncrement",Grid<$CT$>::_W_4);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","clear",Grid<$CT$>::_W_5);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","copyFrom",Grid<$CT$>::_W_6);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","add",Grid<$CT$>::_W_7);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","sub",Grid<$CT$>::_W_8);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","setConst",Grid<$CT$>::_W_9);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","addConst",Grid<$CT$>::_W_10);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","addScaled",Grid<$CT$>::_W_11);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","mult",Grid<$CT$>::_W_12);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","multConst",Grid<$CT$>::_W_13);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","clamp",Grid<$CT$>::_W_14);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getMaxAbsValue",Grid<$CT$>::_W_15);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getMaxValue",Grid<$CT$>::_W_16);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getMinValue",Grid<$CT$>::_W_17);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","printGrid",Grid<$CT$>::_W_18);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","writeGridToMemory",Grid<$CT$>::_W_19);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","readGridFromMemory",Grid<$CT$>::_W_20);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","readAdaptiveGridFromMemory",Grid<$CT$>::_W_21);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","applyToGrid",Grid<$CT$>::_W_22);
++Grid^ static const Pb::Register _R_$IDX$ ("Grid<$CT$>","getDataPointer",Grid<$CT$>::_W_23);
+>Grid^int
+&static const Pb::Register _R_$IDX$ ("Grid<int>","IntGrid","");
+>Grid^Real
+&static const Pb::Register _R_$IDX$ ("Grid<Real>","RealGrid","");
+>Grid^Vec3
+&static const Pb::Register _R_$IDX$ ("Grid<Vec3>","VecGrid","");
++MACGrid^ static const Pb::Register _R_$IDX$ ("MACGrid","MACGrid","Grid<$BT$>"); template<> const char* Namify<MACGrid >::S = "MACGrid";
+>MACGrid^
+@MACGrid^^Grid^Vec3
++MACGrid^ static const Pb::Register _R_$IDX$ ("MACGrid","MACGrid",MACGrid::_W_24);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","FlagGrid","Grid<$BT$>"); template<> const char* Namify<FlagGrid >::S = "FlagGrid";
+>FlagGrid^
+@FlagGrid^^Grid^int
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","FlagGrid",FlagGrid::_W_25);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","initDomain",FlagGrid::_W_26);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","initBoundaries",FlagGrid::_W_27);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","updateFromLevelset",FlagGrid::_W_28);
++FlagGrid^ static const Pb::Register _R_$IDX$ ("FlagGrid","fillGrid",FlagGrid::_W_29);
diff --git a/source/blender/python/manta_pp/grid.h.reg.cpp b/source/blender/python/manta_pp/grid.h.reg.cpp
new file mode 100644
index 00000000000..76321052a1d
--- /dev/null
+++ b/source/blender/python/manta_pp/grid.h.reg.cpp
@@ -0,0 +1,107 @@
+
+
+
+
+
+// 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_3 ("FlagGrid","FlagGrid","Grid<int>"); template<> const char* Namify<FlagGrid >::S = "FlagGrid";
+ static const Pb::Register _R_4 ("FlagGrid","FlagGrid",FlagGrid::_W_25);
+ static const Pb::Register _R_5 ("FlagGrid","initDomain",FlagGrid::_W_26);
+ static const Pb::Register _R_6 ("FlagGrid","initBoundaries",FlagGrid::_W_27);
+ static const Pb::Register _R_7 ("FlagGrid","updateFromLevelset",FlagGrid::_W_28);
+ static const Pb::Register _R_8 ("FlagGrid","fillGrid",FlagGrid::_W_29);
+#endif
+#ifdef _C_Grid
+ static const Pb::Register _R_9 ("Grid<int>","Grid<int>","GridBase"); template<> const char* Namify<Grid<int> >::S = "Grid<int>";
+ static const Pb::Register _R_10 ("Grid<int>","Grid",Grid<int>::_W_1);
+ static const Pb::Register _R_11 ("Grid<int>","save",Grid<int>::_W_2);
+ static const Pb::Register _R_12 ("Grid<int>","load",Grid<int>::_W_3);
+ static const Pb::Register _R_13 ("Grid<int>","loadIncrement",Grid<int>::_W_4);
+ static const Pb::Register _R_14 ("Grid<int>","clear",Grid<int>::_W_5);
+ static const Pb::Register _R_15 ("Grid<int>","copyFrom",Grid<int>::_W_6);
+ static const Pb::Register _R_16 ("Grid<int>","add",Grid<int>::_W_7);
+ static const Pb::Register _R_17 ("Grid<int>","sub",Grid<int>::_W_8);
+ static const Pb::Register _R_18 ("Grid<int>","setConst",Grid<int>::_W_9);
+ static const Pb::Register _R_19 ("Grid<int>","addConst",Grid<int>::_W_10);
+ static const Pb::Register _R_20 ("Grid<int>","addScaled",Grid<int>::_W_11);
+ static const Pb::Register _R_21 ("Grid<int>","mult",Grid<int>::_W_12);
+ static const Pb::Register _R_22 ("Grid<int>","multConst",Grid<int>::_W_13);
+ static const Pb::Register _R_23 ("Grid<int>","clamp",Grid<int>::_W_14);
+ static const Pb::Register _R_24 ("Grid<int>","getMaxAbsValue",Grid<int>::_W_15);
+ static const Pb::Register _R_25 ("Grid<int>","getMaxValue",Grid<int>::_W_16);
+ static const Pb::Register _R_26 ("Grid<int>","getMinValue",Grid<int>::_W_17);
+ static const Pb::Register _R_27 ("Grid<int>","printGrid",Grid<int>::_W_18);
+ static const Pb::Register _R_28 ("Grid<int>","writeGridToMemory",Grid<int>::_W_19);
+ static const Pb::Register _R_29 ("Grid<int>","readGridFromMemory",Grid<int>::_W_20);
+ static const Pb::Register _R_30 ("Grid<int>","readAdaptiveGridFromMemory",Grid<int>::_W_21);
+ static const Pb::Register _R_31 ("Grid<int>","applyToGrid",Grid<int>::_W_22);
+ static const Pb::Register _R_32 ("Grid<int>","getDataPointer",Grid<int>::_W_23);
+ static const Pb::Register _R_33 ("Grid<Real>","Grid<Real>","GridBase"); template<> const char* Namify<Grid<Real> >::S = "Grid<Real>";
+ static const Pb::Register _R_34 ("Grid<Real>","Grid",Grid<Real>::_W_1);
+ static const Pb::Register _R_35 ("Grid<Real>","save",Grid<Real>::_W_2);
+ static const Pb::Register _R_36 ("Grid<Real>","load",Grid<Real>::_W_3);
+ static const Pb::Register _R_37 ("Grid<Real>","loadIncrement",Grid<Real>::_W_4);
+ static const Pb::Register _R_38 ("Grid<Real>","clear",Grid<Real>::_W_5);
+ static const Pb::Register _R_39 ("Grid<Real>","copyFrom",Grid<Real>::_W_6);
+ static const Pb::Register _R_40 ("Grid<Real>","add",Grid<Real>::_W_7);
+ static const Pb::Register _R_41 ("Grid<Real>","sub",Grid<Real>::_W_8);
+ static const Pb::Register _R_42 ("Grid<Real>","setConst",Grid<Real>::_W_9);
+ static const Pb::Register _R_43 ("Grid<Real>","addConst",Grid<Real>::_W_10);
+ static const Pb::Register _R_44 ("Grid<Real>","addScaled",Grid<Real>::_W_11);
+ static const Pb::Register _R_45 ("Grid<Real>","mult",Grid<Real>::_W_12);
+ static const Pb::Register _R_46 ("Grid<Real>","multConst",Grid<Real>::_W_13);
+ static const Pb::Register _R_47 ("Grid<Real>","clamp",Grid<Real>::_W_14);
+ static const Pb::Register _R_48 ("Grid<Real>","getMaxAbsValue",Grid<Real>::_W_15);
+ static const Pb::Register _R_49 ("Grid<Real>","getMaxValue",Grid<Real>::_W_16);
+ static const Pb::Register _R_50 ("Grid<Real>","getMinValue",Grid<Real>::_W_17);
+ static const Pb::Register _R_51 ("Grid<Real>","printGrid",Grid<Real>::_W_18);
+ static const Pb::Register _R_52 ("Grid<Real>","writeGridToMemory",Grid<Real>::_W_19);
+ static const Pb::Register _R_53 ("Grid<Real>","readGridFromMemory",Grid<Real>::_W_20);
+ static const Pb::Register _R_54 ("Grid<Real>","readAdaptiveGridFromMemory",Grid<Real>::_W_21);
+ static const Pb::Register _R_55 ("Grid<Real>","applyToGrid",Grid<Real>::_W_22);
+ static const Pb::Register _R_56 ("Grid<Real>","getDataPointer",Grid<Real>::_W_23);
+ static const Pb::Register _R_57 ("Grid<Vec3>","Grid<Vec3>","GridBase"); template<> const char* Namify<Grid<Vec3> >::S = "Grid<Vec3>";
+ static const Pb::Register _R_58 ("Grid<Vec3>","Grid",Grid<Vec3>::_W_1);
+ static const Pb::Register _R_59 ("Grid<Vec3>","save",Grid<Vec3>::_W_2);
+ static const Pb::Register _R_60 ("Grid<Vec3>","load",Grid<Vec3>::_W_3);
+ static const Pb::Register _R_61 ("Grid<Vec3>","loadIncrement",Grid<Vec3>::_W_4);
+ static const Pb::Register _R_62 ("Grid<Vec3>","clear",Grid<Vec3>::_W_5);
+ static const Pb::Register _R_63 ("Grid<Vec3>","copyFrom",Grid<Vec3>::_W_6);
+ static const Pb::Register _R_64 ("Grid<Vec3>","add",Grid<Vec3>::_W_7);
+ static const Pb::Register _R_65 ("Grid<Vec3>","sub",Grid<Vec3>::_W_8);
+ static const Pb::Register _R_66 ("Grid<Vec3>","setConst",Grid<Vec3>::_W_9);
+ static const Pb::Register _R_67 ("Grid<Vec3>","addConst",Grid<Vec3>::_W_10);
+ static const Pb::Register _R_68 ("Grid<Vec3>","addScaled",Grid<Vec3>::_W_11);
+ static const Pb::Register _R_69 ("Grid<Vec3>","mult",Grid<Vec3>::_W_12);
+ static const Pb::Register _R_70 ("Grid<Vec3>","multConst",Grid<Vec3>::_W_13);
+ static const Pb::Register _R_71 ("Grid<Vec3>","clamp",Grid<Vec3>::_W_14);
+ static const Pb::Register _R_72 ("Grid<Vec3>","getMaxAbsValue",Grid<Vec3>::_W_15);
+ static const Pb::Register _R_73 ("Grid<Vec3>","getMaxValue",Grid<Vec3>::_W_16);
+ static const Pb::Register _R_74 ("Grid<Vec3>","getMinValue",Grid<Vec3>::_W_17);
+ static const Pb::Register _R_75 ("Grid<Vec3>","printGrid",Grid<Vec3>::_W_18);
+ static const Pb::Register _R_76 ("Grid<Vec3>","writeGridToMemory",Grid<Vec3>::_W_19);
+ static const Pb::Register _R_77 ("Grid<Vec3>","readGridFromMemory",Grid<Vec3>::_W_20);
+ static const Pb::Register _R_78 ("Grid<Vec3>","readAdaptiveGridFromMemory",Grid<Vec3>::_W_21);
+ static const Pb::Register _R_79 ("Grid<Vec3>","applyToGrid",Grid<Vec3>::_W_22);
+ static const Pb::Register _R_80 ("Grid<Vec3>","getDataPointer",Grid<Vec3>::_W_23);
+#endif
+#ifdef _C_GridBase
+ static const Pb::Register _R_81 ("GridBase","GridBase","PbClass"); template<> const char* Namify<GridBase >::S = "GridBase";
+ static const Pb::Register _R_82 ("GridBase","GridBase",GridBase::_W_0);
+#endif
+#ifdef _C_MACGrid
+ static const Pb::Register _R_83 ("MACGrid","MACGrid","Grid<Vec3>"); template<> const char* Namify<MACGrid >::S = "MACGrid";
+ static const Pb::Register _R_84 ("MACGrid","MACGrid",MACGrid::_W_24);
+#endif
+static const Pb::Register _R_0 ("Grid<int>","IntGrid","");
+static const Pb::Register _R_1 ("Grid<Real>","RealGrid","");
+static const Pb::Register _R_2 ("Grid<Vec3>","VecGrid","");
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/gui/customctrl.cpp b/source/blender/python/manta_pp/gui/customctrl.cpp
new file mode 100644
index 00000000000..c7d4defeca7
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/customctrl.cpp
@@ -0,0 +1,198 @@
+
+
+
+
+
+// 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
+ *
+ * GUI extension from python
+ *
+ ******************************************************************************/
+
+#include "customctrl.h"
+#include "qtmain.h"
+#include "painter.h"
+
+using namespace std;
+namespace Manta {
+
+// *****************************************************************************
+// Slider class
+
+CustomControl::CustomControl() : PbClass(0) {
+}
+
+CustomCheckbox::CustomCheckbox(string name, bool val) : mVal(val), mSName(name), mCheckbox(0) {
+}
+
+void CustomCheckbox::init(QBoxLayout* layout) {
+ mCheckbox = new TextCheckbox(mSName, mVal);
+ QObject::connect(mCheckbox, SIGNAL(stateChanged(int)), mCheckbox, SLOT(update(int)));
+ mCheckbox->attach(layout);
+}
+
+bool CustomCheckbox::get() {
+ if (!mCheckbox) throw Error("Slider is not attached yet!");
+ return mCheckbox->get();
+}
+void CustomCheckbox::set(bool v) {
+ if (!mCheckbox) throw Error("Slider is not attached yet!");
+ mCheckbox->set(v);
+}
+
+CustomSlider::CustomSlider(string name, float val, float min, float max) :
+ mMin(min), mMax(max), mVal(val), mSName(name), mSlider(0)
+{
+}
+
+void CustomSlider::init(QBoxLayout* layout) {
+ mSlider = new TextSlider(mSName, mVal, mMin, mMax);
+ QObject::connect(mSlider, SIGNAL(valueChanged(int)), mSlider, SLOT(update(int)));
+ mSlider->attach(layout);
+}
+
+float CustomSlider::get() {
+ if (!mSlider) throw Error("Slider is not attached yet!");
+ return mSlider->get();
+}
+
+void CustomSlider::set(float v) {
+ if (!mSlider) throw Error("Slider is not attached yet!");
+ mSlider->set(v);
+}
+
+TextSlider::TextSlider(const string& name, float val, float vmin, float vmax) :
+ QSlider(Qt::Horizontal), mMin(vmin), mMax(vmax), mSName(name.c_str())
+{
+ mLabel = new QLabel();
+ mScale = 1000;
+ setMinimum(0);
+ setMaximum(999);
+ set(val);
+ update(0);
+ }
+
+void TextSlider::attach(QBoxLayout* layout) {
+ layout->addWidget(mLabel);
+ layout->addWidget(this);
+}
+
+void TextSlider::update(int val) {
+ float v = get();
+ QString num;
+ num.sprintf("%.2g", v);
+ mLabel->setText(mSName + ": " + num);
+}
+
+float TextSlider::get() {
+ float va = mMin + (mMax-mMin) / mScale * (float)value();
+ return clamp(va, mMin, mMax);
+}
+
+void TextSlider::set(float v) {
+ float va = clamp(v, mMin, mMax);
+ va = (va - mMin) / (mMax-mMin) * mScale;
+ setValue((int)(va+0.5));
+}
+
+TextCheckbox::TextCheckbox(const string& name, bool val) :
+ QCheckBox(), mVal(val), mSName(name.c_str())
+{
+ mLabel = new QLabel();
+ set(val);
+ mLabel->setText(mSName);
+ }
+
+void TextCheckbox::attach(QBoxLayout* layout) {
+ QLayout* lay = new QHBoxLayout;
+ lay->setAlignment(Qt::AlignLeft);
+ lay->addWidget(this);
+ lay->addWidget(mLabel);
+ layout->addLayout(lay);
+}
+
+void TextCheckbox::update(int val) {
+}
+
+bool TextCheckbox::get() {
+ return isChecked();
+}
+
+void TextCheckbox::set(bool v) {
+ setChecked(v);
+}
+
+
+
+// **************************************************************************************
+// GUI class
+
+void updateQtGui(bool full, int frame, const std::string& curPlugin);
+extern MainThread* gMainThread;
+extern GuiThread* gGuiThread;
+
+Gui::Gui() :
+ PbClass(NULL), mGuiPtr(gGuiThread), mMainPtr(gMainThread) {
+}
+
+void Gui::setBackgroundMesh(Mesh* m) {
+ mGuiPtr->getWindow()->setBackground(m);
+}
+void Gui::show(bool twoD) {
+ if(twoD)
+ mMainPtr->send( (int)MainWnd::EventSet2DCam );
+ mMainPtr->sendAndWait( (int)MainWnd::EventGuiShow );
+}
+void Gui::update() {
+ updateQtGui(true,-1,"");
+}
+void Gui::pause() {
+ mMainPtr->sendAndWait((int)MainWnd::EventFullUpdate);
+ mGuiPtr->getWindow()->pause();
+}
+void Gui::screenshot(string filename) {
+ QString s(filename.c_str());
+ QMetaObject::invokeMethod(mGuiPtr->getWindow(), "screenshot", Q_ARG(QString, s));
+}
+
+void Gui::nextRealGrid() { QMetaObject::invokeMethod(mGuiPtr->getWindow(), "nextRealGrid" ); }
+void Gui::nextVec3Grid() { QMetaObject::invokeMethod(mGuiPtr->getWindow(), "nextVec3Grid" ); }
+void Gui::nextParts() { QMetaObject::invokeMethod(mGuiPtr->getWindow(), "nextParts" ); }
+void Gui::nextPdata() { QMetaObject::invokeMethod(mGuiPtr->getWindow(), "nextPdata" ); }
+void Gui::nextMesh() { QMetaObject::invokeMethod(mGuiPtr->getWindow(), "nextMesh" ); }
+
+void Gui::nextVec3Display() { QMetaObject::invokeMethod(mGuiPtr->getWindow(), "nextVec3Display" ); }
+void Gui::nextPartDisplay() { QMetaObject::invokeMethod(mGuiPtr->getWindow(), "nextPartDisplay" ); }
+void Gui::nextMeshDisplay() { QMetaObject::invokeMethod(mGuiPtr->getWindow(), "nextMeshDisplay" ); }
+
+PbClass* Gui::addControl(PbType t) {
+ _args.add("nocheck",true);
+ if (t.str() == "")
+ throw Error("Need to specify object type. Use e.g. gui.create(Slider, ...)");
+
+ PbClass* obj = PbClass::createPyObject(t.str(), "", _args, this);
+ if (!obj || !obj->canConvertTo("CustomControl"))
+ throw Error("gui.create() can only create CustomControl-based objects");
+
+ QMetaObject::invokeMethod(gGuiThread->getWindow(), "addControl", Q_ARG(void*, (void*)obj));
+
+ return obj;
+}
+
+
+} // namespace
+
+
diff --git a/source/blender/python/manta_pp/gui/customctrl.h b/source/blender/python/manta_pp/gui/customctrl.h
new file mode 100644
index 00000000000..8dcd2a6c885
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/customctrl.h
@@ -0,0 +1,148 @@
+
+
+
+
+
+// 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
+ *
+ * GUI extension from python
+ *
+ ******************************************************************************/
+
+#ifndef _CUSTOMCTRL_H__
+#define _CUSTOMCTRL_H__
+
+#include <QSlider>
+#include <QLabel>
+#include <QCheckBox>
+#include <QBoxLayout>
+#include "manta.h"
+
+namespace Manta {
+
+// fwd decl.
+class Mesh;
+class GuiThread;
+class MainThread;
+
+//! Interface for python declared controls
+class CustomControl : public PbClass {public:
+ CustomControl(); static int _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "CustomControl::CustomControl" ); { ArgLocker _lock; obj = new CustomControl(); obj->registerObject(_self, &_args); _args.check(); } pbFinalizePlugin(obj->getParent(),"CustomControl::CustomControl" ); return 0; } catch(std::exception& e) { pbSetError("CustomControl::CustomControl",e.what()); return -1; } }
+
+ virtual void init(QBoxLayout* layout) {};
+ protected: public: PbArgs _args;}
+#define _C_CustomControl
+;
+
+//! Checkbox with attached text display
+class TextCheckbox : public QCheckBox {
+ Q_OBJECT
+public:
+ TextCheckbox(const std::string& name, bool val);
+ void attach(QBoxLayout* layout);
+ void set(bool v);
+ bool get();
+
+public slots:
+ void update(int v);
+
+protected:
+ bool mVal;
+ QLabel* mLabel;
+ QString mSName;
+};
+
+//! Slider with attached text display
+class TextSlider : public QSlider {
+ Q_OBJECT
+public:
+ TextSlider(const std::string& name, float val, float min, float max);
+ void attach(QBoxLayout* layout);
+ void set(float v);
+ float get();
+
+public slots:
+ void update(int v);
+
+protected:
+ float mMin, mMax, mScale;
+ QLabel* mLabel;
+ QString mSName;
+};
+
+//! Links a slider control
+
+class CustomSlider : public CustomControl {public:
+ CustomSlider(std::string text, float val, float min, float max); static int _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "CustomSlider::CustomSlider" ); { ArgLocker _lock; std::string text = _args.get<std::string >("text",0,&_lock); float val = _args.get<float >("val",1,&_lock); float min = _args.get<float >("min",2,&_lock); float max = _args.get<float >("max",3,&_lock); obj = new CustomSlider(text,val,min,max); obj->registerObject(_self, &_args); _args.check(); } pbFinalizePlugin(obj->getParent(),"CustomSlider::CustomSlider" ); return 0; } catch(std::exception& e) { pbSetError("CustomSlider::CustomSlider",e.what()); return -1; } }
+ virtual void init(QBoxLayout* layout);
+
+ float get(); static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); CustomSlider* pbo = dynamic_cast<CustomSlider*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "CustomSlider::get"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->get()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"CustomSlider::get"); return _retval; } catch(std::exception& e) { pbSetError("CustomSlider::get",e.what()); return 0; } }
+ void set(float v); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); CustomSlider* pbo = dynamic_cast<CustomSlider*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "CustomSlider::set"); PyObject *_retval = 0; { ArgLocker _lock; float v = _args.get<float >("v",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->set(v); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"CustomSlider::set"); return _retval; } catch(std::exception& e) { pbSetError("CustomSlider::set",e.what()); return 0; } }
+
+protected:
+ float mMin, mMax, mVal;
+ std::string mSName; TextSlider* mSlider; public: PbArgs _args;}
+#define _C_CustomSlider
+;
+
+//! Links a checkbox control
+
+class CustomCheckbox : public CustomControl {public:
+ CustomCheckbox(std::string text, bool val); static int _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "CustomCheckbox::CustomCheckbox" ); { ArgLocker _lock; std::string text = _args.get<std::string >("text",0,&_lock); bool val = _args.get<bool >("val",1,&_lock); obj = new CustomCheckbox(text,val); obj->registerObject(_self, &_args); _args.check(); } pbFinalizePlugin(obj->getParent(),"CustomCheckbox::CustomCheckbox" ); return 0; } catch(std::exception& e) { pbSetError("CustomCheckbox::CustomCheckbox",e.what()); return -1; } }
+ virtual void init(QBoxLayout* layout);
+
+ bool get(); static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); CustomCheckbox* pbo = dynamic_cast<CustomCheckbox*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "CustomCheckbox::get"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->get()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"CustomCheckbox::get"); return _retval; } catch(std::exception& e) { pbSetError("CustomCheckbox::get",e.what()); return 0; } }
+ void set(bool v); static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); CustomCheckbox* pbo = dynamic_cast<CustomCheckbox*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "CustomCheckbox::set"); PyObject *_retval = 0; { ArgLocker _lock; bool v = _args.get<bool >("v",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->set(v); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"CustomCheckbox::set"); return _retval; } catch(std::exception& e) { pbSetError("CustomCheckbox::set",e.what()); return 0; } }
+
+protected:
+ bool mVal;
+ std::string mSName; TextCheckbox* mCheckbox; public: PbArgs _args;}
+#define _C_CustomCheckbox
+;
+
+
+//! GUI adapter class to call from Python
+class Gui : public PbClass {public:
+ Gui(); static int _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "Gui::Gui" ); { ArgLocker _lock; obj = new Gui(); obj->registerObject(_self, &_args); _args.check(); } pbFinalizePlugin(obj->getParent(),"Gui::Gui" ); return 0; } catch(std::exception& e) { pbSetError("Gui::Gui",e.what()); return -1; } }
+
+ void setBackgroundMesh(Mesh* m); static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::setBackgroundMesh"); PyObject *_retval = 0; { ArgLocker _lock; Mesh* m = _args.getPtr<Mesh >("m",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->setBackgroundMesh(m); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::setBackgroundMesh"); return _retval; } catch(std::exception& e) { pbSetError("Gui::setBackgroundMesh",e.what()); return 0; } }
+ void show(bool twoD=false); static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::show"); PyObject *_retval = 0; { ArgLocker _lock; bool twoD = _args.getOpt<bool >("twoD",0,false,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->show(twoD); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::show"); return _retval; } catch(std::exception& e) { pbSetError("Gui::show",e.what()); return 0; } }
+ void update(); static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::update"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->update(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::update"); return _retval; } catch(std::exception& e) { pbSetError("Gui::update",e.what()); return 0; } }
+ void pause(); static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::pause"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->pause(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::pause"); return _retval; } catch(std::exception& e) { pbSetError("Gui::pause",e.what()); return 0; } }
+ PbClass* addControl(PbType t); static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::addControl"); PyObject *_retval = 0; { ArgLocker _lock; PbType t = _args.get<PbType >("t",0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->addControl(t)); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::addControl"); return _retval; } catch(std::exception& e) { pbSetError("Gui::addControl",e.what()); return 0; } }
+ void screenshot(std::string filename); static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::screenshot"); PyObject *_retval = 0; { ArgLocker _lock; std::string filename = _args.get<std::string >("filename",0,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->screenshot(filename); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::screenshot"); return _retval; } catch(std::exception& e) { pbSetError("Gui::screenshot",e.what()); return 0; } }
+
+ // control display upon startup
+ void nextRealGrid(); static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::nextRealGrid"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->nextRealGrid(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::nextRealGrid"); return _retval; } catch(std::exception& e) { pbSetError("Gui::nextRealGrid",e.what()); return 0; } }
+ void nextVec3Grid(); static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::nextVec3Grid"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->nextVec3Grid(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::nextVec3Grid"); return _retval; } catch(std::exception& e) { pbSetError("Gui::nextVec3Grid",e.what()); return 0; } }
+ void nextParts(); static PyObject* _W_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::nextParts"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->nextParts(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::nextParts"); return _retval; } catch(std::exception& e) { pbSetError("Gui::nextParts",e.what()); return 0; } }
+ void nextPdata(); static PyObject* _W_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::nextPdata"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->nextPdata(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::nextPdata"); return _retval; } catch(std::exception& e) { pbSetError("Gui::nextPdata",e.what()); return 0; } }
+ void nextMesh(); static PyObject* _W_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::nextMesh"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->nextMesh(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::nextMesh"); return _retval; } catch(std::exception& e) { pbSetError("Gui::nextMesh",e.what()); return 0; } }
+ void nextVec3Display(); static PyObject* _W_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::nextVec3Display"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->nextVec3Display(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::nextVec3Display"); return _retval; } catch(std::exception& e) { pbSetError("Gui::nextVec3Display",e.what()); return 0; } }
+ void nextMeshDisplay(); static PyObject* _W_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::nextMeshDisplay"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->nextMeshDisplay(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::nextMeshDisplay"); return _retval; } catch(std::exception& e) { pbSetError("Gui::nextMeshDisplay",e.what()); return 0; } }
+ void nextPartDisplay(); static PyObject* _W_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Gui* pbo = dynamic_cast<Gui*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Gui::nextPartDisplay"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->nextPartDisplay(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Gui::nextPartDisplay"); return _retval; } catch(std::exception& e) { pbSetError("Gui::nextPartDisplay",e.what()); return 0; } }
+
+protected:
+ GuiThread* mGuiPtr; MainThread* mMainPtr; public: PbArgs _args;}
+#define _C_Gui
+;
+
+} // namespace
+
+#endif
+
+
+
diff --git a/source/blender/python/manta_pp/gui/customctrl.h.reg b/source/blender/python/manta_pp/gui/customctrl.h.reg
new file mode 100644
index 00000000000..cdf4d27668f
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/customctrl.h.reg
@@ -0,0 +1,31 @@
+#include "gui/customctrl.h"
++CustomControl^ static const Pb::Register _R_$IDX$ ("CustomControl","CustomControl","PbClass"); template<> const char* Namify<CustomControl >::S = "CustomControl";
+>CustomControl^
++CustomControl^ static const Pb::Register _R_$IDX$ ("CustomControl","CustomControl",CustomControl::_W_0);
++CustomSlider^ static const Pb::Register _R_$IDX$ ("CustomSlider","Slider","CustomControl"); template<> const char* Namify<CustomSlider >::S = "CustomSlider";
+>CustomSlider^
++CustomSlider^ static const Pb::Register _R_$IDX$ ("CustomSlider","CustomSlider",CustomSlider::_W_1);
++CustomSlider^ static const Pb::Register _R_$IDX$ ("CustomSlider","get",CustomSlider::_W_2);
++CustomSlider^ static const Pb::Register _R_$IDX$ ("CustomSlider","set",CustomSlider::_W_3);
++CustomCheckbox^ static const Pb::Register _R_$IDX$ ("CustomCheckbox","Checkbox","CustomControl"); template<> const char* Namify<CustomCheckbox >::S = "CustomCheckbox";
+>CustomCheckbox^
++CustomCheckbox^ static const Pb::Register _R_$IDX$ ("CustomCheckbox","CustomCheckbox",CustomCheckbox::_W_4);
++CustomCheckbox^ static const Pb::Register _R_$IDX$ ("CustomCheckbox","get",CustomCheckbox::_W_5);
++CustomCheckbox^ static const Pb::Register _R_$IDX$ ("CustomCheckbox","set",CustomCheckbox::_W_6);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","Gui","PbClass"); template<> const char* Namify<Gui >::S = "Gui";
+>Gui^
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","Gui",Gui::_W_7);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","setBackgroundMesh",Gui::_W_8);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","show",Gui::_W_9);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","update",Gui::_W_10);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","pause",Gui::_W_11);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","addControl",Gui::_W_12);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","screenshot",Gui::_W_13);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","nextRealGrid",Gui::_W_14);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","nextVec3Grid",Gui::_W_15);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","nextParts",Gui::_W_16);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","nextPdata",Gui::_W_17);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","nextMesh",Gui::_W_18);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","nextVec3Display",Gui::_W_19);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","nextMeshDisplay",Gui::_W_20);
++Gui^ static const Pb::Register _R_$IDX$ ("Gui","nextPartDisplay",Gui::_W_21);
diff --git a/source/blender/python/manta_pp/gui/customctrl.h.reg.cpp b/source/blender/python/manta_pp/gui/customctrl.h.reg.cpp
new file mode 100644
index 00000000000..060ae2e56a8
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/customctrl.h.reg.cpp
@@ -0,0 +1,48 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep link).
+
+
+
+
+#include "gui/customctrl.h"
+namespace Manta {
+#ifdef _C_CustomCheckbox
+ static const Pb::Register _R_0 ("CustomCheckbox","Checkbox","CustomControl"); template<> const char* Namify<CustomCheckbox >::S = "CustomCheckbox";
+ static const Pb::Register _R_1 ("CustomCheckbox","CustomCheckbox",CustomCheckbox::_W_4);
+ static const Pb::Register _R_2 ("CustomCheckbox","get",CustomCheckbox::_W_5);
+ static const Pb::Register _R_3 ("CustomCheckbox","set",CustomCheckbox::_W_6);
+#endif
+#ifdef _C_CustomControl
+ static const Pb::Register _R_4 ("CustomControl","CustomControl","PbClass"); template<> const char* Namify<CustomControl >::S = "CustomControl";
+ static const Pb::Register _R_5 ("CustomControl","CustomControl",CustomControl::_W_0);
+#endif
+#ifdef _C_CustomSlider
+ static const Pb::Register _R_6 ("CustomSlider","Slider","CustomControl"); template<> const char* Namify<CustomSlider >::S = "CustomSlider";
+ static const Pb::Register _R_7 ("CustomSlider","CustomSlider",CustomSlider::_W_1);
+ static const Pb::Register _R_8 ("CustomSlider","get",CustomSlider::_W_2);
+ static const Pb::Register _R_9 ("CustomSlider","set",CustomSlider::_W_3);
+#endif
+#ifdef _C_Gui
+ static const Pb::Register _R_10 ("Gui","Gui","PbClass"); template<> const char* Namify<Gui >::S = "Gui";
+ static const Pb::Register _R_11 ("Gui","Gui",Gui::_W_7);
+ static const Pb::Register _R_12 ("Gui","setBackgroundMesh",Gui::_W_8);
+ static const Pb::Register _R_13 ("Gui","show",Gui::_W_9);
+ static const Pb::Register _R_14 ("Gui","update",Gui::_W_10);
+ static const Pb::Register _R_15 ("Gui","pause",Gui::_W_11);
+ static const Pb::Register _R_16 ("Gui","addControl",Gui::_W_12);
+ static const Pb::Register _R_17 ("Gui","screenshot",Gui::_W_13);
+ static const Pb::Register _R_18 ("Gui","nextRealGrid",Gui::_W_14);
+ static const Pb::Register _R_19 ("Gui","nextVec3Grid",Gui::_W_15);
+ static const Pb::Register _R_20 ("Gui","nextParts",Gui::_W_16);
+ static const Pb::Register _R_21 ("Gui","nextPdata",Gui::_W_17);
+ static const Pb::Register _R_22 ("Gui","nextMesh",Gui::_W_18);
+ static const Pb::Register _R_23 ("Gui","nextVec3Display",Gui::_W_19);
+ static const Pb::Register _R_24 ("Gui","nextMeshDisplay",Gui::_W_20);
+ static const Pb::Register _R_25 ("Gui","nextPartDisplay",Gui::_W_21);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/gui/glwidget.cpp b/source/blender/python/manta_pp/gui/glwidget.cpp
new file mode 100644
index 00000000000..de9e7b32051
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/glwidget.cpp
@@ -0,0 +1,311 @@
+
+
+
+
+
+// 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
+ *
+ * QT OpenGL widget
+ *
+ ******************************************************************************/
+
+#include "glwidget.h"
+#ifdef __APPLE__
+# include <OpenGL/glu.h>
+#else
+# include <GL/glu.h>
+#endif
+#include <cmath>
+#include "painter.h"
+
+namespace Manta {
+
+GLWidget::GLWidget(QWidget* p): QGLWidget(QGLFormat(QGL::SampleBuffers), p), mRotX(0), mRotY(0), mGridsize(0), mScreenshotNumber(0)
+{
+ mPlaneDim = 2; // Y plane
+ mPlane = -1;
+ mCamPos = Vec3(0, 0, -2);
+ for (int i=0; i<MoveDirNum; i++)
+ mMoveState[i] = false;
+ mMoveFast = false;
+
+ setAutoBufferSwap(true);
+ setFocusPolicy(Qt::ClickFocus);
+ startTimer(10);
+}
+
+GLWidget::~GLWidget()
+{
+
+}
+
+QSize GLWidget::minimumSizeHint() const
+{
+ return QSize(400, 300);
+}
+
+QSize GLWidget::sizeHint() const
+{
+ return QSize(800, 600);
+}
+
+void GLWidget::initializeGL()
+{
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClearDepth(1.0);
+}
+
+void GLWidget::paintGL()
+{
+ if (mGridsize.max() == 0) return;
+ glDepthFunc(GL_ALWAYS);
+ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+ //glEnable(GL_POLYGON_OFFSET_FILL);
+ //glPolygonOffset(0,0);
+
+ // camera transform
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(mCamPos.x, mCamPos.y, mCamPos.z);
+ glRotatef(mRotX, 1.,0.,0.);
+ glRotatef(mRotY, 0.,1.,0.);
+ Real dx = 1.0 / (Real) mGridsize.max();
+ Vec3 sz = toVec3(mGridsize) * (-0.5f * dx);
+
+ glTranslatef(sz.x, sz.y, sz.z);
+ emit paintSub();
+}
+
+void GLWidget::resizeGL(int w, int h)
+{
+ glViewport(0, 0, (GLsizei) w, (GLsizei) h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ GLfloat fov = 45;
+ GLfloat zNear = 0.05f;
+ GLfloat zFar = 100.0f;
+ GLfloat aspect = float(w)/float(h);
+ GLfloat fH = tan( float(fov / 360.0f * M_PI) ) * zNear;
+ GLfloat fW = fH * aspect;
+ glFrustum( -fW, fW, -fH, fH, zNear, zFar );
+ glMatrixMode(GL_MODELVIEW);
+
+}
+
+void GLWidget::mouseReleaseEvent(QMouseEvent* event) {
+ // only do tooltip if not moving
+ QPoint pos = event->pos();
+ if ((mDownPos - pos).manhattanLength() == 0) {
+ // get GL transform matrices
+ int viewport[4];
+ GLdouble modelMatrix[16], projMatrix[16];
+ glGetDoublev(GL_MODELVIEW_MATRIX,modelMatrix);
+ glGetDoublev(GL_PROJECTION_MATRIX,projMatrix);
+ glGetIntegerv(GL_VIEWPORT,viewport);
+
+ // obtain click line
+ GLdouble line[6], wx=pos.x(), wy=viewport[3]-pos.y();
+ if (!gluUnProject(wx,wy,0,modelMatrix,projMatrix,viewport,&line[0],&line[1],&line[2])) return;
+ if (!gluUnProject(wx,wy,1.0,modelMatrix,projMatrix,viewport,&line[3],&line[4],&line[5])) return;
+
+ // calculate intersection with plane
+ emit clickLine(event->globalPos(), line[0],line[1],line[2],line[3],line[4],line[5]);
+ }
+}
+
+void GLWidget::mouseMoveEvent(QMouseEvent* e)
+{
+ const float speedRot = 0.2f, speedPan = 0.002f;
+
+ QPoint diff = e->pos() - mAnchor;
+ if (e->buttons() & Qt::LeftButton) {
+ mRotX += diff.y() * speedRot;
+ mRotY += diff.x() * speedRot;
+ updateGL();
+ }
+ if (e->buttons() & Qt::RightButton) {
+ mCamPos.x += diff.x() * speedPan;
+ mCamPos.y -= diff.y() * speedPan;
+ updateGL();
+ }
+
+ mAnchor = e->pos();
+}
+
+void GLWidget::mousePressEvent(QMouseEvent* e)
+{
+ mDownPos = mAnchor = e->pos();
+}
+
+void GLWidget::wheelEvent(QWheelEvent* e)
+{
+ const float speed = 0.002f;
+ mCamPos.z += speed*e->delta();
+ updateGL();
+}
+
+void GLWidget::timerEvent(QTimerEvent* e)
+{
+ bool doRepaint = false;
+
+ float speed = 0.005f;
+ if (mMoveFast) speed *= 5.;
+
+ if (mMoveState[MoveLeft]) { mCamPos.x += speed; doRepaint = true; }
+ if (mMoveState[MoveRight]) { mCamPos.x -= speed; doRepaint = true; }
+ if (mMoveState[MoveUp]) { mCamPos.y -= speed; doRepaint = true; }
+ if (mMoveState[MoveDown]) { mCamPos.y += speed; doRepaint = true; }
+ if (mMoveState[MoveOut]) { mCamPos.z -= speed; doRepaint = true; }
+ if (mMoveState[MoveIn]) { mCamPos.z += speed; doRepaint = true; }
+ if (doRepaint)
+ updateGL();
+}
+
+void GLWidget::setViewport(const Vec3i& gridsize) {
+ if (mGridsize.x != gridsize.x ||
+ mGridsize.y != gridsize.y ||
+ mGridsize.z != gridsize.z) {
+ if (mPlane < 0) {
+ mPlane = gridsize[mPlaneDim] / 2;
+ } else {
+ Real fac = (Real)gridsize[mPlaneDim] / (Real)mGridsize[mPlaneDim];
+ mPlane = (int)(fac * mPlane);
+ }
+ mGridsize = gridsize;
+ emit painterEvent(Painter::EventSetMax, mGridsize[mPlaneDim]);
+ emit painterEvent(Painter::EventSetPlane, mPlane);
+ }
+}
+
+void GLWidget::keyPressEvent(QKeyEvent* e)
+{
+ if(!keyProcess(e->key(), e->modifiers(), true))
+ QGLWidget::keyPressEvent(e);
+ else
+ updateGL();
+}
+
+void GLWidget::keyReleaseEvent(QKeyEvent* e)
+{
+ if(!keyProcess(e->key(), e->modifiers(), false))
+ QGLWidget::keyReleaseEvent(e);
+ else
+ updateGL();
+}
+
+bool GLWidget::keyProcess(int key, int modifier, bool down)
+{
+ bool shift = (modifier & Qt::ShiftModifier);
+ bool alt = (modifier & Qt::AltModifier);
+ bool ctrl = (modifier & Qt::ControlModifier);
+ if (key == Qt::Key_A) { mMoveState[MoveLeft] = down; mMoveFast = shift; }
+ else if (key == Qt::Key_D) { mMoveState[MoveRight] = down; mMoveFast = shift; }
+ else if (key == Qt::Key_W) { mMoveState[MoveUp] = down; mMoveFast = shift; }
+ else if (key == Qt::Key_S) { mMoveState[MoveDown] = down; mMoveFast = shift; }
+ else if (key == Qt::Key_Q) { mMoveState[MoveIn] = down; mMoveFast = shift; }
+ else if (key == Qt::Key_E) { mMoveState[MoveOut] = down; mMoveFast = shift; }
+ else if (down)
+ {
+ // only press events
+ // note Key_P and Key_L used for play/step in mainwindow.cpp
+ if (key == Qt::Key_Z) { /* next "solver" info sometime? */ }
+ else if (key == Qt::Key_G) { emit painterEvent(Painter::EventToggleGridDisplay); }
+ // data grids, first int
+ else if (key == Qt::Key_X && shift) { /* int display mdoes, not yet used */ }
+ else if (key == Qt::Key_X) { emit painterEvent(Painter::EventNextInt); updatePlane(mPlane); }
+ // real
+ else if (key == Qt::Key_C && shift) { emit painterEvent(Painter::EventNextRealDisplayMode); /* real display modes */ }
+ else if (key == Qt::Key_C) { emit painterEvent(Painter::EventNextReal); updatePlane(mPlane); }
+ else if ((key == Qt::Key_Less) ||
+ (key == Qt::Key_Comma) ) { emit painterEvent(Painter::EventScaleRealDown); }
+ else if ((key == Qt::Key_Greater) ||
+ (key == Qt::Key_Period) ) { emit painterEvent(Painter::EventScaleRealUp); }
+
+ // vec3 grids, scaling can be used with two key combinations (the second one is for international keyboards)
+ else if (key == Qt::Key_V && shift) { emit painterEvent(Painter::EventNextVecDisplayMode); }
+ else if (key == Qt::Key_V) { emit painterEvent(Painter::EventNextVec); updatePlane(mPlane); }
+ // grid scaling
+ else if (key == Qt::Key_Semicolon) { emit painterEvent(Painter::EventScaleVecDown); }
+ else if (key == Qt::Key_Apostrophe) { emit painterEvent(Painter::EventScaleVecUp); }
+
+ // particles
+ else if (key == Qt::Key_B && shift) { emit painterEvent(Painter::EventNextParticleDisplayMode); }
+ else if (key == Qt::Key_B && alt) { emit painterEvent(Painter::EventNextSystem); }
+ else if (key == Qt::Key_B) { emit painterEvent(Painter::EventToggleParticles); }
+
+ else if((key == Qt::Key_ParenLeft) || // a bit ugly, but for some reason parentheses dont work in some cases... fall back with dual assignment
+ (key == Qt::Key_9) ) { emit painterEvent(Painter::EventScalePdataDown); }
+ else if((key == Qt::Key_ParenRight) ||
+ (key == Qt::Key_0) ) { emit painterEvent(Painter::EventScalePdataUp); }
+
+ // mesh display
+ else if (key == Qt::Key_M && shift) emit painterEvent(Painter::EventMeshMode);
+ else if (key == Qt::Key_BraceLeft ) { emit painterEvent(Painter::EventScaleMeshDown); }
+ else if (key == Qt::Key_BracketLeft) { emit painterEvent(Painter::EventScaleMeshDown); }
+ else if (key == Qt::Key_BraceRight) { emit painterEvent(Painter::EventScaleMeshUp); }
+ else if (key == Qt::Key_BracketRight) { emit painterEvent(Painter::EventScaleMeshUp); }
+ // special mesh display modes
+ else if (key == Qt::Key_M && alt) emit painterEvent(Painter::EventMeshColorMode);
+ else if (key == Qt::Key_M && ctrl) emit painterEvent(Painter::EventToggleBackgroundMesh);
+ else if (key == Qt::Key_M) emit painterEvent(Painter::EventNextMesh);
+
+ // switch display planes
+ else if ( (key == Qt::Key_Asterisk) || (key == Qt::Key_8) ) {
+ mPlaneDim = (mPlaneDim+1) % 3;
+ emit painterEvent(Painter::EventSetDim, mPlaneDim);
+ emit painterEvent(Painter::EventSetMax, mGridsize[mPlaneDim]);
+ }
+ // move plane (+shift is faster)
+ else if (shift && ((key == Qt::Key_Plus) || (key == Qt::Key_Equal)) ) {
+ updatePlane(mPlane + 10);
+ } else if (shift && ((key == Qt::Key_Minus) || (key == Qt::Key_Underscore)) ) {
+ updatePlane(mPlane - 10);
+ } else if (key == Qt::Key_Plus || key == Qt::Key_Equal) {
+ updatePlane(mPlane + 1);
+ } else if (key == Qt::Key_Minus) {
+ updatePlane(mPlane - 1);
+ }
+ else if ( key == Qt::Key_K) {
+ QString filename = QString("scr_%1.png").arg(QString::number(mScreenshotNumber), 3, QChar('0'));
+ screenshot(filename);
+ mScreenshotNumber++;
+ }
+
+ else return false;
+ }
+ else return false;
+ return true;
+}
+
+void GLWidget::screenshot(QString file) {
+ grabFrameBuffer().save(file);
+}
+
+void GLWidget::updatePlane(int plane) {
+ mPlane = clamp(plane, 0, mGridsize[mPlaneDim]);
+ emit painterEvent(Painter::EventSetPlane, mPlane);
+}
+
+
+
+}
+
+
diff --git a/source/blender/python/manta_pp/gui/glwidget.h b/source/blender/python/manta_pp/gui/glwidget.h
new file mode 100644
index 00000000000..ee034c317b1
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/glwidget.h
@@ -0,0 +1,87 @@
+
+
+
+
+
+// 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
+ *
+ * QT OpenGL widget
+ *
+ ******************************************************************************/
+
+#ifndef _GLWIDGET_H__
+#define _GLWIDGET_H__
+
+#include <QGLWidget>
+#include <QtOpenGL>
+#include "vectorbase.h"
+
+namespace Manta {
+
+class GLWidget : public QGLWidget {
+Q_OBJECT
+
+public:
+ GLWidget(QWidget *parent = NULL);
+ ~GLWidget();
+
+ QSize minimumSizeHint() const;
+ QSize sizeHint() const;
+
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void wheelEvent(QWheelEvent *e);
+ void screenshot(QString file);
+
+ void setCamPos(Vec3 pos) { mCamPos = pos; }
+
+public slots:
+ void setViewport(const Vec3i& gridsize);
+ void keyPressEvent(QKeyEvent* e);
+ void keyReleaseEvent(QKeyEvent* e);
+
+signals:
+ void paintSub();
+ void clickLine(QPoint pos, float p0, float p1,float p2, float q0, float q1, float q2);
+ void painterEvent(int e, int param=0);
+
+protected:
+ bool keyProcess(int key, int mod, bool down);
+ void timerEvent(QTimerEvent* e);
+ void initializeGL();
+ void resizeGL(int w, int h);
+ void paintGL();
+ void updatePlane(int plane);
+
+ enum MoveDir { None = 0, MoveLeft, MoveRight, MoveUp, MoveDown, MoveIn, MoveOut, MoveDirNum };
+
+ bool mMoveState[MoveDirNum];
+ bool mMoveFast;
+ QPoint mAnchor, mDownPos;
+ Vec3 mCamPos;
+ float mRotX, mRotY;
+ Vec3i mGridsize;
+ int mPlaneDim, mPlane;
+
+ int mScreenshotNumber;
+};
+
+} // namespace
+
+#endif
+
+
diff --git a/source/blender/python/manta_pp/gui/glwidget.h.reg b/source/blender/python/manta_pp/gui/glwidget.h.reg
new file mode 100644
index 00000000000..d0d8ed4b59d
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/glwidget.h.reg
@@ -0,0 +1 @@
+#include "gui/glwidget.h"
diff --git a/source/blender/python/manta_pp/gui/glwidget.h.reg.cpp b/source/blender/python/manta_pp/gui/glwidget.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/glwidget.h.reg.cpp
diff --git a/source/blender/python/manta_pp/gui/mainwindow.cpp b/source/blender/python/manta_pp/gui/mainwindow.cpp
new file mode 100644
index 00000000000..62d2f69f376
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/mainwindow.cpp
@@ -0,0 +1,318 @@
+
+
+
+
+
+// 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
+ *
+ * QT main window
+ *
+ ******************************************************************************/
+
+#include "mainwindow.h"
+#include "qtmain.h"
+
+#include <QLabel>
+#include <QMenu>
+#include <QMenuBar>
+#include <QAction>
+#include <QtOpenGL>
+#include <sstream>
+#include "meshpainter.h"
+#include "particlepainter.h"
+
+using namespace std;
+
+namespace Manta {
+
+MainWnd::MainWnd() : QMainWindow(0), mPaused(true), mRequestPause(false), mRequestClose(false), mStep(0),
+ mKbwScene(0), mKbwView(0), mKbwPixmap(0), mMenuBar(0)
+{
+ // Frame info label
+ mInfo = new QLabel;
+ setStep(0);
+
+ // register GL widget
+ mGlWidget = new GLWidget();
+ setCentralWidget(mGlWidget);
+ connect(mGlWidget, SIGNAL(clickLine(QPoint,float,float,float,float,float,float)), SLOT(clickLine(QPoint,float,float,float,float,float,float)));
+
+ // register grid painters
+ mPainterLayout = new QVBoxLayout;
+ mPainterLayout->setAlignment(Qt::AlignTop);
+ mPainterLayout->addWidget(mInfo);
+ GridPainter<int>* intPainter = new GridPainter<int>(NULL, this);
+ mPainter.push_back(new GridPainter<Real>((FlagGrid**)intPainter->getGridPtr(), this));
+ mPainter.push_back(new GridPainter<Vec3>(NULL, this));
+ mPainter.push_back(intPainter);
+ mPainter.push_back(new ParticlePainter(intPainter, this));
+ MeshPainter* ptr = new MeshPainter(this);
+ mPainter.push_back(ptr);
+ connect(this, SIGNAL(setBackgroundMesh(Mesh*)), ptr, SLOT(setBackgroundMesh(Mesh*)));
+
+ for (int i=0; i<(int)mPainter.size(); i++) {
+ connect(mGlWidget, SIGNAL(paintSub()), mPainter[i], SLOT(paint()));
+ connect(mGlWidget, SIGNAL(painterEvent(int, int)), mPainter[i], SLOT(doEvent(int, int)));
+ connect(this, SIGNAL(painterEvent(int, int)), mPainter[i], SLOT(doEvent(int, int)));
+ connect(mPainter[i], SIGNAL(setViewport(const Vec3i&)), mGlWidget, SLOT(setViewport(const Vec3i&)));
+ mPainter[i]->attachWidget(mPainterLayout);
+ }
+
+ // docking widget for painters
+ QDockWidget* painterDock = new QDockWidget("Info", this);
+ QWidget* painterProxy = new QWidget;
+ painterProxy->setLayout(mPainterLayout);
+ painterDock->setWidget(painterProxy);
+ painterDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
+ addDockWidget(Qt::RightDockWidgetArea, painterDock);
+
+ // Top toolbar
+ QToolBar* toolbar = addToolBar("Control");
+ toolbar->setAllowedAreas(Qt::TopToolBarArea);
+ toolbar->setMovable(false);
+ mAcPlay = toolbar->addAction(QIcon(":/play.png"),"Play");
+ mAcPlay->setStatusTip("Continue simulation");
+ connect(mAcPlay, SIGNAL(triggered()), SLOT(play()));
+ mAcPause = toolbar->addAction(QIcon(":/pause.png"),"Pause");
+ mAcPause->setStatusTip("Pause simulation");
+ connect(mAcPause, SIGNAL(triggered()), SLOT(pause()));
+ emit play();
+
+ // build menu
+ /*QAction* a = new QAction(this);
+ a->setText( "Quit" );
+ connect(a, SIGNAL(triggered()), SLOT(close()) );
+ mMenuBar = menuBar()->addMenu( "File" );
+ mMenuBar->addAction( a ); */
+
+ // keyboard info window, show on demand
+ mKbwScene = new QGraphicsScene();
+ mKbwView = new QGraphicsView(mKbwScene);
+ mKbwPixmap = new QGraphicsPixmapItem(QPixmap(":/keyboard.png"));
+ mKbwScene->addItem(mKbwPixmap);
+ mKbwView->hide();
+
+ mAcHelp = toolbar->addAction(QIcon(":/help.png"),"Help");
+ mAcHelp->setStatusTip("Help");
+ connect(mAcHelp, SIGNAL(triggered()), SLOT(showHelp()));
+
+ // start...
+ mGlWidget->setFocus();
+ this->raise();
+ this->activateWindow();
+
+ /*
+ // MLE 2014-07-05 added
+ // move gui window to upper left corner and resize window to screen size
+ QRect rc = frameGeometry();
+ QRect rcDesktop = QApplication::desktop()->frameGeometry();
+ rc.setLeft(rcDesktop.left());
+ rc.setTop(rcDesktop.top());
+ rc.setRight(rcDesktop.right());
+ rc.setBottom(rcDesktop.bottom());
+ move(rc.topLeft());
+ resize(rc.size());
+ */
+
+ // uncomment to start paused
+ //emit pause();
+}
+
+void MainWnd::clickLine(QPoint pos, float p0, float p1,float p2, float q0, float q1, float q2) {
+ string msg;
+ for (int i=mPainter.size()-1; i>=0; i--) {
+ msg += mPainter[i]->clickLine(Vec3(p0,p1,p2),Vec3(q0,q1,q2));
+ }
+ if (!msg.empty())
+ QToolTip::showText(pos, QString(msg.c_str()));
+}
+
+void MainWnd::addControl(void* ctrl) {
+ CustomControl* control = (CustomControl*) ctrl;
+ mCtrls.push_back(control);
+ control->init(mPainterLayout);
+}
+
+void MainWnd::setStep(int f) {
+ std::stringstream s;
+ s << "Simulation step " << f;
+ mInfo->setText(s.str().c_str());
+}
+
+void MainWnd::setPauseStatus(bool v)
+{
+ mPaused = v;
+}
+
+bool MainWnd::event(QEvent* e) {
+ if (e->type() == (QEvent::Type)EventGuiShow) {
+ if (!mRequestClose) {
+ this->show();
+ emit painterEvent(Painter::UpdateFull);
+ mGlWidget->updateGL();
+ }
+ emit wakeMain();
+ return true;
+ }
+ else if (e->type() == (QEvent::Type)EventFullUpdate) {
+ if (!mRequestClose) {
+ emit painterEvent(Painter::UpdateFull);
+ mGlWidget->updateGL();
+ }
+ emit wakeMain();
+ return true;
+ }
+ else if (e->type() == (QEvent::Type)EventStepUpdate) {
+ if (!mRequestClose) {
+ if (mRequestPause)
+ emit painterEvent(Painter::UpdateFull);
+ else
+ emit painterEvent(Painter::UpdateStep);
+ mGlWidget->updateGL();
+ }
+ emit wakeMain();
+ return true;
+ }
+ else if (e->type() == (QEvent::Type)EventFinalUpdate) {
+ if (!mRequestClose) {
+ emit painterEvent(Painter::UpdateFull);
+ mGlWidget->updateGL();
+ }
+ mRequestClose = true;
+ emit wakeMain();
+ return true;
+ }
+ else if (e->type() == (QEvent::Type)EventSet2DCam) {
+ mGlWidget->setCamPos( Vec3(0, 0, -1.3) );
+ return true;
+ }
+ else if (e->type() == (QEvent::Type)EventInstantKill) {
+ emit killMain();
+ emit exitApp();
+ return true;
+ }
+
+ // update button states for pause events
+ if( (mRequestPause) && (!mAcPlay->isEnabled()) ) {
+ mAcPlay->setEnabled(true);
+ mAcPause->setEnabled(false);
+ }
+ if( (mRequestPause) && (!mAcPlay->isEnabled()) ) {
+ mAcPlay->setEnabled(true);
+ mAcPause->setEnabled(false);
+ }
+
+ return QMainWindow::event(e);
+}
+
+void MainWnd::keyPressEvent(QKeyEvent* e) {
+ if (e->key() == Qt::Key_Escape) {
+ mRequestClose = true;
+ emit killMain();
+ this->close();
+ } else if (e->key() == Qt::Key_Space) {
+ if (mRequestClose) {
+ emit killMain();
+ this->close();
+ } else {
+ emit painterEvent(mPaused ? Painter::UpdateFull : Painter::UpdateRequest);
+ mGlWidget->updateGL();
+ }
+ } else if (e->key() == Qt::Key_P) {
+ if (mRequestClose) {
+ emit killMain();
+ this->close();
+ } else if (mRequestPause)
+ emit play();
+ else
+ emit pause();
+ } else if (e->key() == Qt::Key_L) {
+ if (mRequestClose) {
+ emit killMain();
+ this->close();
+ } else if (mRequestPause) {
+ mRequestPause = false;
+ mStep = (e->modifiers() & Qt::ShiftModifier) ? 1 : 2;
+ } else
+ emit pause();
+ } else if (e->key() == Qt::Key_H) {
+ emit showHelp();
+ } else {
+ mGlWidget->keyPressEvent(e); // let gl widget take care of keyboard shortcuts
+ //QMainWindow::keyPressEvent(e);
+ }
+}
+void MainWnd::keyReleaseEvent(QKeyEvent* e)
+{
+ mGlWidget->keyReleaseEvent(e);
+}
+
+void MainWnd::pause() {
+ mRequestPause = true;
+ // dont call: mAcPlay/mAcPause ->setEnabled(true) here; wrong thread if called from python
+}
+
+void MainWnd::play() {
+ mRequestPause = false;
+ mAcPlay->setEnabled(false);
+ mAcPause->setEnabled(true);
+}
+
+void MainWnd::step() {
+ mStep = 2;
+ mRequestPause = false;
+}
+
+void MainWnd::showHelp() {
+ mKbwView->show();
+}
+
+void MainWnd::nextRealGrid() {
+ emit painterEvent(Painter::EventNextReal);
+}
+void MainWnd::nextVec3Grid() {
+ emit painterEvent(Painter::EventNextVec);
+}
+void MainWnd::nextMesh() {
+ emit painterEvent(Painter::EventNextMesh);
+}
+void MainWnd::nextParts() {
+ emit painterEvent(Painter::EventNextSystem);
+}
+void MainWnd::nextPdata() {
+ emit painterEvent(Painter::EventToggleParticles);
+}
+void MainWnd::nextVec3Display() {
+ emit painterEvent(Painter::EventNextVecDisplayMode);
+}
+void MainWnd::nextPartDisplay() {
+ emit painterEvent(Painter::EventNextParticleDisplayMode);
+}
+void MainWnd::nextMeshDisplay() {
+ emit painterEvent(Painter::EventMeshMode);
+}
+
+MainWnd::~MainWnd() {
+}
+
+void MainWnd::screenshot(QString file) {
+ mGlWidget->screenshot(file);
+}
+
+
+}
+
+
diff --git a/source/blender/python/manta_pp/gui/mainwindow.h b/source/blender/python/manta_pp/gui/mainwindow.h
new file mode 100644
index 00000000000..a760461b4b7
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/mainwindow.h
@@ -0,0 +1,106 @@
+
+
+
+
+
+// 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
+ *
+ * QT main window
+ *
+ ******************************************************************************/
+
+#ifndef _MAINWINDOW_H_
+#define _MAINWINDOW_H_
+
+#include <QMainWindow>
+#include <QMenuBar>
+#include "glwidget.h"
+#include "customctrl.h"
+#include "painter.h"
+#include <vector>
+
+namespace Manta {
+class Mesh;
+
+class MainWnd : public QMainWindow
+{
+Q_OBJECT
+public:
+ enum EventType { EventFullUpdate = QEvent::User, EventGuiShow,
+ EventStepUpdate, EventFinalUpdate, EventInstantKill, EventSet2DCam };
+
+ MainWnd();
+ virtual ~MainWnd();
+ bool event(QEvent* e);
+ void keyPressEvent(QKeyEvent* e);
+ void keyReleaseEvent(QKeyEvent* e);
+ inline bool pauseRequest() { return mRequestPause && !mRequestClose; }
+ inline bool closeRequest() { return mRequestClose; }
+ void setPauseStatus(bool v);
+ void stepReset(bool fullUpdate) { if (mStep == 1 || (mStep == 2 && fullUpdate)) {mRequestPause = true; mStep = 0;} }
+ void requestClose() { mRequestClose =true; }
+ void setStep(int f);
+ void setBackground(Mesh *m) { emit setBackgroundMesh(m); }
+
+public slots:
+ void pause();
+ void play();
+ void step();
+ void showHelp();
+ void addControl(void* ctrl);
+ void screenshot(QString file);
+ void clickLine(QPoint pos, float p0, float p1,float p2, float q0, float q1, float q2);
+
+ void nextRealGrid();
+ void nextVec3Grid();
+ void nextMesh();
+ void nextParts();
+ void nextPdata();
+ void nextVec3Display();
+ void nextPartDisplay();
+ void nextMeshDisplay();
+
+signals:
+ void painterEvent(int e, int param=0);
+ void wakeMain();
+ void setBackgroundMesh(Mesh* bgr);
+ void killMain();
+ void exitApp();
+
+protected:
+ bool mPaused, mRequestPause, mRequestClose;
+ int mStep;
+ GLWidget *mGlWidget;
+ QAction *mAcPlay, *mAcPause;
+ std::vector<Painter*> mPainter;
+ std::vector<CustomControl*> mCtrls;
+ QLabel* mInfo;
+ QVBoxLayout* mPainterLayout;
+
+ // keyboard info window
+ QAction *mAcHelp;
+ QGraphicsScene *mKbwScene;
+ QGraphicsView *mKbwView;
+ QGraphicsPixmapItem *mKbwPixmap;
+
+ QMenu *mMenuBar;
+};
+
+}
+
+#endif
+
+
diff --git a/source/blender/python/manta_pp/gui/mainwindow.h.reg b/source/blender/python/manta_pp/gui/mainwindow.h.reg
new file mode 100644
index 00000000000..b71e6628a99
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/mainwindow.h.reg
@@ -0,0 +1 @@
+#include "gui/mainwindow.h"
diff --git a/source/blender/python/manta_pp/gui/mainwindow.h.reg.cpp b/source/blender/python/manta_pp/gui/mainwindow.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/mainwindow.h.reg.cpp
diff --git a/source/blender/python/manta_pp/gui/meshpainter.cpp b/source/blender/python/manta_pp/gui/meshpainter.cpp
new file mode 100644
index 00000000000..5f04cbc7152
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/meshpainter.cpp
@@ -0,0 +1,313 @@
+
+
+
+
+
+// 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
+ *
+ * Painting mesh objects
+ *
+ ******************************************************************************/
+
+#include "meshpainter.h"
+#include <QtOpenGL>
+#include "mesh.h"
+#include "vortexsheet.h"
+
+using namespace std;
+
+namespace Manta {
+
+MeshPainter::MeshPainter(QWidget* par)
+ : LockedObjPainter(par), mColorScale(1.0), mMode(ModeFlatShade), mVorticityMode(VModeNone),
+ mBackgroundMode(BModeNormal), mLocalMesh(0) , mBackground(0), mHide(false)
+{
+ mInfo = new QLabel();
+}
+
+MeshPainter::~MeshPainter() {
+ if (mLocalMesh)
+ delete mLocalMesh;
+}
+
+void MeshPainter::attachWidget(QLayout* layout) {
+ layout->addWidget(mInfo);
+}
+
+void MeshPainter::update() {
+ Mesh* src = (Mesh*) mObject;
+
+ // always reallocate
+ if (mLocalMesh)
+ delete mLocalMesh;
+
+ mLocalMesh = src->clone();
+
+ updateText();
+}
+
+string MeshPainter::getID() { return "Mesh"; }
+
+
+void MeshPainter::processKeyEvent(PainterEvent e, int param)
+{
+ if (e == EventNextMesh)
+ nextObject();
+ else if (e == EventMeshMode)
+ mMode = (DisplayMode) ((mMode+1) % (int)Num_DisplayModes);
+ else if (e == EventScaleMeshUp)
+ mColorScale *= 2.0;
+ else if (e == EventScaleMeshDown)
+ mColorScale /= 2.0;
+ else if (e == EventMeshColorMode)
+ mVorticityMode = (VorticityMode) ((mVorticityMode+1)%(int)Num_VorticityModes);
+ else if (e == EventToggleBackgroundMesh)
+ mBackgroundMode = (BackgroundMode) ((mBackgroundMode+1)%(int)Num_BackgroundModes);
+ else return;
+
+ updateText();
+}
+
+void MeshPainter::updateText() {
+ stringstream s;
+
+ if ( mObject && !mHide && mLocalMesh ) {
+ s << "Mesh '" << mLocalMesh->getName() << "' [" << mLocalMesh->numTris() << " tris]" << endl;
+ if (mMode == ModeFlatShade) s << "DisplayMode: Flatshade" << endl;
+ if (mMode == ModeInvisible) s << "DisplayMode: Invisible" << endl;
+ if (mMode == ModeLines) s << "DisplayMode: Wireframe" << endl;
+ if (mMode == ModePoints) s << "DisplayMode: Pointset" << endl;
+ if (mMode == ModeTrans) s << "DisplayMode: Semi-Transparent" << endl;
+ if (mLocalMesh->getType() == Mesh::TypeVortexSheet) {
+ if (mVorticityMode==VModeFull) s << "Vorticity: full" << endl;
+ if (mVorticityMode==VModeSmoothed) s << "Vorticity: gauss smooth" << endl;
+ if (mVorticityMode==VModeDiff) s << "Vorticity: gauss diff" << endl;
+ if (mVorticityMode==VModeSmoke) s << "Smoke Density" << endl;
+ if (mVorticityMode==VModeTex) s << "Texture coordinates 0" << endl;
+ if (mVorticityMode!=VModeNone) s << " Scale " << 1.0/mColorScale << "" << endl;
+ }
+ }
+ mInfo->setText(s.str().c_str());
+}
+
+void MeshPainter::setBackgroundMesh(Mesh* bgr) {
+ mBackground = bgr;
+}
+
+void MeshPainter::setupLights(bool specular) {
+ // control colors
+ float max = 1.0;
+ float dim = 0.5;
+ float dims = specular ? dim : 0;
+ float maxs = specular ? max : 0;
+ float amb = 0.1;
+ float shininess = 50.;
+ dim = 0.5; max = 0.75; amb = 0.25;
+
+ float ambient0[] = {amb, amb, amb, max};
+ glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);
+
+ float diffuse0[] = {max, dim, dim, 1.0};
+ float specular0[] = {maxs, dims, dims, 1.0};
+ float position0[] = { 5., 5., 5., 1.0f };
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);
+ glLightfv(GL_LIGHT0, GL_SPECULAR, specular0);
+ glLightfv(GL_LIGHT0, GL_POSITION, position0);
+
+ float diffuse1[] = {dim, max, dim, 1.0};
+ float specular1[] = {dims, maxs, dims, 1.0};
+ float position1[] = { 5., -5., -5., 1.0f };
+ glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1);
+ glLightfv(GL_LIGHT1, GL_SPECULAR, specular1);
+ glLightfv(GL_LIGHT1, GL_POSITION, position1);
+
+ float diffuse2[] = {dim, dim, max, 1.0};
+ float specular2[] = {dims, dims, maxs, 1.0};
+ float position2[] = { 0.3, 2., -10., 1.0f };
+ glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuse2);
+ glLightfv(GL_LIGHT2, GL_SPECULAR, specular2);
+ glLightfv(GL_LIGHT2, GL_POSITION, position2);
+
+ float specReflection[] = { dims, dims, dims, 1.0f };
+ if(shininess == 0.) specReflection[0] = specReflection[1] = specReflection[2] = 0.;
+ glMaterialfv(GL_FRONT, GL_SPECULAR, specReflection);
+ glMateriali(GL_FRONT, GL_SHININESS, shininess);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_LIGHT1);
+ glEnable(GL_LIGHT2);
+}
+
+//static inline void glColor(const Vec3& color) {
+ //glColor3f(std::max(_0,std::min(_1,color.x)), std::max(_0,std::min(_1,color.y)), std::max(_0,std::min(_1,color.z)));
+//}
+
+static inline void glVertex(const Vec3& v, Real dx) {
+ glVertex3f(v.x * dx, v.y * dx, v.z * dx);
+}
+static inline void glNormal(const Vec3& v) {
+ glNormal3f(v.x, v.y, v.z);
+}
+
+void MeshPainter::paint() {
+ if (!mObject || mHide || !mLocalMesh) return;
+
+ Real dx = mLocalMesh->getParent()->getDx();
+
+ bool triColor = (mMode == ModeFlatShade) && (mLocalMesh->getType() == Mesh::TypeVortexSheet) && (mVorticityMode!=VModeNone);
+ bool nodeColor = (mLocalMesh->getType() == Mesh::TypeVortexSheet) && (mVorticityMode==VModeTex);
+
+ // setup OpenGL lighting and material
+ const float isoAlpha = 0.4;
+ setupLights(false);
+ glColorMaterial ( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ) ;
+ glEnable(GL_COLOR_MATERIAL);
+ glDepthFunc(GL_LESS);
+ //glDisable(GL_CULL_FACE);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+
+ // draw background
+ if (mBackground != NULL && mBackgroundMode != BModeInvisible) {
+ if (mBackgroundMode != BModeTrans) {
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+ glColor3f(0.3,0.3,0.5);
+ } else {
+ glEnable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ glColor4f(0.6,0.6,0.8,0.5);
+ }
+ glEnable(GL_CULL_FACE);
+ glPolygonOffset(1.0, 0.5);
+ glBegin(GL_TRIANGLES);
+
+ for(int tri=0; tri<mBackground->numTris(); tri++) {
+ Vec3 normal = mBackground->getFaceNormal(tri);
+ for (int c=0; c<3; c++) {
+ glNormal(normal);
+ glVertex(mBackground->getNode(tri,c), dx);
+ }
+ }
+ glEnd();
+ glPolygonOffset(1., 1.);
+ glDisable(GL_CULL_FACE);
+ }
+
+ setupLights(true);
+ if (mMode == ModeFlatShade) {
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+ } else {
+ glEnable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ }
+ if (triColor)
+ glDisable(GL_LIGHTING);
+
+ // draw triangles
+ if (mMode == ModeFlatShade || mMode == ModeTrans)
+ {
+ glEnable(GL_CULL_FACE);
+ glPolygonOffset(1.0, 0.5);
+ glBegin(GL_TRIANGLES);
+
+ const int numTris = (int)mLocalMesh->numTris();
+ for(int tri=0; tri<numTris; tri++) {
+ if (!nodeColor && triColor) {
+ VortexSheetInfo& info = ((VortexSheetMesh*)mLocalMesh)->sheet(tri);
+ Vec3 v = info.vorticity;
+ if (mVorticityMode == VModeSmoothed) v = info.vorticitySmoothed;
+ if (mVorticityMode == VModeDiff) v -= info.vorticitySmoothed;
+ if (mVorticityMode == VModeSmoke) v = info.smokeAmount / 20.0f;
+
+ Vec3 ca = v * 20.0 * mColorScale;
+ Vec3 color = Vec3(fabs(ca.x),fabs(ca.y),fabs(ca.z));
+ glColor3f(color.x, color.y, color.z);
+ } else if (mLocalMesh->isTriangleFixed(tri))
+ glColor3f(0,1,0);
+ else if (mLocalMesh->tris(tri).flags & Mesh::FfMarked)
+ glColor3f(1,0,0);
+ else
+ glColor4f(0.5,0.5,0.5, isoAlpha);
+
+ for (int c=0; c<3; c++) {
+ if (nodeColor) {
+ Vec3 tc = ((VortexSheetMesh*)mLocalMesh)->tex1(mLocalMesh->tris(tri).c[c]);
+ //Vec3 tc2 = ((VortexSheetMesh*)mLocalMesh)->tex2(mLocalMesh->tris(tri).c[c]);
+ //Vec3 tc = gAlpha*tc1+(1-gAlpha)*tc2;
+ tc = mColorScale * (tc / toVec3(mLocalMesh->getParent()->getGridSize()));
+ tc = nmod(tc, Vec3(1,1,1));
+ glColor3f(tc.x, tc.y ,tc.z);
+ }
+ glNormal(mLocalMesh->getFaceNormal(tri));
+ glVertex(mLocalMesh->getNode(tri,c), dx);
+ }
+ }
+ glEnd();
+ glPolygonOffset(1., 1.);
+ glDisable(GL_CULL_FACE);
+ }
+
+ // Disable light setup
+ glDisable(GL_BLEND);
+ glDisable(GL_LIGHT0);
+ glDisable(GL_LIGHT1);
+ glDisable(GL_LIGHT2);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glDisable(GL_TEXTURE_2D);
+
+ // draw mesh lines
+ if(mMode == ModeLines) {
+ glColor3d(1.0, 0.9, 0.9);
+ glLineWidth(1.0);
+ glBegin(GL_LINES);
+ const int numTris = (int)mLocalMesh->numTris();
+ for(int tri=0; tri<numTris; tri++)
+ for (int j=5; j<5+6; j++)
+ glVertex( mLocalMesh->getNode(tri,(j/2)%3), dx);
+ glEnd();
+ }
+
+ // draw vertex points
+ if(mMode == ModePoints) {
+ static const Vec3 colorSpecial (0.3, 0.5, 0.2);
+ //static const Vec3 colortable[] = { Vec3(0.5), Vec3(1,0,0), Vec3(0,1,0), Vec3(0,0,1) };
+
+ glPointSize(2.0);
+ glBegin(GL_POINTS);
+ const int numNodes = (int)mLocalMesh->numNodes();
+ for(int i=0; i<numNodes; i++) {
+ Vec3 color(0.5, 0.5, 0.5);
+ if (mLocalMesh->isNodeFixed(i))
+ color = Vec3(0,1,0);
+ else if (mLocalMesh->nodes(i).flags & Mesh::NfMarked)
+ color = Vec3(1,0,0);
+ //int flags = mLocalMesh->flags(i);
+
+ glColor3f(color.x, color.y, color.z);
+ glVertex(mLocalMesh->nodes(i).pos, dx);
+ }
+ glEnd();
+ glPointSize(1.0);
+ }
+}
+
+
+
+} // namespace
+
+
diff --git a/source/blender/python/manta_pp/gui/meshpainter.h b/source/blender/python/manta_pp/gui/meshpainter.h
new file mode 100644
index 00000000000..f11115c3c4f
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/meshpainter.h
@@ -0,0 +1,71 @@
+
+
+
+
+
+// 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
+ *
+ * Painting mesh objects
+ *
+ ******************************************************************************/
+
+#ifndef _MESHPAINTER_H_
+#define _MESHPAINTER_H_
+
+#include "painter.h"
+
+namespace Manta {
+// fwd decl
+class Mesh;
+
+//! Painter object for Meshes
+class MeshPainter : public LockedObjPainter {
+ Q_OBJECT
+public:
+ enum DisplayMode { ModeTrans=0, ModeLines, ModePoints, ModeFlatShade, ModeInvisible, Num_DisplayModes };
+ enum BackgroundMode { BModeNormal=0, BModeTrans, BModeInvisible, Num_BackgroundModes };
+ enum VorticityMode { VModeFull=0, VModeSmoothed, VModeDiff, VModeSmoke, VModeTex, VModeNone, Num_VorticityModes };
+
+ MeshPainter(QWidget* par = 0);
+ ~MeshPainter();
+
+ void paint();
+ void attachWidget(QLayout* layout);
+
+public slots:
+ void setBackgroundMesh(Mesh* bgr);
+
+protected:
+ std::string getID();
+ void update();
+ void updateText();
+ void processKeyEvent(PainterEvent e, int param);
+ void processSpecificKeyEvent(PainterEvent e, int param);
+ void setupLights(bool specular);
+
+ Real mColorScale;
+ DisplayMode mMode;
+ VorticityMode mVorticityMode;
+ BackgroundMode mBackgroundMode;
+ Mesh* mLocalMesh, *mBackground;
+ QLabel* mInfo;
+ bool mHide;
+};
+
+} // namespace
+
+#endif
+
diff --git a/source/blender/python/manta_pp/gui/meshpainter.h.reg b/source/blender/python/manta_pp/gui/meshpainter.h.reg
new file mode 100644
index 00000000000..33f65359335
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/meshpainter.h.reg
@@ -0,0 +1 @@
+#include "gui/meshpainter.h"
diff --git a/source/blender/python/manta_pp/gui/meshpainter.h.reg.cpp b/source/blender/python/manta_pp/gui/meshpainter.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/meshpainter.h.reg.cpp
diff --git a/source/blender/python/manta_pp/gui/moc_customctrl.cxx b/source/blender/python/manta_pp/gui/moc_customctrl.cxx
new file mode 100644
index 00000000000..9c486274f23
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_customctrl.cxx
@@ -0,0 +1,165 @@
+/****************************************************************************
+** Meta object code from reading C++ file 'customctrl.h'
+**
+** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.5)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#include "customctrl.h"
+#if !defined(Q_MOC_OUTPUT_REVISION)
+#error "The header file 'customctrl.h' doesn't include <QObject>."
+#elif Q_MOC_OUTPUT_REVISION != 63
+#error "This file was generated using the moc from 4.8.5. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+QT_BEGIN_MOC_NAMESPACE
+static const uint qt_meta_data_Manta__TextCheckbox[] = {
+
+ // content:
+ 6, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 1, 14, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+ 0, // flags
+ 0, // signalCount
+
+ // slots: signature, parameters, type, tag, flags
+ 23, 21, 20, 20, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_Manta__TextCheckbox[] = {
+ "Manta::TextCheckbox\0\0v\0update(int)\0"
+};
+
+void Manta::TextCheckbox::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
+ TextCheckbox *_t = static_cast<TextCheckbox *>(_o);
+ switch (_id) {
+ case 0: _t->update((*reinterpret_cast< int(*)>(_a[1]))); break;
+ default: ;
+ }
+ }
+}
+
+const QMetaObjectExtraData Manta::TextCheckbox::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
+};
+
+const QMetaObject Manta::TextCheckbox::staticMetaObject = {
+ { &QCheckBox::staticMetaObject, qt_meta_stringdata_Manta__TextCheckbox,
+ qt_meta_data_Manta__TextCheckbox, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &Manta::TextCheckbox::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
+
+const QMetaObject *Manta::TextCheckbox::metaObject() const
+{
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
+}
+
+void *Manta::TextCheckbox::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_Manta__TextCheckbox))
+ return static_cast<void*>(const_cast< TextCheckbox*>(this));
+ return QCheckBox::qt_metacast(_clname);
+}
+
+int Manta::TextCheckbox::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QCheckBox::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ if (_id < 1)
+ qt_static_metacall(this, _c, _id, _a);
+ _id -= 1;
+ }
+ return _id;
+}
+static const uint qt_meta_data_Manta__TextSlider[] = {
+
+ // content:
+ 6, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 1, 14, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+ 0, // flags
+ 0, // signalCount
+
+ // slots: signature, parameters, type, tag, flags
+ 21, 19, 18, 18, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_Manta__TextSlider[] = {
+ "Manta::TextSlider\0\0v\0update(int)\0"
+};
+
+void Manta::TextSlider::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
+ TextSlider *_t = static_cast<TextSlider *>(_o);
+ switch (_id) {
+ case 0: _t->update((*reinterpret_cast< int(*)>(_a[1]))); break;
+ default: ;
+ }
+ }
+}
+
+const QMetaObjectExtraData Manta::TextSlider::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
+};
+
+const QMetaObject Manta::TextSlider::staticMetaObject = {
+ { &QSlider::staticMetaObject, qt_meta_stringdata_Manta__TextSlider,
+ qt_meta_data_Manta__TextSlider, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &Manta::TextSlider::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
+
+const QMetaObject *Manta::TextSlider::metaObject() const
+{
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
+}
+
+void *Manta::TextSlider::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_Manta__TextSlider))
+ return static_cast<void*>(const_cast< TextSlider*>(this));
+ return QSlider::qt_metacast(_clname);
+}
+
+int Manta::TextSlider::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QSlider::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ if (_id < 1)
+ qt_static_metacall(this, _c, _id, _a);
+ _id -= 1;
+ }
+ return _id;
+}
+QT_END_MOC_NAMESPACE
diff --git a/source/blender/python/manta_pp/gui/moc_customctrl.cxx_parameters b/source/blender/python/manta_pp/gui/moc_customctrl.cxx_parameters
new file mode 100644
index 00000000000..36b0887518f
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_customctrl.cxx_parameters
@@ -0,0 +1,5 @@
+-DDEBUG
+-DGUI=1
+-o
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/moc_customctrl.cxx
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/customctrl.h
diff --git a/source/blender/python/manta_pp/gui/moc_glwidget.cxx b/source/blender/python/manta_pp/gui/moc_glwidget.cxx
new file mode 100644
index 00000000000..a577cd692c9
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_glwidget.cxx
@@ -0,0 +1,132 @@
+/****************************************************************************
+** Meta object code from reading C++ file 'glwidget.h'
+**
+** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.5)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#include "glwidget.h"
+#if !defined(Q_MOC_OUTPUT_REVISION)
+#error "The header file 'glwidget.h' doesn't include <QObject>."
+#elif Q_MOC_OUTPUT_REVISION != 63
+#error "This file was generated using the moc from 4.8.5. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+QT_BEGIN_MOC_NAMESPACE
+static const uint qt_meta_data_Manta__GLWidget[] = {
+
+ // content:
+ 6, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 7, 14, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+ 0, // flags
+ 4, // signalCount
+
+ // signals: signature, parameters, type, tag, flags
+ 17, 16, 16, 16, 0x05,
+ 50, 28, 16, 16, 0x05,
+ 112, 104, 16, 16, 0x05,
+ 136, 134, 16, 16, 0x25,
+
+ // slots: signature, parameters, type, tag, flags
+ 163, 154, 16, 16, 0x0a,
+ 182, 134, 16, 16, 0x0a,
+ 208, 134, 16, 16, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_Manta__GLWidget[] = {
+ "Manta::GLWidget\0\0paintSub()\0"
+ "pos,p0,p1,p2,q0,q1,q2\0"
+ "clickLine(QPoint,float,float,float,float,float,float)\0"
+ "e,param\0painterEvent(int,int)\0e\0"
+ "painterEvent(int)\0gridsize\0"
+ "setViewport(Vec3i)\0keyPressEvent(QKeyEvent*)\0"
+ "keyReleaseEvent(QKeyEvent*)\0"
+};
+
+void Manta::GLWidget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
+ GLWidget *_t = static_cast<GLWidget *>(_o);
+ switch (_id) {
+ case 0: _t->paintSub(); break;
+ case 1: _t->clickLine((*reinterpret_cast< QPoint(*)>(_a[1])),(*reinterpret_cast< float(*)>(_a[2])),(*reinterpret_cast< float(*)>(_a[3])),(*reinterpret_cast< float(*)>(_a[4])),(*reinterpret_cast< float(*)>(_a[5])),(*reinterpret_cast< float(*)>(_a[6])),(*reinterpret_cast< float(*)>(_a[7]))); break;
+ case 2: _t->painterEvent((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
+ case 3: _t->painterEvent((*reinterpret_cast< int(*)>(_a[1]))); break;
+ case 4: _t->setViewport((*reinterpret_cast< const Vec3i(*)>(_a[1]))); break;
+ case 5: _t->keyPressEvent((*reinterpret_cast< QKeyEvent*(*)>(_a[1]))); break;
+ case 6: _t->keyReleaseEvent((*reinterpret_cast< QKeyEvent*(*)>(_a[1]))); break;
+ default: ;
+ }
+ }
+}
+
+const QMetaObjectExtraData Manta::GLWidget::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
+};
+
+const QMetaObject Manta::GLWidget::staticMetaObject = {
+ { &QGLWidget::staticMetaObject, qt_meta_stringdata_Manta__GLWidget,
+ qt_meta_data_Manta__GLWidget, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &Manta::GLWidget::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
+
+const QMetaObject *Manta::GLWidget::metaObject() const
+{
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
+}
+
+void *Manta::GLWidget::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_Manta__GLWidget))
+ return static_cast<void*>(const_cast< GLWidget*>(this));
+ return QGLWidget::qt_metacast(_clname);
+}
+
+int Manta::GLWidget::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QGLWidget::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ if (_id < 7)
+ qt_static_metacall(this, _c, _id, _a);
+ _id -= 7;
+ }
+ return _id;
+}
+
+// SIGNAL 0
+void Manta::GLWidget::paintSub()
+{
+ QMetaObject::activate(this, &staticMetaObject, 0, 0);
+}
+
+// SIGNAL 1
+void Manta::GLWidget::clickLine(QPoint _t1, float _t2, float _t3, float _t4, float _t5, float _t6, float _t7)
+{
+ void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)), const_cast<void*>(reinterpret_cast<const void*>(&_t3)), const_cast<void*>(reinterpret_cast<const void*>(&_t4)), const_cast<void*>(reinterpret_cast<const void*>(&_t5)), const_cast<void*>(reinterpret_cast<const void*>(&_t6)), const_cast<void*>(reinterpret_cast<const void*>(&_t7)) };
+ QMetaObject::activate(this, &staticMetaObject, 1, _a);
+}
+
+// SIGNAL 2
+void Manta::GLWidget::painterEvent(int _t1, int _t2)
+{
+ void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)) };
+ QMetaObject::activate(this, &staticMetaObject, 2, _a);
+}
+QT_END_MOC_NAMESPACE
diff --git a/source/blender/python/manta_pp/gui/moc_glwidget.cxx_parameters b/source/blender/python/manta_pp/gui/moc_glwidget.cxx_parameters
new file mode 100644
index 00000000000..98948164723
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_glwidget.cxx_parameters
@@ -0,0 +1,5 @@
+-DDEBUG
+-DGUI=1
+-o
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/moc_glwidget.cxx
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/glwidget.h
diff --git a/source/blender/python/manta_pp/gui/moc_mainwindow.cxx b/source/blender/python/manta_pp/gui/moc_mainwindow.cxx
new file mode 100644
index 00000000000..1ab1bc4bb6a
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_mainwindow.cxx
@@ -0,0 +1,175 @@
+/****************************************************************************
+** Meta object code from reading C++ file 'mainwindow.h'
+**
+** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.5)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#include "mainwindow.h"
+#if !defined(Q_MOC_OUTPUT_REVISION)
+#error "The header file 'mainwindow.h' doesn't include <QObject>."
+#elif Q_MOC_OUTPUT_REVISION != 63
+#error "This file was generated using the moc from 4.8.5. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+QT_BEGIN_MOC_NAMESPACE
+static const uint qt_meta_data_Manta__MainWnd[] = {
+
+ // content:
+ 6, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 21, 14, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+ 0, // flags
+ 6, // signalCount
+
+ // signals: signature, parameters, type, tag, flags
+ 24, 16, 15, 15, 0x05,
+ 48, 46, 15, 15, 0x25,
+ 66, 15, 15, 15, 0x05,
+ 81, 77, 15, 15, 0x05,
+ 106, 15, 15, 15, 0x05,
+ 117, 15, 15, 15, 0x05,
+
+ // slots: signature, parameters, type, tag, flags
+ 127, 15, 15, 15, 0x0a,
+ 135, 15, 15, 15, 0x0a,
+ 142, 15, 15, 15, 0x0a,
+ 149, 15, 15, 15, 0x0a,
+ 165, 160, 15, 15, 0x0a,
+ 188, 183, 15, 15, 0x0a,
+ 230, 208, 15, 15, 0x0a,
+ 284, 15, 15, 15, 0x0a,
+ 299, 15, 15, 15, 0x0a,
+ 314, 15, 15, 15, 0x0a,
+ 325, 15, 15, 15, 0x0a,
+ 337, 15, 15, 15, 0x0a,
+ 349, 15, 15, 15, 0x0a,
+ 367, 15, 15, 15, 0x0a,
+ 385, 15, 15, 15, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_Manta__MainWnd[] = {
+ "Manta::MainWnd\0\0e,param\0painterEvent(int,int)\0"
+ "e\0painterEvent(int)\0wakeMain()\0bgr\0"
+ "setBackgroundMesh(Mesh*)\0killMain()\0"
+ "exitApp()\0pause()\0play()\0step()\0"
+ "showHelp()\0ctrl\0addControl(void*)\0"
+ "file\0screenshot(QString)\0pos,p0,p1,p2,q0,q1,q2\0"
+ "clickLine(QPoint,float,float,float,float,float,float)\0"
+ "nextRealGrid()\0nextVec3Grid()\0nextMesh()\0"
+ "nextParts()\0nextPdata()\0nextVec3Display()\0"
+ "nextPartDisplay()\0nextMeshDisplay()\0"
+};
+
+void Manta::MainWnd::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
+ MainWnd *_t = static_cast<MainWnd *>(_o);
+ switch (_id) {
+ case 0: _t->painterEvent((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
+ case 1: _t->painterEvent((*reinterpret_cast< int(*)>(_a[1]))); break;
+ case 2: _t->wakeMain(); break;
+ case 3: _t->setBackgroundMesh((*reinterpret_cast< Mesh*(*)>(_a[1]))); break;
+ case 4: _t->killMain(); break;
+ case 5: _t->exitApp(); break;
+ case 6: _t->pause(); break;
+ case 7: _t->play(); break;
+ case 8: _t->step(); break;
+ case 9: _t->showHelp(); break;
+ case 10: _t->addControl((*reinterpret_cast< void*(*)>(_a[1]))); break;
+ case 11: _t->screenshot((*reinterpret_cast< QString(*)>(_a[1]))); break;
+ case 12: _t->clickLine((*reinterpret_cast< QPoint(*)>(_a[1])),(*reinterpret_cast< float(*)>(_a[2])),(*reinterpret_cast< float(*)>(_a[3])),(*reinterpret_cast< float(*)>(_a[4])),(*reinterpret_cast< float(*)>(_a[5])),(*reinterpret_cast< float(*)>(_a[6])),(*reinterpret_cast< float(*)>(_a[7]))); break;
+ case 13: _t->nextRealGrid(); break;
+ case 14: _t->nextVec3Grid(); break;
+ case 15: _t->nextMesh(); break;
+ case 16: _t->nextParts(); break;
+ case 17: _t->nextPdata(); break;
+ case 18: _t->nextVec3Display(); break;
+ case 19: _t->nextPartDisplay(); break;
+ case 20: _t->nextMeshDisplay(); break;
+ default: ;
+ }
+ }
+}
+
+const QMetaObjectExtraData Manta::MainWnd::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
+};
+
+const QMetaObject Manta::MainWnd::staticMetaObject = {
+ { &QMainWindow::staticMetaObject, qt_meta_stringdata_Manta__MainWnd,
+ qt_meta_data_Manta__MainWnd, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &Manta::MainWnd::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
+
+const QMetaObject *Manta::MainWnd::metaObject() const
+{
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
+}
+
+void *Manta::MainWnd::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_Manta__MainWnd))
+ return static_cast<void*>(const_cast< MainWnd*>(this));
+ return QMainWindow::qt_metacast(_clname);
+}
+
+int Manta::MainWnd::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QMainWindow::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ if (_id < 21)
+ qt_static_metacall(this, _c, _id, _a);
+ _id -= 21;
+ }
+ return _id;
+}
+
+// SIGNAL 0
+void Manta::MainWnd::painterEvent(int _t1, int _t2)
+{
+ void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)) };
+ QMetaObject::activate(this, &staticMetaObject, 0, _a);
+}
+
+// SIGNAL 2
+void Manta::MainWnd::wakeMain()
+{
+ QMetaObject::activate(this, &staticMetaObject, 2, 0);
+}
+
+// SIGNAL 3
+void Manta::MainWnd::setBackgroundMesh(Mesh * _t1)
+{
+ void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
+ QMetaObject::activate(this, &staticMetaObject, 3, _a);
+}
+
+// SIGNAL 4
+void Manta::MainWnd::killMain()
+{
+ QMetaObject::activate(this, &staticMetaObject, 4, 0);
+}
+
+// SIGNAL 5
+void Manta::MainWnd::exitApp()
+{
+ QMetaObject::activate(this, &staticMetaObject, 5, 0);
+}
+QT_END_MOC_NAMESPACE
diff --git a/source/blender/python/manta_pp/gui/moc_mainwindow.cxx_parameters b/source/blender/python/manta_pp/gui/moc_mainwindow.cxx_parameters
new file mode 100644
index 00000000000..0399d8bd0fb
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_mainwindow.cxx_parameters
@@ -0,0 +1,5 @@
+-DDEBUG
+-DGUI=1
+-o
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/moc_mainwindow.cxx
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/mainwindow.h
diff --git a/source/blender/python/manta_pp/gui/moc_meshpainter.cxx b/source/blender/python/manta_pp/gui/moc_meshpainter.cxx
new file mode 100644
index 00000000000..a128a0fd7a2
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_meshpainter.cxx
@@ -0,0 +1,93 @@
+/****************************************************************************
+** Meta object code from reading C++ file 'meshpainter.h'
+**
+** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.5)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#include "meshpainter.h"
+#if !defined(Q_MOC_OUTPUT_REVISION)
+#error "The header file 'meshpainter.h' doesn't include <QObject>."
+#elif Q_MOC_OUTPUT_REVISION != 63
+#error "This file was generated using the moc from 4.8.5. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+QT_BEGIN_MOC_NAMESPACE
+static const uint qt_meta_data_Manta__MeshPainter[] = {
+
+ // content:
+ 6, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 1, 14, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+ 0, // flags
+ 0, // signalCount
+
+ // slots: signature, parameters, type, tag, flags
+ 24, 20, 19, 19, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_Manta__MeshPainter[] = {
+ "Manta::MeshPainter\0\0bgr\0"
+ "setBackgroundMesh(Mesh*)\0"
+};
+
+void Manta::MeshPainter::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
+ MeshPainter *_t = static_cast<MeshPainter *>(_o);
+ switch (_id) {
+ case 0: _t->setBackgroundMesh((*reinterpret_cast< Mesh*(*)>(_a[1]))); break;
+ default: ;
+ }
+ }
+}
+
+const QMetaObjectExtraData Manta::MeshPainter::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
+};
+
+const QMetaObject Manta::MeshPainter::staticMetaObject = {
+ { &LockedObjPainter::staticMetaObject, qt_meta_stringdata_Manta__MeshPainter,
+ qt_meta_data_Manta__MeshPainter, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &Manta::MeshPainter::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
+
+const QMetaObject *Manta::MeshPainter::metaObject() const
+{
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
+}
+
+void *Manta::MeshPainter::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_Manta__MeshPainter))
+ return static_cast<void*>(const_cast< MeshPainter*>(this));
+ return LockedObjPainter::qt_metacast(_clname);
+}
+
+int Manta::MeshPainter::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = LockedObjPainter::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ if (_id < 1)
+ qt_static_metacall(this, _c, _id, _a);
+ _id -= 1;
+ }
+ return _id;
+}
+QT_END_MOC_NAMESPACE
diff --git a/source/blender/python/manta_pp/gui/moc_meshpainter.cxx_parameters b/source/blender/python/manta_pp/gui/moc_meshpainter.cxx_parameters
new file mode 100644
index 00000000000..eb7319e1fab
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_meshpainter.cxx_parameters
@@ -0,0 +1,5 @@
+-DDEBUG
+-DGUI=1
+-o
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/moc_meshpainter.cxx
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/meshpainter.h
diff --git a/source/blender/python/manta_pp/gui/moc_painter.cxx b/source/blender/python/manta_pp/gui/moc_painter.cxx
new file mode 100644
index 00000000000..7e2dc158f81
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_painter.cxx
@@ -0,0 +1,170 @@
+/****************************************************************************
+** Meta object code from reading C++ file 'painter.h'
+**
+** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.5)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#include "painter.h"
+#if !defined(Q_MOC_OUTPUT_REVISION)
+#error "The header file 'painter.h' doesn't include <QObject>."
+#elif Q_MOC_OUTPUT_REVISION != 63
+#error "This file was generated using the moc from 4.8.5. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+QT_BEGIN_MOC_NAMESPACE
+static const uint qt_meta_data_Manta__Painter[] = {
+
+ // content:
+ 6, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 4, 14, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+ 0, // flags
+ 1, // signalCount
+
+ // signals: signature, parameters, type, tag, flags
+ 25, 16, 15, 15, 0x05,
+
+ // slots: signature, parameters, type, tag, flags
+ 44, 15, 15, 15, 0x0a,
+ 60, 52, 15, 15, 0x0a,
+ 79, 77, 15, 15, 0x2a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_Manta__Painter[] = {
+ "Manta::Painter\0\0gridsize\0setViewport(Vec3i)\0"
+ "paint()\0e,param\0doEvent(int,int)\0e\0"
+ "doEvent(int)\0"
+};
+
+void Manta::Painter::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
+ Painter *_t = static_cast<Painter *>(_o);
+ switch (_id) {
+ case 0: _t->setViewport((*reinterpret_cast< const Vec3i(*)>(_a[1]))); break;
+ case 1: _t->paint(); break;
+ case 2: _t->doEvent((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
+ case 3: _t->doEvent((*reinterpret_cast< int(*)>(_a[1]))); break;
+ default: ;
+ }
+ }
+}
+
+const QMetaObjectExtraData Manta::Painter::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
+};
+
+const QMetaObject Manta::Painter::staticMetaObject = {
+ { &QObject::staticMetaObject, qt_meta_stringdata_Manta__Painter,
+ qt_meta_data_Manta__Painter, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &Manta::Painter::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
+
+const QMetaObject *Manta::Painter::metaObject() const
+{
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
+}
+
+void *Manta::Painter::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_Manta__Painter))
+ return static_cast<void*>(const_cast< Painter*>(this));
+ return QObject::qt_metacast(_clname);
+}
+
+int Manta::Painter::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ if (_id < 4)
+ qt_static_metacall(this, _c, _id, _a);
+ _id -= 4;
+ }
+ return _id;
+}
+
+// SIGNAL 0
+void Manta::Painter::setViewport(const Vec3i & _t1)
+{
+ void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
+ QMetaObject::activate(this, &staticMetaObject, 0, _a);
+}
+static const uint qt_meta_data_Manta__LockedObjPainter[] = {
+
+ // content:
+ 6, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 0, 0, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+ 0, // flags
+ 0, // signalCount
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_Manta__LockedObjPainter[] = {
+ "Manta::LockedObjPainter\0"
+};
+
+void Manta::LockedObjPainter::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ Q_UNUSED(_o);
+ Q_UNUSED(_id);
+ Q_UNUSED(_c);
+ Q_UNUSED(_a);
+}
+
+const QMetaObjectExtraData Manta::LockedObjPainter::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
+};
+
+const QMetaObject Manta::LockedObjPainter::staticMetaObject = {
+ { &Painter::staticMetaObject, qt_meta_stringdata_Manta__LockedObjPainter,
+ qt_meta_data_Manta__LockedObjPainter, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &Manta::LockedObjPainter::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
+
+const QMetaObject *Manta::LockedObjPainter::metaObject() const
+{
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
+}
+
+void *Manta::LockedObjPainter::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_Manta__LockedObjPainter))
+ return static_cast<void*>(const_cast< LockedObjPainter*>(this));
+ return Painter::qt_metacast(_clname);
+}
+
+int Manta::LockedObjPainter::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = Painter::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ return _id;
+}
+QT_END_MOC_NAMESPACE
diff --git a/source/blender/python/manta_pp/gui/moc_painter.cxx_parameters b/source/blender/python/manta_pp/gui/moc_painter.cxx_parameters
new file mode 100644
index 00000000000..2dde75589ec
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_painter.cxx_parameters
@@ -0,0 +1,5 @@
+-DDEBUG
+-DGUI=1
+-o
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/moc_painter.cxx
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/painter.h
diff --git a/source/blender/python/manta_pp/gui/moc_particlepainter.cxx b/source/blender/python/manta_pp/gui/moc_particlepainter.cxx
new file mode 100644
index 00000000000..a2ea9bacf4b
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_particlepainter.cxx
@@ -0,0 +1,80 @@
+/****************************************************************************
+** Meta object code from reading C++ file 'particlepainter.h'
+**
+** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.5)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#include "particlepainter.h"
+#if !defined(Q_MOC_OUTPUT_REVISION)
+#error "The header file 'particlepainter.h' doesn't include <QObject>."
+#elif Q_MOC_OUTPUT_REVISION != 63
+#error "This file was generated using the moc from 4.8.5. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+QT_BEGIN_MOC_NAMESPACE
+static const uint qt_meta_data_Manta__ParticlePainter[] = {
+
+ // content:
+ 6, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 0, 0, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+ 0, // flags
+ 0, // signalCount
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_Manta__ParticlePainter[] = {
+ "Manta::ParticlePainter\0"
+};
+
+void Manta::ParticlePainter::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ Q_UNUSED(_o);
+ Q_UNUSED(_id);
+ Q_UNUSED(_c);
+ Q_UNUSED(_a);
+}
+
+const QMetaObjectExtraData Manta::ParticlePainter::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
+};
+
+const QMetaObject Manta::ParticlePainter::staticMetaObject = {
+ { &LockedObjPainter::staticMetaObject, qt_meta_stringdata_Manta__ParticlePainter,
+ qt_meta_data_Manta__ParticlePainter, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &Manta::ParticlePainter::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
+
+const QMetaObject *Manta::ParticlePainter::metaObject() const
+{
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
+}
+
+void *Manta::ParticlePainter::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_Manta__ParticlePainter))
+ return static_cast<void*>(const_cast< ParticlePainter*>(this));
+ return LockedObjPainter::qt_metacast(_clname);
+}
+
+int Manta::ParticlePainter::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = LockedObjPainter::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ return _id;
+}
+QT_END_MOC_NAMESPACE
diff --git a/source/blender/python/manta_pp/gui/moc_particlepainter.cxx_parameters b/source/blender/python/manta_pp/gui/moc_particlepainter.cxx_parameters
new file mode 100644
index 00000000000..efa42b9903c
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_particlepainter.cxx_parameters
@@ -0,0 +1,5 @@
+-DDEBUG
+-DGUI=1
+-o
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/moc_particlepainter.cxx
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/particlepainter.h
diff --git a/source/blender/python/manta_pp/gui/moc_qtmain.cxx b/source/blender/python/manta_pp/gui/moc_qtmain.cxx
new file mode 100644
index 00000000000..7ead8306ef5
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_qtmain.cxx
@@ -0,0 +1,182 @@
+/****************************************************************************
+** Meta object code from reading C++ file 'qtmain.h'
+**
+** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.5)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#include "qtmain.h"
+#if !defined(Q_MOC_OUTPUT_REVISION)
+#error "The header file 'qtmain.h' doesn't include <QObject>."
+#elif Q_MOC_OUTPUT_REVISION != 63
+#error "This file was generated using the moc from 4.8.5. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+QT_BEGIN_MOC_NAMESPACE
+static const uint qt_meta_data_Manta__GuiThread[] = {
+
+ // content:
+ 6, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 2, 14, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+ 0, // flags
+ 0, // signalCount
+
+ // slots: signature, parameters, type, tag, flags
+ 20, 18, 17, 17, 0x0a,
+ 35, 17, 17, 17, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_Manta__GuiThread[] = {
+ "Manta::GuiThread\0\0e\0sendEvent(int)\0"
+ "exitApp()\0"
+};
+
+void Manta::GuiThread::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
+ GuiThread *_t = static_cast<GuiThread *>(_o);
+ switch (_id) {
+ case 0: _t->sendEvent((*reinterpret_cast< int(*)>(_a[1]))); break;
+ case 1: _t->exitApp(); break;
+ default: ;
+ }
+ }
+}
+
+const QMetaObjectExtraData Manta::GuiThread::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
+};
+
+const QMetaObject Manta::GuiThread::staticMetaObject = {
+ { &QObject::staticMetaObject, qt_meta_stringdata_Manta__GuiThread,
+ qt_meta_data_Manta__GuiThread, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &Manta::GuiThread::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
+
+const QMetaObject *Manta::GuiThread::metaObject() const
+{
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
+}
+
+void *Manta::GuiThread::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_Manta__GuiThread))
+ return static_cast<void*>(const_cast< GuiThread*>(this));
+ return QObject::qt_metacast(_clname);
+}
+
+int Manta::GuiThread::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ if (_id < 2)
+ qt_static_metacall(this, _c, _id, _a);
+ _id -= 2;
+ }
+ return _id;
+}
+static const uint qt_meta_data_Manta__MainThread[] = {
+
+ // content:
+ 6, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 3, 14, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+ 0, 0, // constructors
+ 0, // flags
+ 1, // signalCount
+
+ // signals: signature, parameters, type, tag, flags
+ 25, 19, 18, 18, 0x05,
+
+ // slots: signature, parameters, type, tag, flags
+ 40, 18, 18, 18, 0x0a,
+ 49, 18, 18, 18, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_Manta__MainThread[] = {
+ "Manta::MainThread\0\0event\0sendToGui(int)\0"
+ "wakeUp()\0killMe()\0"
+};
+
+void Manta::MainThread::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ Q_ASSERT(staticMetaObject.cast(_o));
+ MainThread *_t = static_cast<MainThread *>(_o);
+ switch (_id) {
+ case 0: _t->sendToGui((*reinterpret_cast< int(*)>(_a[1]))); break;
+ case 1: _t->wakeUp(); break;
+ case 2: _t->killMe(); break;
+ default: ;
+ }
+ }
+}
+
+const QMetaObjectExtraData Manta::MainThread::staticMetaObjectExtraData = {
+ 0, qt_static_metacall
+};
+
+const QMetaObject Manta::MainThread::staticMetaObject = {
+ { &QThread::staticMetaObject, qt_meta_stringdata_Manta__MainThread,
+ qt_meta_data_Manta__MainThread, &staticMetaObjectExtraData }
+};
+
+#ifdef Q_NO_DATA_RELOCATION
+const QMetaObject &Manta::MainThread::getStaticMetaObject() { return staticMetaObject; }
+#endif //Q_NO_DATA_RELOCATION
+
+const QMetaObject *Manta::MainThread::metaObject() const
+{
+ return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
+}
+
+void *Manta::MainThread::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_Manta__MainThread))
+ return static_cast<void*>(const_cast< MainThread*>(this));
+ return QThread::qt_metacast(_clname);
+}
+
+int Manta::MainThread::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QThread::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ if (_id < 3)
+ qt_static_metacall(this, _c, _id, _a);
+ _id -= 3;
+ }
+ return _id;
+}
+
+// SIGNAL 0
+void Manta::MainThread::sendToGui(int _t1)
+{
+ void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
+ QMetaObject::activate(this, &staticMetaObject, 0, _a);
+}
+QT_END_MOC_NAMESPACE
diff --git a/source/blender/python/manta_pp/gui/moc_qtmain.cxx_parameters b/source/blender/python/manta_pp/gui/moc_qtmain.cxx_parameters
new file mode 100644
index 00000000000..50315ba96f5
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/moc_qtmain.cxx_parameters
@@ -0,0 +1,5 @@
+-DDEBUG
+-DGUI=1
+-o
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/moc_qtmain.cxx
+/Users/pr110/Documents/WorkingOnNow/gsoc/manta_git/xcode_build/pp/source/gui/qtmain.h
diff --git a/source/blender/python/manta_pp/gui/painter.cpp b/source/blender/python/manta_pp/gui/painter.cpp
new file mode 100644
index 00000000000..cc51c6bce20
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/painter.cpp
@@ -0,0 +1,555 @@
+
+
+
+
+
+// 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
+ *
+ * Base class for objects painting into the GL widget
+ *
+ ******************************************************************************/
+
+#include "painter.h"
+#include <QtOpenGL>
+#include <sstream>
+#include <iomanip>
+
+using namespace std;
+
+namespace Manta {
+
+//******************************************************************************
+// Base class
+
+void LockedObjPainter::doEvent(int e, int param) {
+ // try to obtain valid handle
+ if (!mObject)
+ nextObject();
+
+ // filter update events
+ if (e == UpdateFull) {
+ // always update
+ if (mObject) {
+ mObject->lock();
+ update();
+ mObject->unlock();
+ mRequestUpdate = false;
+ }
+ } else if (e == UpdateRequest) {
+ // update if resource is available, otherwise wait until next step
+ mRequestUpdate = true;
+ if (mObject) {
+ if (mObject->tryLock()) {
+ update();
+ mRequestUpdate = false;
+ mObject->unlock();
+ }
+ }
+ } else if (e == UpdateStep) {
+ // update if requested only
+ if (mRequestUpdate) {
+ if (mObject) {
+ mObject->lock();
+ update();
+ mObject->unlock();
+ mRequestUpdate = false;
+ }
+ }
+ } else {
+ // pass on all other events
+ processKeyEvent((PainterEvent)e, param);
+ }
+}
+
+void LockedObjPainter::nextObject() {
+ if (PbClass::getNumInstances() == 0) return;
+
+ int oldIndex = mObjIndex;
+ for(;;) {
+ mObjIndex = (mObjIndex + 1) % PbClass::getNumInstances();
+ if (oldIndex == mObjIndex) break;
+
+ PbClass* obj = PbClass::getInstance(mObjIndex);
+ if (obj->canConvertTo(getID()) && !obj->isHidden()) {
+ mObject = obj;
+ doEvent(UpdateRequest);
+ return;
+ }
+ if (oldIndex < 0) oldIndex = 0; // prevent endless loop on first run
+ }
+}
+
+//******************************************************************************
+// Grid painter
+
+template<class T>
+GridPainter<T>::GridPainter(FlagGrid** flags, QWidget* par)
+ : LockedObjPainter(par), mMaxVal(0), mDim(0), mPlane(0), mMax(0), mLocalGrid(NULL),
+ mFlags(flags), mInfo(NULL), mHide(false), mHideLocal(false), mDispMode(VecDispCentered), mValScale()
+{
+ mDim = 2; // Z plane
+ mPlane = 0;
+ mInfo = new QLabel();
+
+}
+
+template<class T>
+GridPainter<T>::~GridPainter() {
+ if (mLocalGrid)
+ delete mLocalGrid;
+}
+
+template<class T>
+void GridPainter<T>::attachWidget(QLayout* layout) {
+ layout->addWidget(mInfo);
+}
+
+template<class T>
+void GridPainter<T>::update() {
+ Grid<T>* src = (Grid<T>*) mObject;
+
+ if (!mLocalGrid) {
+ mLocalGrid = new Grid<T>(src->getParent());
+ // int grid is base for resolution
+ if (src->getType() & GridBase::TypeInt)
+ emit setViewport(src->getSize());
+ }
+ // reallocate if dimensions changed
+ if (mLocalGrid->getSize() != src->getSize()) {
+ delete mLocalGrid;
+ mLocalGrid = new Grid<T>(src->getParent());
+ // int grid is base for resolution
+ if (src->getType() & GridBase::TypeInt)
+ emit setViewport(src->getSize());
+ }
+
+ mLocalGrid->copyFrom( *src ); // copy grid data and type marker
+ mLocalGrid->setName(src->getName());
+ mLocalGrid->setParent(src->getParent());
+ mMaxVal = mLocalGrid->getMaxAbsValue();
+
+ mPlane = clamp(mPlane, 0, mLocalGrid->getSize()[mDim]-1);
+
+ updateText();
+}
+
+template<> string GridPainter<int>::getID() { return "Grid<int>"; }
+template<> string GridPainter<Vec3>::getID() { return "Grid<Vec3>"; }
+template<> string GridPainter<Real>::getID() { return "Grid<Real>"; }
+
+template<class T>
+void GridPainter<T>::processKeyEvent(PainterEvent e, int param)
+{
+ if (e == EventSetDim) {
+ mDim = param;
+ if (mLocalGrid->is2D()) mDim = 2;
+ } else if (e == EventSetMax) {
+ mMax = param;
+ } else if (e == EventSetPlane) {
+ mPlane = param;
+ if (mObject) {
+ if (mMax>0)
+ mPlane = mPlane * mLocalGrid->getSize()[mDim] / mMax;
+ mPlane = clamp(mPlane, 0, mLocalGrid->getSize()[mDim]-1);
+ }
+ } else if (e == EventToggleGridDisplay)
+ mHide = !mHide;
+ else
+ processSpecificKeyEvent(e, param);
+
+ updateText();
+}
+
+// get scale value for current grid from map, or create new
+template<class T>
+Real GridPainter<T>::getScale() {
+ if (!mObject) return 0;
+
+ if (mValScale.find(mObject) == mValScale.end()) {
+ // init new scale value
+ Real s = 1.0;
+ if (mLocalGrid->getType() & GridBase::TypeVec3)
+ s = 0.4;
+ else if (mLocalGrid->getType() & GridBase::TypeLevelset)
+ s = 1.0;
+ mValScale[mObject] = s;
+ }
+ return mValScale[mObject];
+
+}
+
+//******************************************************************************
+// Grid painter class specializations
+
+template<>
+void GridPainter<int>::processSpecificKeyEvent(PainterEvent e, int param) {
+ if (e == EventNextInt)
+ nextObject();
+}
+
+template<>
+void GridPainter<Real>::processSpecificKeyEvent(PainterEvent e, int param) {
+ if (e == EventNextReal)
+ nextObject();
+ else if (e == EventScaleRealDown && mObject)
+ mValScale[mObject] = getScale() * 0.5;
+ else if (e == EventScaleRealUp && mObject)
+ mValScale[mObject] = getScale() * 2.0;
+ else if (e == EventNextRealDisplayMode) {
+ mDispMode = (mDispMode+1)%NumRealDispModes;
+ mHideLocal = (mDispMode==RealDispOff);
+ }
+}
+
+template<>
+void GridPainter<Vec3>::processSpecificKeyEvent(PainterEvent e, int param) {
+ if (e == EventNextVec)
+ nextObject();
+ else if (e == EventScaleVecDown && mObject)
+ mValScale[mObject] = getScale() * 0.5;
+ else if (e == EventScaleVecUp && mObject)
+ mValScale[mObject] = getScale() * 2.0;
+ else if (e == EventNextVecDisplayMode) {
+ mDispMode = (mDispMode+1)%NumVecDispModes;
+ mHideLocal = (mDispMode==VecDispOff);
+ }
+}
+
+template<> void GridPainter<int>::updateText() {
+ stringstream s;
+ if (mObject && (!mHide)) {
+ s << "Int Grid '" << mLocalGrid->getName() << "'" << endl;
+ }
+ mInfo->setText(s.str().c_str());
+}
+
+template<> void GridPainter<Real>::updateText() {
+ stringstream s;
+
+ s << "Display Plane " << mPlane << " [" << (char)('X' + mDim) << "]" << endl << endl;
+ if (mObject) {
+ s << "Solver '" << mLocalGrid->getParent()->getName() << "'" << endl;
+ s << "Grid resolution [" << mLocalGrid->getSizeX() << ", " << mLocalGrid->getSizeY() << ", " << mLocalGrid->getSizeZ() << "]" << endl;
+ s << endl;
+ }
+
+ if (mObject && !mHide && !mHideLocal) {
+ s << "Real Grid '" << mLocalGrid->getName() << "'" << endl;
+ s << "-> Max " << fixed << setprecision(2) << mMaxVal << " Scale " << getScale() << endl;
+ }
+ mInfo->setText(s.str().c_str());
+}
+
+template<> void GridPainter<Vec3>::updateText() {
+ stringstream s;
+ if (mObject && !mHide && !mHideLocal) {
+ s << "Vec Grid '" << mLocalGrid->getName() << "'" << endl;
+ s << "-> Max norm " << fixed << setprecision(2) << mMaxVal << " Scale " << getScale() << endl;
+ }
+ mInfo->setText(s.str().c_str());
+}
+
+// compute line intersection with the display plane
+Vec3i getQuad(const Vec3& l0, const Vec3& l1, int dim, int plane, Real dx) {
+ Vec3 n(0.); n[dim] = 1;
+ Vec3 p0 = n*(plane+0.5);
+ Vec3 e = (l1-l0)/dx;
+ Vec3 e0 = l0/dx;
+ Real dotP = dot(p0-e0,n);
+ Real dotE = dot(e,n);
+ if (dotE == 0)
+ return Vec3i(-1,-1,-1);
+ Vec3 s = e0 + (dotP/dotE)*e;
+ return toVec3i(s);
+}
+
+template<> string GridPainter<int>::clickLine(const Vec3& p0, const Vec3& p1) {
+ if (!mObject) return "";
+ Vec3i s = getQuad(p0,p1,mDim,mPlane,mLocalGrid->getDx());
+ if (!mLocalGrid->isInBounds(s)) return "";
+ stringstream m;
+ m << "Grid [ " << s.x << ", " << s.y << ", " << s.z << " ]" << endl << mLocalGrid->getName() << ": " << mLocalGrid->get(s) << endl;
+ return m.str();
+}
+
+template<> string GridPainter<Real>::clickLine(const Vec3& p0, const Vec3& p1) {
+ if (!mObject) return "";
+ Vec3i s = getQuad(p0,p1,mDim,mPlane,mLocalGrid->getDx());
+ if (!mLocalGrid->isInBounds(s)) return "";
+ stringstream m;
+ m << mLocalGrid->getName() << ": " << setprecision(2) << mLocalGrid->get(s) << endl;
+ return m.str();
+}
+
+template<> string GridPainter<Vec3>::clickLine(const Vec3& p0, const Vec3& p1) {
+ if (!mObject) return "";
+ Vec3i s = getQuad(p0,p1,mDim,mPlane,mLocalGrid->getDx());
+ if (!mLocalGrid->isInBounds(s)) return "";
+ stringstream m;
+ m << mLocalGrid->getName() << ": [ " << setprecision(2) << mLocalGrid->get(s).x << ", " <<
+ mLocalGrid->get(s).y << ", " << mLocalGrid->get(s).z << " ]" << endl;
+ return m.str();
+}
+
+
+//******************************************************************************
+// Actual painting functions
+
+// GL helper functions
+
+// Macro to iterate through one plane
+#define FOR_P_SLICE(__g,__dim,__plane) \
+ for(Vec3i __g0(__fRange(Vec3i(0,0,0),__dim,__plane)), __g1(__fRange((__g)->getSize(),__dim,__plane+1)), p(__g0); p.z<__g1.z; p.z++) \
+ for(p.y=__g0.y; p.y < __g1.y; p.y++) \
+ for(p.x=__g0.x; p.x < __g1.x; p.x++)
+inline Vec3i __fRange(Vec3i size, int dim, int plane) { Vec3i p(size); p[dim]=plane; return p; }
+
+// coordinate system :
+// cell center(i,j,k) -> (i+0.5,j+0.5,k+0.5) / N
+//
+
+void getCellCoordinates(const Vec3i& pos, Vec3 box[4], int dim) {
+ int dim2=(dim+1)%3;
+ Vec3 p0(pos.x, pos.y, pos.z);
+ Vec3 p1(pos.x+1, pos.y+1, pos.z+1);
+ p1[dim] = p0[dim] = pos[dim] + 0.5;
+ box[0] = p0;
+ box[3] = p0; box[3][dim2] = p1[dim2];
+ box[1] = p1; box[1][dim2] = p0[dim2];
+ box[2] = p1;
+}
+static inline void glVertex(const Vec3& v, const float dx) {
+ glVertex3f(v.x * dx, v.y * dx, v.z * dx);
+}
+void glBox(const Vec3& p0, const Vec3& p1, const float dx) {
+ const int box[24] = {0,1,0,2,0,4,7,6,7,5,7,3,1,3,1,5,2,3,2,6,4,5,4,6};
+ for (int i=0;i<24;i++) {
+ const int b = box[i];
+ glVertex(Vec3( (b&1) ? p1.x : p0.x, (b&2) ? p1.y : p0.y, (b&4) ? p1.z : p0.z), dx);
+ }
+}
+
+// Paint gridlines
+template<> void GridPainter<int>::paint() {
+ if (!mObject || mHide || mPlane <0 || mPlane >= mLocalGrid->getSize()[mDim])
+ return;
+ float dx = mLocalGrid->getDx();
+ Vec3 box[4];
+ glColor3f(0.5,0,0);
+
+ bool rbox = true;
+ bool skipFluid = mLocalGrid->getSize().max() > 40;
+ bool drawLines = mLocalGrid->getSize().max() <= 80;
+ if (drawLines) {
+ //glDepthFunc(GL_LESS);
+ glBegin(GL_LINES);
+ FOR_P_SLICE(mLocalGrid, mDim, mPlane) {
+
+ int flag = 0;
+ flag = mLocalGrid->get(p);
+
+ if (flag & FlagGrid::TypeObstacle) {
+ glColor3f(0.2,0.2,0.2);
+ } else if (flag & FlagGrid::TypeOutflow) {
+ glColor3f(0.9,0.2,0);
+ } else if (flag & FlagGrid::TypeEmpty) {
+ glColor3f(0.25,0,0);
+ } else if (flag & FlagGrid::TypeFluid) {
+ if(skipFluid) continue;
+ glColor3f(0,0,0.75);
+ } else {
+ glColor3f(0.5,0,0); // unknown
+ }
+
+ getCellCoordinates(p, box, mDim);
+ for (int n=1;n<=8;n++)
+ glVertex(box[(n/2)%4], dx);
+ }
+ glEnd();
+ //glDepthFunc(GL_ALWAYS);
+ }
+
+ if (rbox) {
+ Vec3 p0(0.0), p1(toVec3(mLocalGrid->getSize())),p(p0);
+ glDepthFunc(GL_LESS);
+ glBegin(GL_LINES);
+ glBox(p0,p1,dx);
+ glEnd();
+ glDepthFunc(GL_ALWAYS);
+ }
+}
+
+// Paint box colors
+template<> void GridPainter<Real>::paint() {
+ if (!mObject || mHide || mHideLocal || mPlane <0 || mPlane >= mLocalGrid->getSize()[mDim] || !mFlags || !(*mFlags))
+ return;
+
+ float dx = mLocalGrid->getDx();
+ Vec3 box[4];
+ glBegin(GL_QUADS);
+ Real scale = getScale();
+ bool isLevelset = mLocalGrid->getType() & GridBase::TypeLevelset;
+ //glPolygonOffset(1.0,1.0);
+ //glDepthFunc(GL_LESS);
+
+ const bool useOldDrawStyle = false;
+ if(useOldDrawStyle) {
+ // original mantaflow drawing style
+ FlagGrid *flags = *mFlags;
+ if (flags->getSize() != mLocalGrid->getSize()) flags = 0;
+
+ FOR_P_SLICE(mLocalGrid, mDim, mPlane) {
+ int flag = FlagGrid::TypeFluid;
+ if (flags && (mLocalGrid->getType() & GridBase::TypeLevelset) == 0) flag = flags->get(p);
+ if (flag & FlagGrid::TypeObstacle)
+ glColor3f(0.15,0.15,0.15);
+ else if (flag & FlagGrid::TypeOutflow)
+ glColor3f(0.3,0.0,0.0);
+ else if (flag & FlagGrid::TypeEmpty)
+ glColor3f(0.,0.2,0.);
+ else {
+ Real v = mLocalGrid->get(p) * scale;
+
+ if (isLevelset) {
+ v = max(min(v*0.2, 1.0),-1.0);
+ if (v>=0)
+ glColor3f(v,0,0.5);
+ else
+ glColor3f(0.5, 1.0+v, 0.);
+ } else {
+ if (v>0)
+ glColor3f(v,0,0);
+ else
+ glColor3f(0,0,-v);
+ }
+ }
+
+ if ((flag & FlagGrid::TypeEmpty) == 0) {
+ getCellCoordinates(p, box, mDim);
+ for (int n=0;n<4;n++)
+ glVertex(box[n], dx);
+ }
+ }
+
+ } else {
+ // "new" drawing style
+ // ignore flags, its a bit dangerous to skip outside info
+
+ FOR_P_SLICE(mLocalGrid, mDim, mPlane)
+ {
+ Real v = mLocalGrid->get(p) * scale;
+ if (isLevelset) {
+ v = max(min(v*0.2, 1.0),-1.0);
+ if (v>=0)
+ glColor3f(v,0,0.5);
+ else
+ glColor3f(0.5, 1.0+v, 0.);
+ } else {
+ if (v>0)
+ glColor3f(v,v,v);
+ else
+ glColor3f(-v,0,0);
+ }
+
+ getCellCoordinates(p, box, mDim);
+ for (int n=0;n<4;n++)
+ glVertex(box[n], dx);
+ }
+ }
+
+ glEnd();
+ //glDepthFunc(GL_ALWAYS);
+ //glPolygonOffset(0,0);
+}
+
+// Paint velocity vectors
+template<> void GridPainter<Vec3>::paint() {
+ if (!mObject || mHide || mHideLocal || mPlane <0 || mPlane >= mLocalGrid->getSize()[mDim])
+ return;
+
+ float dx = mLocalGrid->getDx();
+ bool mac = mLocalGrid->getType() & GridBase::TypeMAC;
+ const Real scale = getScale();
+
+ if( (mDispMode==VecDispCentered) || (mDispMode==VecDispStaggered) ) {
+
+ // regular velocity drawing mode
+ glBegin(GL_LINES);
+
+ FOR_P_SLICE(mLocalGrid, mDim, mPlane) {
+ Vec3 vel = mLocalGrid->get(p) * scale;
+ Vec3 pos (p.x+0.5, p.y+0.5, p.z+0.5);
+ if (mDispMode==VecDispCentered) {
+ if (mac) {
+ if (p.x < mLocalGrid->getSizeX()-1)
+ vel.x = 0.5 * (vel.x + scale * mLocalGrid->get(p.x+1,p.y,p.z).x);
+ if (p.y < mLocalGrid->getSizeY()-1)
+ vel.y = 0.5 * (vel.y + scale * mLocalGrid->get(p.x,p.y+1,p.z).y);
+ if (p.z < mLocalGrid->getSizeZ()-1)
+ vel.z = 0.5 * (vel.z + scale * mLocalGrid->get(p.x,p.y,p.z+1).z);
+ }
+ glColor3f(0,1,0);
+ glVertex(pos, dx);
+ glColor3f(1,1,0);
+ glVertex(pos+vel*1.2, dx);
+ } else if (mDispMode==VecDispStaggered) {
+ for (int d=0; d<3; d++) {
+ if (fabs(vel[d]) < 1e-2) continue;
+ Vec3 p1(pos);
+ if (mac)
+ p1[d] -= 0.5f;
+ Vec3 color(0.0);
+ color[d] = 1;
+ glColor3f(color.x, color.y, color.z);
+ glVertex(p1, dx);
+ glColor3f(1,1,0);
+ p1[d] += vel[d];
+ glVertex(p1, dx);
+ }
+ }
+ }
+ glEnd();
+
+ } else if (mDispMode==VecDispUv) {
+ // draw as uv coordinates , note - this will completely hide the real grid display!
+ Vec3 box[4];
+ glBegin(GL_QUADS);
+ FOR_P_SLICE(mLocalGrid, mDim, mPlane)
+ {
+ Vec3 v = mLocalGrid->get(p) * scale;
+ for(int c=0; c<3; ++c) {
+ if(v[c]<0.) v[c] *= -1.;
+ v[c] = fmod( (Real)v[c], (Real)1.);
+ }
+ //v *= mLocalGrid->get(0)[0]; // debug, show uv grid weight as brightness of values
+ glColor3f(v[0],v[1],v[2]);
+ getCellCoordinates(p, box, mDim);
+ for (int n=0;n<4;n++)
+ glVertex(box[n], dx);
+ }
+ glEnd();
+ }
+}
+
+
+// explicit instantiation
+template class GridPainter<int>;
+template class GridPainter<Real>;
+template class GridPainter<Vec3>;
+
+} // namespace
+
+
diff --git a/source/blender/python/manta_pp/gui/painter.h b/source/blender/python/manta_pp/gui/painter.h
new file mode 100644
index 00000000000..c2e8af192f0
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/painter.h
@@ -0,0 +1,127 @@
+
+
+
+
+
+// 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
+ *
+ * Base class for objects painting into the GL widget
+ *
+ ******************************************************************************/
+
+#ifndef _PAINTER_H_
+#define _PAINTER_H_
+
+#include <QWidget>
+#include <QLabel>
+#include <map>
+#include "grid.h"
+
+namespace Manta {
+
+// forward decl.
+class PbClass;
+
+//! Base class for all painter
+/*! Derived classes have to implement paint, doEvent */
+class Painter : public QObject {
+ Q_OBJECT
+public:
+ enum PainterEvent {
+ EventNone = 0, UpdateRequest, UpdateFull, UpdateStep,
+ EventScaleVecUp, EventScaleVecDown, EventNextRealDisplayMode, EventScaleRealUp, EventScaleRealDown, EventChangePlane,
+ EventSetPlane, EventSetDim, EventNextInt, EventNextReal, EventNextVec, EventNextVecDisplayMode,
+ EventNextMesh, EventMeshMode, EventToggleGridDisplay, EventScaleMeshUp, EventScaleMeshDown, EventMeshColorMode,
+ EventNextSystem, EventToggleParticles, EventNextParticleDisplayMode, EventToggleBackgroundMesh, EventSetMax,
+ EventScalePdataDown, EventScalePdataUp };
+
+ enum RealDisplayModes { RealDispOff=0, RealDispStd, NumRealDispModes };
+
+ enum VecDisplayModes { VecDispOff=0, VecDispCentered, VecDispStaggered, VecDispUv, NumVecDispModes };
+
+ Painter(QWidget* par = 0) : QObject(par) {}
+ virtual ~Painter() {}
+
+ virtual std::string clickLine(const Vec3& p0, const Vec3& p1) { return ""; }
+ virtual void attachWidget(QLayout* layout) {}
+signals:
+ void setViewport(const Vec3i& gridsize);
+
+public slots:
+ virtual void paint() = 0;
+ virtual void doEvent(int e, int param=0) = 0;
+};
+
+//! Base clas for all painters that require access to a locked PbClass
+/*! Derived classes have to implement paint, update, getID, processKeyEvent. doEvent is handled in this class */
+class LockedObjPainter : public Painter {
+ Q_OBJECT
+public:
+ LockedObjPainter(QWidget* par = 0) : Painter(par), mRequestUpdate(false), mObject(NULL), mObjIndex(-1) {}
+
+ void doEvent(int e, int param=0); // don't overload, use processKeyEvent and update instead
+
+protected:
+ void nextObject();
+ virtual std::string getID() = 0;
+ virtual void update() = 0;
+ virtual void processKeyEvent(PainterEvent e, int param) = 0;
+
+ bool mRequestUpdate;
+ PbClass* mObject;
+ int mObjIndex;
+};
+
+//! Painter object for int,Real,Vec3 grids
+template<class T>
+class GridPainter : public LockedObjPainter {
+public:
+ GridPainter(FlagGrid** flags = NULL, QWidget* par = 0);
+ ~GridPainter();
+
+ void paint();
+ void attachWidget(QLayout* layout);
+ Grid<T>** getGridPtr() { return &mLocalGrid; }
+ int getPlane() { return mPlane; }
+ int getDim() { return mDim; }
+ int getMax() { return mMax; }
+ virtual std::string clickLine(const Vec3& p0, const Vec3& p1);
+
+protected:
+ std::string getID();
+ Real getScale();
+ void update();
+ void updateText();
+ void processKeyEvent(PainterEvent e, int param);
+ void processSpecificKeyEvent(PainterEvent e, int param);
+ //void paintGridLines(bool lines, bool box);
+
+ Real mMaxVal;
+ int mDim, mPlane, mMax;
+ Grid<T>* mLocalGrid;
+ FlagGrid** mFlags;
+ QLabel* mInfo;
+ bool mHide; // hide all grids?
+ bool mHideLocal; // hide only this type?
+ int mDispMode; // display modes
+ std::map<PbClass*, Real> mValScale;
+};
+
+}
+
+#endif
+
+
diff --git a/source/blender/python/manta_pp/gui/painter.h.reg b/source/blender/python/manta_pp/gui/painter.h.reg
new file mode 100644
index 00000000000..73dfb7feeee
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/painter.h.reg
@@ -0,0 +1 @@
+#include "gui/painter.h"
diff --git a/source/blender/python/manta_pp/gui/painter.h.reg.cpp b/source/blender/python/manta_pp/gui/painter.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/painter.h.reg.cpp
diff --git a/source/blender/python/manta_pp/gui/particlepainter.cpp b/source/blender/python/manta_pp/gui/particlepainter.cpp
new file mode 100644
index 00000000000..fca56377f85
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/particlepainter.cpp
@@ -0,0 +1,370 @@
+
+
+
+
+
+// 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
+ *
+ * Painting particle systems
+ *
+ ******************************************************************************/
+
+#include <ctime>
+#include "particlepainter.h"
+#include <sstream>
+#include <iomanip>
+#include <QtOpenGL>
+#include "vortexpart.h"
+#include "turbulencepart.h"
+
+using namespace std;
+
+namespace Manta {
+
+ParticlePainter::ParticlePainter(GridPainter<int>* gridRef, QWidget* par)
+ : LockedObjPainter(par), mGridRef(gridRef), mLocal(0), mMode(PaintVel), mDisplayMode(0),
+ mLastPdata(-1), mHavePdata(false), mMaxVal(0.)
+{
+ mInfo = new QLabel();
+}
+
+ParticlePainter::~ParticlePainter() {
+ if (mLocal)
+ delete mLocal;
+}
+
+void ParticlePainter::attachWidget(QLayout* layout) {
+ layout->addWidget(mInfo);
+}
+
+void ParticlePainter::update() {
+ ParticleBase* src = (ParticleBase*) mObject;
+
+ // always reallocate
+ if (mLocal)
+ delete mLocal;
+
+ mLocal = src->clone();
+
+ updateText();
+}
+
+string ParticlePainter::getID() { return "ParticleBase"; }
+
+Real ParticlePainter::getScale() {
+ if (!mObject) return 0;
+
+ if (mValScale.find(mObject) == mValScale.end()) {
+ Real s = 1.0;
+ //if (mLocalGrid->getType() & GridBase::TypeVec3) s = 0.4;
+ mValScale[mObject] = s;
+ }
+ return mValScale[mObject];
+
+}
+
+void ParticlePainter::processKeyEvent(PainterEvent e, int param) {
+ if (e == EventNextSystem)
+ nextObject();
+ else if (e == EventScalePdataDown && mObject)
+ mValScale[mObject] = getScale() * 0.5;
+ else if (e == EventScalePdataUp && mObject)
+ mValScale[mObject] = getScale() * 2.0;
+ else if (e == EventToggleParticles) {
+ mMode++; // apply modulo later depending on particle system
+ //if(mMode>PaintVel) mMode=PaintOff;
+ }
+ else if (e == EventNextParticleDisplayMode) {
+ mDisplayMode++;
+ }
+ else return;
+
+ updateText();
+}
+
+void ParticlePainter::updateText() {
+ ostringstream s;
+
+ if (mObject && !(mMode==PaintOff) ) {
+ s << mLocal->infoString() << endl;
+ s << mPdataInfo;
+ if(mHavePdata) {
+ s << "-> Max " << fixed << setprecision(2) << mMaxVal << " Scale " << getScale() << endl;
+ }
+ }
+ mInfo->setText( s.str().c_str() );
+}
+
+
+static inline void glVertex(const Vec3& v, Real dx) {
+ glVertex3f(v.x * dx, v.y * dx, v.z * dx);
+}
+
+static inline void glColor(const Vec3& color) {
+ glColor3f( std::max(0.0f,std::min(1.0f,(float)color.x)),
+ std::max(0.0f,std::min(1.0f,(float)color.y)),
+ std::max(0.0f,std::min(1.0f,(float)color.z)) );
+}
+
+void ParticlePainter::paint() {
+ if (!mObject) return;
+ if (mMode == PaintOff) return;
+ float dx = mLocal->getParent()->getDx();
+ mHavePdata = false;
+ mMaxVal = 0.;
+
+ glDisable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST); // disable depth test for particles, clashes with display plane for regular ones
+ glDisable(GL_LIGHTING);
+
+ // draw points
+ if(mLocal->getType() == ParticleBase::VORTEX) {
+ VortexParticleSystem* vp = (VortexParticleSystem*) mLocal;
+ glColor3f(1,1,0);
+ for(int i=0; i<vp->size(); i++) {
+ if (vp->isActive(i)) {
+ Vec3 pos = (*vp)[i].pos;
+
+ glPointSize((*vp)[i].sigma);
+
+ glBegin(GL_POINTS);
+ glVertex(pos, dx);
+ glEnd();
+ }
+ }
+ } else if (mLocal->getType() == ParticleBase::FILAMENT) {
+ // Filaments don't work yet
+ /*VortexFilamentSystem* fp = (VortexFilamentSystem*) mLocal;
+ glColor3f(1,1,0);
+
+ for(int i=0; i<fp->segSize(); i++) {
+ if (!fp->isSegActive(i)) continue;
+ const VortexRing& r = fp->seg(i);
+
+ glPointSize(1.0);
+ glBegin(GL_LINES);
+ for(int j=0; j<r.size(); j++) {
+ glVertex( (*fp)[r.idx0(j)].pos, dx);
+ glVertex( (*fp)[r.idx1(j)].pos, dx);
+ }
+ glEnd();
+ } */
+ } else if(mLocal->getType() == ParticleBase::TURBULENCE) {
+ TurbulenceParticleSystem* vp = (TurbulenceParticleSystem*) mLocal;
+ glPointSize(2.5);
+ glColor3f(0,1,0);
+ glBegin(GL_POINTS);
+ for(int i=0; i<(int)vp->size(); i++) {
+ Vec3 pos = (*vp)[i].pos;
+ glColor((*vp)[i].color);
+ glVertex(pos, dx);
+
+ }
+ glEnd();
+
+ } else if(mLocal->getType() == ParticleBase::PARTICLE) {
+ paintBasicSys();
+ }
+
+ glPointSize(1.0);
+ glEnable(GL_DEPTH_TEST);
+}
+
+void ParticlePainter::paintBasicSys() {
+ BasicParticleSystem* bp = (BasicParticleSystem*) mLocal;
+ //int dim = mGridRef->getDim();
+
+ // obtain current plane & draw settings
+ int dim = mGridRef->getDim();
+ Real factor = mGridRef->getMax() / mLocal->getParent()->getGridSize()[dim];
+ int plane = factor * mGridRef->getPlane();
+ Real scale = getScale();
+ float dx = mLocal->getParent()->getDx();
+
+ // draw other particle data, if available
+ int pdataId = mMode % (bp->getNumPdata() + 2);
+ std::ostringstream infoStr;
+ bool drewPoints = false;
+
+ if( pdataId==0 ) {
+ // dont draw any points
+ infoStr << "Off\n";
+ drewPoints = true;
+ } else if( pdataId==1 ) {
+ // dont draw data, only flags with center below
+ infoStr << "Drawing center & flags\n";
+ } else if (bp->getNumPdata() > 0) {
+ int pdNum = pdataId-2; // start at 0
+ ParticleDataBase* pdb = bp->getPdata(pdNum);
+
+ switch (pdb->getType() ) {
+
+ case ParticleDataBase::TypeReal: {
+ ParticleDataImpl<Real>* pdi = dynamic_cast<ParticleDataImpl<Real>*>(pdb);
+ if(!pdi) break;
+ mHavePdata = true;
+ drewPoints = true;
+ glPointSize(1.5);
+ glBegin(GL_POINTS);
+ for(int i=0; i<(int)bp->size(); i++) {
+ if (!bp->isActive(i)) continue;
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+ mMaxVal = std::max( pdi->get(i), mMaxVal );
+ Real val = pdi->get(i) * scale;
+ glColor3f(0,val,0);
+ glVertex(pos, dx);
+ }
+ glEnd();
+ infoStr << "Pdata '"<<pdi->getName()<<"' #"<<pdNum<<", real\n";
+ } break;
+
+ case ParticleDataBase::TypeInt: {
+ ParticleDataImpl<int>* pdi = dynamic_cast<ParticleDataImpl<int>*>(pdb);
+ if(!pdi) break;
+ mHavePdata = true;
+ drewPoints = true;
+ glPointSize(1.5);
+ glBegin(GL_POINTS);
+ for(int i=0; i<(int)bp->size(); i++) {
+ if (!bp->isActive(i)) continue;
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+ Real val = pdi->get(i);
+ mMaxVal = std::max( val, mMaxVal );
+ val *= scale;
+ glColor3f(0,val,0);
+ glVertex(pos, dx);
+ }
+ glEnd();
+ infoStr << "Pdata '"<<pdi->getName()<<"' #"<<pdNum<<", int\n";
+ } break;
+
+ case ParticleDataBase::TypeVec3: {
+ ParticleDataImpl<Vec3>* pdi = dynamic_cast<ParticleDataImpl<Vec3>*>(pdb);
+ if(!pdi) break;
+ mHavePdata = true;
+
+ // particle vector data can be drawn in different ways...
+ mDisplayMode = mDisplayMode%3;
+
+ switch(mDisplayMode) {
+ case 0: // lines
+ glBegin(GL_LINES);
+ for(int i=0; i<(int)bp->size(); i++) {
+ if (!bp->isActive(i)) continue;
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+ mMaxVal = std::max( norm(pdi->get(i)), mMaxVal );
+ Vec3 val = pdi->get(i) * scale;
+ glColor3f(0.5,0.0,0);
+ glVertex(pos, dx);
+ pos += val;
+ glColor3f(0.5,1.0,0);
+ glVertex(pos, dx);
+ }
+ glEnd();
+ break;
+ case 1:
+ // colored points
+ glPointSize(2.0);
+ glBegin(GL_POINTS);
+ for(int i=0; i<(int)bp->size(); i++) {
+ if (!bp->isActive(i)) continue;
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+ mMaxVal = std::max( norm(pdi->get(i)), mMaxVal );
+ Vec3 val = pdi->get(i) * scale;
+ for(int c=0; c<3; ++c) val[c] = fmod( (Real)val[c], (Real)1.);
+
+ glColor3f(val[0],val[1],val[2]);
+ glVertex(pos, dx);
+ //pos += val;
+ //glColor3f(0.5,1.0,0);
+ //glVertex(pos, dx);
+ }
+ glEnd();
+ drewPoints = true;
+ break;
+ case 2:
+ glClear(GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+
+ // colored by magnitude all
+ glPointSize(2.0);
+ glBegin(GL_POINTS);
+ for(int i=0; i<(int)bp->size(); i++) {
+ if (!bp->isActive(i)) continue;
+ Vec3 pos = (*bp)[i].pos;
+ mMaxVal = std::max( norm(pdi->get(i)), mMaxVal );
+ Vec3 val = Vec3( norm( pdi->get(i) * scale ) );
+ val[2] += 0.5; // base blue
+ for(int c=0; c<3; ++c) val[c] = std::min( (Real)val[c], (Real)1.);
+
+ glColor3f(val[0],val[1],val[2]);
+ glVertex(pos, dx);
+ }
+ glEnd();
+ drewPoints = true;
+ break;
+ }
+
+ infoStr << "Pdata '"<<pdi->getName()<<"' #"<<pdNum<<", vec3\n";
+ } break;
+
+ default: {
+ // skip...
+ } break;
+ }
+ }
+
+ mPdataInfo = infoStr.str();
+ // enforce refresh upon change
+ if(mLastPdata!=pdataId) {
+ mLastPdata = pdataId;
+ updateText();
+ }
+
+ // otherwise draw center
+ if(!drewPoints) {
+ glPointSize(1.5);
+ glBegin(GL_POINTS);
+
+ for(int i=0; i<(int)bp->size(); i++) {
+ Vec3 pos = (*bp)[i].pos;
+ if (pos[dim] < plane || pos[dim] > plane + 1.0f) continue;
+
+ if(!bp->isActive(i) ) {
+ glColor3f(1.0, 0., 0.); // deleted, red
+ } else if(bp->getStatus(i) & ParticleBase::PNEW ) {
+ glColor3f(0.0, 1.0, 0.); // new, green
+ } else {
+ //glColor3f(0, 0.0, 1.0); // regular, blue
+ glColor3f(1.0, 1.0, 1.0); // regular, white - hi contrast
+ }
+ glVertex(pos, dx);
+
+ }
+ glEnd();
+ }
+
+ // draw basic part sys done
+}
+
+} // namespace
+
+
+
diff --git a/source/blender/python/manta_pp/gui/particlepainter.h b/source/blender/python/manta_pp/gui/particlepainter.h
new file mode 100644
index 00000000000..ba482b38bc6
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/particlepainter.h
@@ -0,0 +1,74 @@
+
+
+
+
+
+// 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
+ *
+ * Painting particle systems
+ *
+ ******************************************************************************/
+
+#ifndef _PARTICLEPAINTER_H_
+#define _PARTICLEPAINTER_H_
+
+#include "painter.h"
+#include "particle.h"
+
+namespace Manta {
+
+//! Painter object for Particle Systems
+class ParticlePainter : public LockedObjPainter {
+ Q_OBJECT
+public:
+ ParticlePainter(GridPainter<int>* gridRef, QWidget* par = 0);
+ ~ParticlePainter();
+
+ void paint();
+ void attachWidget(QLayout* layout);
+
+ enum PaintModes { PaintOff=0, PaintVel=1, PaintPos=2 };
+
+protected:
+ std::string getID();
+ Real getScale();
+ void update();
+ void updateText();
+ void processKeyEvent(PainterEvent e, int param);
+
+ GridPainter<int>* mGridRef;
+ ParticleBase* mLocal;
+ QLabel* mInfo;
+
+ //! for standard particle systems, this is used to select the data channel (display is changed with displayMode below)
+ int mMode;
+ //! for BasicParticleSystem , change the way data channels are displayed
+ int mDisplayMode;
+
+ int mLastPdata;
+ bool mHavePdata;
+ Real mMaxVal;
+ std::string mPdataInfo;
+ std::map<PbClass*, Real> mValScale;
+
+ void paintBasicSys();
+};
+
+} // namespace
+
+#endif
+
+
diff --git a/source/blender/python/manta_pp/gui/particlepainter.h.reg b/source/blender/python/manta_pp/gui/particlepainter.h.reg
new file mode 100644
index 00000000000..b1580c96d67
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/particlepainter.h.reg
@@ -0,0 +1 @@
+#include "gui/particlepainter.h"
diff --git a/source/blender/python/manta_pp/gui/particlepainter.h.reg.cpp b/source/blender/python/manta_pp/gui/particlepainter.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/particlepainter.h.reg.cpp
diff --git a/source/blender/python/manta_pp/gui/qtmain.cpp b/source/blender/python/manta_pp/gui/qtmain.cpp
new file mode 100644
index 00000000000..6c46d607cb2
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/qtmain.cpp
@@ -0,0 +1,163 @@
+
+
+
+
+
+// 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
+ *
+ * QT threads
+ *
+ ******************************************************************************/
+
+#include "mainwindow.h"
+#include "qtmain.h"
+#include "customctrl.h"
+
+using namespace std;
+
+// execute python script
+// from pymain.cpp
+extern void runScript(vector<string>& args);
+
+namespace Manta {
+
+GuiThread* gGuiThread = NULL;
+MainThread* gMainThread = NULL;
+
+MainThread::MainThread(vector<string>& args) : mFinished(false), mArgs(args) {
+}
+
+void MainThread::run() {
+ runScript(mArgs);
+}
+
+void MainThread::sendAndWait(int e) {
+ mMutex.lock();
+ emit sendToGui(e);
+ while(!mWait.wait(&mMutex, 250))
+ if (gGuiThread->getWindow()->closeRequest()) {
+ mMutex.unlock();
+ throw Error("User interrupt");
+ }
+ mMutex.unlock();
+}
+
+void MainThread::send(int e) {
+ emit sendToGui(e);
+}
+
+void MainThread::killMe() {
+ if (!mFinished) {
+ wait(1000);
+ if (!mFinished) {
+ cout << "worker thread still running, terminate" << endl;
+ terminate();
+ return;
+ }
+ }
+ wait();
+}
+
+void MainThread::wakeUp() {
+ mMutex.lock();
+ mWait.wakeAll();
+ mMutex.unlock();
+}
+
+GuiThread::GuiThread(QApplication& app) : mApp(app), mWnd() {
+}
+
+void GuiThread::sendEvent(int e) {
+ mApp.postEvent(&mWnd, new QEvent((QEvent::Type)e));
+}
+
+void GuiThread::exitApp() {
+ mApp.exit(1);
+}
+
+void guiMain(int argc, char* argv[]) {
+ QApplication app(argc, argv);
+
+ // parse arguments
+ vector<string> args;
+ for (int i=1;i<argc;i++) args.push_back(argv[i]);
+
+ // Show file dialog if no argument is present
+ if (argc <= 1) {
+ QString filename = QFileDialog::getOpenFileName(0, "Open scene file", "", "Python scene files (*.py)");
+ args.push_back(filename.toLatin1().data());
+ }
+
+ GuiThread gui(app);
+ MainThread worker(args);
+
+ gGuiThread = &gui;
+ gMainThread = &worker;
+
+ // connect thread wakeup and termination signals
+ QObject::connect(&worker, SIGNAL(sendToGui(int)), &gui, SLOT(sendEvent(int)));
+ QObject::connect(gui.getWindow(), SIGNAL(wakeMain()), &worker, SLOT(wakeUp()));
+ QObject::connect(gui.getWindow(), SIGNAL(killMain()), &worker, SLOT(killMe()));
+ QObject::connect(gui.getWindow(), SIGNAL(exitApp()), &gui, SLOT(exitApp()));
+ app.setQuitOnLastWindowClosed(true);
+
+ // Start main program threads
+ worker.start();
+ app.exec();
+}
+
+void guiWaitFinish() {
+ gMainThread->setFinished();
+ gMainThread->send((int)MainWnd::EventInstantKill);
+ /*
+ if (gGuiThread->getWindow()->closeRequest())
+ return;
+
+ gMainThread->sendAndWait((int)MainWnd::EventFinalUpdate);
+ gGuiThread->getWindow()->pause();
+ while (gGuiThread->getWindow()->pauseRequest())
+ gMainThread->threadSleep(10); */
+}
+
+//******************************************************************************
+// Python adapter class
+
+
+// external callback functions
+void updateQtGui(bool full, int frame, const string& curPlugin) {
+ if (!gGuiThread->getWindow()->isVisible()) return;
+ if (gGuiThread->getWindow()->closeRequest()) throw Error("User interrupt");
+
+ if (full && frame >= 0) gGuiThread->getWindow()->setStep(frame);
+ gMainThread->sendAndWait(full ? (int)MainWnd::EventFullUpdate : (int)MainWnd::EventStepUpdate);
+
+ if (gGuiThread->getWindow()->pauseRequest()) {
+ if (!curPlugin.empty()) {
+ cout << "Step: " << curPlugin << endl;
+ }
+ gGuiThread->getWindow()->setPauseStatus(true);
+ while (gGuiThread->getWindow()->pauseRequest()) {
+ gMainThread->threadSleep(10);
+ }
+ if (gGuiThread->getWindow()->closeRequest()) throw Error("User interrupt");
+ gGuiThread->getWindow()->setPauseStatus(false);
+ }
+ gGuiThread->getWindow()->stepReset(full);
+}
+
+} //namespace
+
+
diff --git a/source/blender/python/manta_pp/gui/qtmain.h b/source/blender/python/manta_pp/gui/qtmain.h
new file mode 100644
index 00000000000..289e817159c
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/qtmain.h
@@ -0,0 +1,89 @@
+
+
+
+
+
+// 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
+ *
+ * QT threads
+ *
+ ******************************************************************************/
+#ifndef _QTMAIN_H_
+#define _QTMAIN_H_
+
+#include <QThread>
+#include <QApplication>
+#include <vector>
+#include <QMutex>
+#include <QWaitCondition>
+#include "mainwindow.h"
+#include "manta.h"
+
+namespace Manta {
+
+//! encapsulates GUI thread
+class GuiThread : public QObject {
+ Q_OBJECT
+public:
+
+ GuiThread(QApplication& app);
+
+ //! obtain window handle
+ inline MainWnd* getWindow() { return &mWnd; }
+
+public slots:
+ void sendEvent(int e);
+ void exitApp();
+
+protected:
+ QApplication& mApp;
+ MainWnd mWnd;
+};
+
+//! encapsulates working/python thread
+class MainThread : public QThread {
+ Q_OBJECT
+public:
+ MainThread(std::vector<std::string>& args);
+
+ //! send event to GUI and wait for completion
+ void sendAndWait(int e);
+ void send(int e);
+
+ //! sleep for given number of milliseconds
+ inline void threadSleep(int msec) { msleep(msec); }
+ inline bool isFinished() { return mFinished; }
+ inline void setFinished() { mFinished = true; }
+
+public slots:
+ void wakeUp();
+ void killMe();
+
+signals:
+ void sendToGui(int event);
+
+protected:
+ QMutex mMutex;
+ QWaitCondition mWait;
+ bool mFinished;
+ std::vector<std::string> mArgs;
+ void run();
+};
+
+} // namespace
+
+#endif
+
diff --git a/source/blender/python/manta_pp/gui/qtmain.h.reg b/source/blender/python/manta_pp/gui/qtmain.h.reg
new file mode 100644
index 00000000000..0d932b9aeba
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/qtmain.h.reg
@@ -0,0 +1 @@
+#include "gui/qtmain.h"
diff --git a/source/blender/python/manta_pp/gui/qtmain.h.reg.cpp b/source/blender/python/manta_pp/gui/qtmain.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/gui/qtmain.h.reg.cpp
diff --git a/source/blender/python/manta_pp/hginfo.h b/source/blender/python/manta_pp/hginfo.h
new file mode 100644
index 00000000000..4caf264131c
--- /dev/null
+++ b/source/blender/python/manta_pp/hginfo.h
@@ -0,0 +1,4 @@
+
+
+#define MANTA_HG_VERSION "commit 79cf1d3f26350f1a10c829b1367e8e5d096979dd"
+
diff --git a/source/blender/python/manta_pp/kernel.cpp b/source/blender/python/manta_pp/kernel.cpp
new file mode 100644
index 00000000000..746ad2b77db
--- /dev/null
+++ b/source/blender/python/manta_pp/kernel.cpp
@@ -0,0 +1,49 @@
+
+
+
+
+
+// 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
+ *
+ * Function and macros for defining compution kernels over grids
+ *
+ ******************************************************************************/
+
+#include "kernel.h"
+#include "grid.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),
+ X (base->getStrideX()),
+ Y (base->getStrideY()),
+ Z (base->getStrideZ()),
+ size (base->getSizeX() * base->getSizeY() * base->getSizeZ()),
+ threadId(0),threadNum(1) {}
+
+KernelBase::KernelBase(int sz) :
+ size(sz),
+ threadId(0),threadNum(1) {}
+
+
+} // namespace
+
+
diff --git a/source/blender/python/manta_pp/kernel.h b/source/blender/python/manta_pp/kernel.h
new file mode 100644
index 00000000000..143fca906c7
--- /dev/null
+++ b/source/blender/python/manta_pp/kernel.h
@@ -0,0 +1,95 @@
+
+
+
+
+
+// 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
+ *
+ * Function and macros for defining compution kernels over grids
+ *
+ ******************************************************************************/
+
+#ifndef _KERNEL_H
+#define _KERNEL_H
+
+#ifdef TBB
+# include <tbb/blocked_range3d.h>
+# include <tbb/blocked_range.h>
+# include <tbb/parallel_for.h>
+# include <tbb/parallel_reduce.h>
+#endif
+
+#ifdef OPENMP
+# include <omp.h>
+#endif
+
+namespace Manta {
+// fwd decl
+class GridBase;
+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(int 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(int idx=0, total=(parts).size(); idx<total; idx++)
+
+struct KernelBase {
+ int maxX, maxY, maxZ, minZ;
+ int X, Y, Z;
+ int size;
+ //! store thread info for this kernel
+ int threadId, threadNum;
+
+ KernelBase(int num);
+ KernelBase(const GridBase* base, int bnd);
+ //KernelBase(int _maxX, int _maxY, int _maxZ, int _maxC, int _minZ, int _X, int _Y, int _Z);
+
+ // specify in your derived classes:
+
+ // kernel operators
+ // ijk mode: void operator() (size_t idx)
+ // idx mode: void operator() (size_t i, size_t j, size_t k)
+
+ // reduce mode:
+ // void join(classname& other)
+ // void setup()
+};
+
+} // namespace
+
+// Define plugin documentation group
+// all kernels will automatically be added to this group
+/*! @defgroup Kernels Computation Kernels
+ */
+
+#endif
+
+
diff --git a/source/blender/python/manta_pp/kernel.h.reg b/source/blender/python/manta_pp/kernel.h.reg
new file mode 100644
index 00000000000..6457157c184
--- /dev/null
+++ b/source/blender/python/manta_pp/kernel.h.reg
@@ -0,0 +1 @@
+#include "kernel.h"
diff --git a/source/blender/python/manta_pp/kernel.h.reg.cpp b/source/blender/python/manta_pp/kernel.h.reg.cpp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/source/blender/python/manta_pp/kernel.h.reg.cpp
diff --git a/source/blender/python/manta_pp/levelset.cpp b/source/blender/python/manta_pp/levelset.cpp
new file mode 100644
index 00000000000..be1c2ffdcfe
--- /dev/null
+++ b/source/blender/python/manta_pp/levelset.cpp
@@ -0,0 +1,346 @@
+
+
+
+
+
+// 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
+ *
+ * Levelset
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "fastmarch.h"
+#include "kernel.h"
+#include "mcubes.h"
+#include "mesh.h"
+
+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(FlagGrid& flags, Grid<int>& fmFlags, LevelsetGrid& phi, bool ignoreWalls, int obstacleType) : KernelBase(&flags,1) ,flags(flags),fmFlags(fmFlags),phi(phi),ignoreWalls(ignoreWalls),obstacleType(obstacleType) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<int>& fmFlags, LevelsetGrid& phi, bool ignoreWalls, int obstacleType ) {
+ const int idx = flags.index(i,j,k);
+ const Real v = phi[idx];
+ if (v>=0 && (!ignoreWalls || (flags[idx] & obstacleType) == 0))
+ fmFlags[idx] = FlagInited;
+ else
+ fmFlags[idx] = 0;
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<int>& getArg1() { return fmFlags; } typedef Grid<int> type1;inline LevelsetGrid& getArg2() { return phi; } typedef LevelsetGrid type2;inline bool& getArg3() { return ignoreWalls; } typedef bool type3;inline int& getArg4() { return obstacleType; } typedef int type4; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, flags,fmFlags,phi,ignoreWalls,obstacleType); } FlagGrid& flags; Grid<int>& fmFlags; LevelsetGrid& phi; bool ignoreWalls; int obstacleType; };
+
+
+ struct InitFmOut : public KernelBase { InitFmOut(FlagGrid& flags, Grid<int>& fmFlags, LevelsetGrid& phi, bool ignoreWalls, int obstacleType) : KernelBase(&flags,1) ,flags(flags),fmFlags(fmFlags),phi(phi),ignoreWalls(ignoreWalls),obstacleType(obstacleType) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<int>& fmFlags, LevelsetGrid& phi, bool ignoreWalls, int obstacleType ) {
+ const int 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 FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<int>& getArg1() { return fmFlags; } typedef Grid<int> type1;inline LevelsetGrid& getArg2() { return phi; } typedef LevelsetGrid type2;inline bool& getArg3() { return ignoreWalls; } typedef bool type3;inline int& getArg4() { return obstacleType; } typedef int type4; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, flags,fmFlags,phi,ignoreWalls,obstacleType); } FlagGrid& flags; Grid<int>& fmFlags; LevelsetGrid& phi; bool ignoreWalls; int obstacleType; };
+
+
+ struct SetUninitialized : public KernelBase { SetUninitialized(Grid<int>& fmFlags, LevelsetGrid& phi, const Real val) : KernelBase(&fmFlags,1) ,fmFlags(fmFlags),phi(phi),val(val) { run(); } inline void op(int i, int j, int k, Grid<int>& fmFlags, LevelsetGrid& phi, const Real val ) {
+ if (fmFlags(i,j,k) != FlagInited)
+ phi(i,j,k) = val;
+} inline Grid<int>& getArg0() { return fmFlags; } typedef Grid<int> type0;inline LevelsetGrid& getArg1() { return phi; } typedef LevelsetGrid type1;inline const Real& getArg2() { return val; } typedef Real type2; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, fmFlags,phi,val); } Grid<int>& fmFlags; LevelsetGrid& phi; const Real val; };
+
+template<bool inward>
+inline bool isAtInterface(Grid<int>& fmFlags, LevelsetGrid& phi, const Vec3i& p) {
+ // check for interface
+ for (int nb=0; nb<6; 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;
+}
+
+// helper function to compute normal
+inline Vec3 getNormal(const Grid<Real>& data, int i, int j, int k) {
+ 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 (i < 1) i = 1;
+ if (j < 1) j = 1;
+ if (k < 1) k = 1;
+ 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+1) - data(i ,j ,k-1) );
+}
+
+//************************************************************************
+// Levelset class def
+
+LevelsetGrid::LevelsetGrid(FluidSolver* parent, bool show)
+ : Grid<Real>(parent, 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) { run(); } inline void op(int idx, Grid<Real>& a, const Grid<Real>& b ) {
+ 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, a,b); } Grid<Real>& a; const Grid<Real>& b; };
+
+void LevelsetGrid::join(const LevelsetGrid& o) {
+ KnJoin(*this, o);
+}
+
+//! re-init levelset and extrapolate velocities (in & out)
+// note - uses flags to identify border (could also be done based on ls values)
+void LevelsetGrid::reinitMarching(
+ FlagGrid& flags, Real maxTime, MACGrid* velTransport,
+ bool ignoreWalls, bool correctOuterLayer, int obstacleType
+ , Grid<Real>* normSpeed )
+{
+ const int dim = (is3D() ? 3 : 2);
+
+ Grid<int> fmFlags(mParent);
+ LevelsetGrid& phi = *this;
+
+ FastMarch<FmHeapEntryIn, -1> marchIn (flags, fmFlags, phi, maxTime, NULL, NULL);
+
+ // march inside
+ InitFmIn (flags, fmFlags, phi, ignoreWalls, obstacleType);
+
+ FOR_IJK_BND(flags, 1) {
+ if (fmFlags(i,j,k) == FlagInited) continue;
+ if ((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 ((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 (fmFlags, phi, -maxTime - 1.);
+
+ InitFmOut (flags, fmFlags, phi, ignoreWalls, obstacleType);
+
+ FastMarch<FmHeapEntryOut, +1> marchOut(flags, fmFlags, phi, maxTime, velTransport, normSpeed);
+
+ // NT_DEBUG
+ if(normSpeed && velTransport) {
+ FOR_IJK_BND(flags, 1) {
+ Vec3 vel = velTransport->getCentered(i,j,k);
+ Vec3 norm = getNormal(phi, i,j,k); normalize(norm);
+ (*normSpeed)(i,j,k) = dot( norm , vel );
+ }
+ }
+
+ // 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 ((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 ((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 ((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 ((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 (fmFlags, phi, +maxTime + 1.);
+}
+
+void LevelsetGrid::initFromFlags(FlagGrid& flags, bool ignoreWalls) {
+ FOR_IDX(*this) {
+ if (flags.isFluid(idx) || (ignoreWalls && flags.isObstacle(idx)))
+ mData[idx] = -0.5;
+ else
+ mData[idx] = 0.5;
+ }
+}
+
+// note - the following functions are experimental, might be removed at some point NT_DEBUG
+ struct knGridRemapLsMask : public KernelBase { knGridRemapLsMask(Grid<Real>& me, Real min, Real max, Real fac) : KernelBase(&me,0) ,me(me),min(min),max(max),fac(fac) { run(); } inline void op(int idx, Grid<Real>& me, Real min, Real max, Real fac ) {
+ me[idx] = (clamp(me[idx], min, max) - min) * fac;
+
+ // now we have 0..1 range, convert to hat around 1/2
+ me[idx] = me[idx] * 2.;
+ if(me[idx]>1.0) me[idx] = 2. - me[idx];
+} inline Grid<Real>& getArg0() { return me; } typedef Grid<Real> type0;inline Real& getArg1() { return min; } typedef Real type1;inline Real& getArg2() { return max; } typedef Real type2;inline Real& getArg3() { return fac; } typedef Real type3; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,min,max,fac); } Grid<Real>& me; Real min; Real max; Real fac; };
+// remap min/max range to hat function around (min+max)/2
+void remapLsMask(Grid<Real>& phi, Real min, Real max) {
+ Real fac = 0.;
+ if ( fabs(max-min) > VECTOR_EPSILON ) fac = 1. / (max-min);
+ knGridRemapLsMask(phi, min, max, fac);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "remapLsMask" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<Real>& phi = *_args.getPtr<Grid<Real> >("phi",0,&_lock); Real min = _args.get<Real >("min",1,&_lock); Real max = _args.get<Real >("max",2,&_lock); _retval = getPyNone(); remapLsMask(phi,min,max); _args.check(); } pbFinalizePlugin(parent,"remapLsMask" ); return _retval; } catch(std::exception& e) { pbSetError("remapLsMask",e.what()); return 0; } } static const Pb::Register _RP_remapLsMask ("","remapLsMask",_W_0);
+
+//! 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;
+ vertex.normal = getNormalized(
+ getNormal( *this, i+cubieOffsetX[e1], j+cubieOffsetY[e1], k+cubieOffsetZ[e1]) * (1.0-mu) +
+ getNormal( *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();
+}
+
+
+} //namespace
+
+
diff --git a/source/blender/python/manta_pp/levelset.h b/source/blender/python/manta_pp/levelset.h
new file mode 100644
index 00000000000..6b1746ada23
--- /dev/null
+++ b/source/blender/python/manta_pp/levelset.h
@@ -0,0 +1,56 @@
+
+
+
+
+
+// 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
+ *
+ * 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); pbPreparePlugin(0, "LevelsetGrid::LevelsetGrid" ); { 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" ); return 0; } catch(std::exception& e) { pbSetError("LevelsetGrid::LevelsetGrid",e.what()); return -1; } }
+
+ //! reconstruct the levelset using fast marching
+
+
+void reinitMarching(FlagGrid& flags, Real maxTime=4.0, MACGrid* velTransport=NULL, bool ignoreWalls=false, bool correctOuterLayer=true, int obstacleType = FlagGrid::TypeObstacle, Grid<Real>* scalarTransport = NULL ); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::reinitMarching"); PyObject *_retval = 0; { ArgLocker _lock; 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); Grid<Real>* scalarTransport = _args.getPtrOpt<Grid<Real> >("scalarTransport",6,NULL ,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->reinitMarching(flags,maxTime,velTransport,ignoreWalls,correctOuterLayer,obstacleType,scalarTransport); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"LevelsetGrid::reinitMarching"); 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)); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::createMesh"); 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"); 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)); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::join"); 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"); return _retval; } catch(std::exception& e) { pbSetError("LevelsetGrid::join",e.what()); return 0; } }
+
+ //! initialize levelset from flags (+/- 0.5 heaviside)
+ void initFromFlags(FlagGrid& flags, bool ignoreWalls=false); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); LevelsetGrid* pbo = dynamic_cast<LevelsetGrid*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "LevelsetGrid::initFromFlags"); PyObject *_retval = 0; { ArgLocker _lock; 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"); return _retval; } catch(std::exception& e) { pbSetError("LevelsetGrid::initFromFlags",e.what()); return 0; } }
+ static Real invalidTimeValue(); public: PbArgs _args;}
+#define _C_LevelsetGrid
+;
+
+} //namespace
+#endif
+
+
diff --git a/source/blender/python/manta_pp/levelset.h.reg b/source/blender/python/manta_pp/levelset.h.reg
new file mode 100644
index 00000000000..d8191c3dceb
--- /dev/null
+++ b/source/blender/python/manta_pp/levelset.h.reg
@@ -0,0 +1,9 @@
+#include "levelset.h"
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","LevelsetGrid","Grid<$BT$>"); template<> const char* Namify<LevelsetGrid >::S = "LevelsetGrid";
+>LevelsetGrid^
+@LevelsetGrid^^Grid^Real
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","LevelsetGrid",LevelsetGrid::_W_0);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","reinitMarching",LevelsetGrid::_W_1);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","createMesh",LevelsetGrid::_W_2);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","join",LevelsetGrid::_W_3);
++LevelsetGrid^ static const Pb::Register _R_$IDX$ ("LevelsetGrid","initFromFlags",LevelsetGrid::_W_4);
diff --git a/source/blender/python/manta_pp/levelset.h.reg.cpp b/source/blender/python/manta_pp/levelset.h.reg.cpp
new file mode 100644
index 00000000000..200a459e80b
--- /dev/null
+++ b/source/blender/python/manta_pp/levelset.h.reg.cpp
@@ -0,0 +1,22 @@
+
+
+
+
+
+// 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_0 ("LevelsetGrid","LevelsetGrid","Grid<Real>"); template<> const char* Namify<LevelsetGrid >::S = "LevelsetGrid";
+ static const Pb::Register _R_1 ("LevelsetGrid","LevelsetGrid",LevelsetGrid::_W_0);
+ static const Pb::Register _R_2 ("LevelsetGrid","reinitMarching",LevelsetGrid::_W_1);
+ static const Pb::Register _R_3 ("LevelsetGrid","createMesh",LevelsetGrid::_W_2);
+ static const Pb::Register _R_4 ("LevelsetGrid","join",LevelsetGrid::_W_3);
+ static const Pb::Register _R_5 ("LevelsetGrid","initFromFlags",LevelsetGrid::_W_4);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/mesh.cpp b/source/blender/python/manta_pp/mesh.cpp
new file mode 100644
index 00000000000..2c6322003b6
--- /dev/null
+++ b/source/blender/python/manta_pp/mesh.cpp
@@ -0,0 +1,800 @@
+
+
+
+
+
+// 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
+ *
+ * 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 "fileio.h"
+#include "kernel.h"
+#include "shapes.h"
+#include <stack>
+
+using namespace std;
+namespace Manta {
+
+Mesh::Mesh(FluidSolver* parent) : PbClass(parent) {
+}
+
+Mesh::~Mesh() {
+}
+
+Mesh* Mesh::clone() {
+ Mesh* nm = new Mesh(mParent);
+ *nm = *this;
+ nm->setName(getName());
+ return nm;
+}
+
+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/3.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);
+}
+
+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(vector<Node>& nodes, const FlagGrid& flags, const MACGrid& vel, const Real dt) : KernelBase(nodes.size()) ,nodes(nodes),flags(flags),vel(vel),dt(dt) ,u((size)) { run(); } inline void op(int idx, vector<Node>& nodes, const FlagGrid& flags, const MACGrid& vel, const Real dt ,vector<Vec3> & u) {
+ if (nodes[idx].flags & Mesh::NfFixed)
+ u[idx] = _0;
+ else if (!flags.isInBounds(nodes[idx].pos,1))
+ u[idx] = _0;
+ else
+ u[idx] = vel.getInterpolated(nodes[idx].pos) * dt;
+} 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, nodes,flags,vel,dt,u); } vector<Node>& nodes; const FlagGrid& flags; const MACGrid& vel; const Real dt; vector<Vec3> u; };
+
+// advection plugin
+void Mesh::advectInGrid(FlagGrid& flaggrid, MACGrid& vel, int integrationMode) {
+ KnAdvectMeshInGrid kernel(mNodes, flaggrid, 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::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());
+ 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");
+ }
+ }
+ }
+ }
+}
+
+ void Mesh::SDFKernel(const int* partStart, const int* partLen, CVec3Ptr pos, CVec3Ptr normal, float* sdf, Vec3i gridRes, int intRadius, float safeRadius2, float cutoff2, float 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);
+ float sum = 0.0f;
+ float 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);
+ float 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);
+ float normSqr = r[0]*r[0] + r[1]*r[1] + r[2]*r[2];
+ float r2 = normSqr;
+ if (r2 < cutoff2) {
+ float 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;
+ }
+ }
+ }
+ }
+
+ inline int _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) { run(); } inline void op(int i, int j, int k, Grid<T>* grid, Grid<Real> sdf, T value, FlagGrid* respectFlags ) {
+ 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 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, grid,sdf,value,respectFlags); } Grid<T>* grid; Grid<Real> sdf; T value; FlagGrid* respectFlags; };
+
+ void Mesh::applyToGrid(GridBase* grid, FlagGrid* respectFlags, float cutoff) {
+ FluidSolver dummy(grid->getSize());
+ LevelsetGrid mesh_sdf(&dummy, false);
+ meshSDF(*this, mesh_sdf, 2., _args.get<float>("cutoff"));
+
+ 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");
+ }
+
+ void Mesh::meshSDF(Mesh& mesh, LevelsetGrid & levelset, float sigma, float cutoff)
+ {
+ if (cutoff<0) cutoff = 2*sigma;
+ float maxEdgeLength = 0.75;
+ float 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(size_t 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;
+ }
+
+ short axisA(0), axisB(1);
+ float u(0.),v(0.),w(0.); //barycentric uvw coords
+ Vec3 samplePoint,normal;
+ for (int sample0(0); sample0 < iterA; ++sample0){
+ u = float(1. * sample0 / iterA);
+ for (int sample1(0); sample1 < iterB; ++sample1){
+ v = float(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
+ const int numCells = gridRes.x * gridRes.y * gridRes.z;
+ vector<Real> gridDev(numCells);
+ for (int i=0; i<numCells; i++)
+ gridDev[i] = -cutoff;
+
+ // 1. count sources per cell
+ vector<int> srcPerCell(numCells);
+ for (size_t i=0; i<center.size(); i++) {
+ int cell = _cIndex(center[i], gridRes);
+ if (cell >= 0)
+ srcPerCell[cell]++;
+ }
+
+ // 2. create start index lookup
+ vector<int> srcCellStart(numCells);
+ int cnt=0;
+ for (int i=0; i<numCells; i++) {
+ srcCellStart[i] = cnt;
+ cnt += srcPerCell[i];
+ }
+
+ // 3. reorder nodes
+ CVec3Array reorderPos(center.size());
+ CVec3Array reorderNormal(center.size());
+ {
+ vector<int> curSrcCell(numCells);
+ for (int i=0; i<(int)center.size(); i++) {
+ int cell = _cIndex(center[i], gridRes);
+ if (cell < 0) continue;
+ int idx = srcCellStart[cell] + curSrcCell[cell];
+ reorderPos.set(idx, center[i]);
+ reorderNormal.set(idx, normals[i]);
+ curSrcCell[cell]++;
+ }
+ }
+
+ // construct parameters
+ float safeRadius = cutoff + sqrt(3.0)*0.5;
+ float safeRadius2 = safeRadius*safeRadius;
+ float cutoff2 = cutoff*cutoff;
+ float isigma2 = 1.0/(sigma*sigma);
+ int intRadius = (int)(cutoff+0.5);
+
+ SDFKernel(srcCellStart.data(), srcPerCell.data(),
+ reorderPos.data(), reorderNormal.data(),
+ gridDev.data(),
+ Vec3i(gridRes.x, gridRes.y, gridRes.z), intRadius, safeRadius2, cutoff2, isigma2);
+
+ for (int i=0;i<numCells; i++)
+ levelset[i] = gridDev[i];
+
+ // 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));
+ };
+ }
+
+} //namespace
+
+
diff --git a/source/blender/python/manta_pp/mesh.h b/source/blender/python/manta_pp/mesh.h
new file mode 100644
index 00000000000..7917fefcaf1
--- /dev/null
+++ b/source/blender/python/manta_pp/mesh.h
@@ -0,0 +1,273 @@
+
+
+
+
+
+// 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
+ *
+ * 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 "grid.h"
+#include "vectorbase.h"
+#include <set>
+namespace Manta {
+
+// fwd decl
+class FlagGrid;
+class MACGrid;
+class Shape;
+
+//! 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;
+};
+
+/*!adapted from Cudatools.h
+*/
+struct CVec3Ptr {
+ float *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; };
+};
+
+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<float> x, y, z;
+};
+
+//! 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); pbPreparePlugin(0, "Mesh::Mesh" ); { 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" ); 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; }
+
+ void clear();
+ Real computeCenterOfMass(Vec3& cm) const;
+ void computeVertexNormals();
+
+ // plugins
+ void load(std::string name, bool append = false); static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Mesh::load"); 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"); return _retval; } catch(std::exception& e) { pbSetError("Mesh::load",e.what()); return 0; } }
+ void fromShape(Shape& shape, 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)); pbPreparePlugin(pbo->getParent(), "Mesh::fromShape"); 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"); return _retval; } catch(std::exception& e) { pbSetError("Mesh::fromShape",e.what()); return 0; } }
+ void save(std::string name); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Mesh::save"); 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"); return _retval; } catch(std::exception& e) { pbSetError("Mesh::save",e.what()); return 0; } }
+ void advectInGrid(FlagGrid& flaggrid, MACGrid& vel, int integrationMode); static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Mesh::advectInGrid"); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flaggrid = *_args.getPtr<FlagGrid >("flaggrid",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(flaggrid,vel,integrationMode); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Mesh::advectInGrid"); return _retval; } catch(std::exception& e) { pbSetError("Mesh::advectInGrid",e.what()); return 0; } }
+ void scale(Vec3 s); static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Mesh::scale"); 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"); return _retval; } catch(std::exception& e) { pbSetError("Mesh::scale",e.what()); return 0; } }
+ void offset(Vec3 o); static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Mesh::offset"); 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"); return _retval; } catch(std::exception& e) { pbSetError("Mesh::offset",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(); }
+
+ 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) { 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) { 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(); }
+ void SDFKernel(const int* partStart, const int* partLen, CVec3Ptr pos, CVec3Ptr normal, float* sdf, Vec3i gridRes, int intRadius, float safeRadius2, float cutoff2, float isigma2);
+ void meshSDF(Mesh& mesh, LevelsetGrid& levelset, float sigma, float cutoff=-1); static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Mesh::meshSDF"); PyObject *_retval = 0; { ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); LevelsetGrid& levelset = *_args.getPtr<LevelsetGrid >("levelset",1,&_lock); float sigma = _args.get<float >("sigma",2,&_lock); float cutoff = _args.getOpt<float >("cutoff",3,-1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->meshSDF(mesh,levelset,sigma,cutoff); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Mesh::meshSDF"); return _retval; } catch(std::exception& e) { pbSetError("Mesh::meshSDF",e.what()); return 0; } }
+ void applyToGrid(GridBase* grid, FlagGrid* respectFlags=0, float cutoff=-1); static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); Mesh* pbo = dynamic_cast<Mesh*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "Mesh::applyToGrid"); PyObject *_retval = 0; { ArgLocker _lock; GridBase* grid = _args.getPtr<GridBase >("grid",0,&_lock); FlagGrid* respectFlags = _args.getPtrOpt<FlagGrid >("respectFlags",1,0,&_lock); float cutoff = _args.getOpt<float >("cutoff",2,-1,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->applyToGrid(grid,respectFlags,cutoff); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Mesh::applyToGrid"); return _retval; } catch(std::exception& e) { pbSetError("Mesh::applyToGrid",e.what()); return 0; } }
+
+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; public: PbArgs _args;}
+#define _C_Mesh
+;
+
+
+
+
+// ***************************************************************************************************************
+// 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);
+}
+
+
+
+} //namespace
+#endif
+
+
diff --git a/source/blender/python/manta_pp/mesh.h.reg b/source/blender/python/manta_pp/mesh.h.reg
new file mode 100644
index 00000000000..fa2e455d9d0
--- /dev/null
+++ b/source/blender/python/manta_pp/mesh.h.reg
@@ -0,0 +1,12 @@
+#include "mesh.h"
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","Mesh","PbClass"); template<> const char* Namify<Mesh >::S = "Mesh";
+>Mesh^
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","Mesh",Mesh::_W_0);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","load",Mesh::_W_1);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","fromShape",Mesh::_W_2);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","save",Mesh::_W_3);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","advectInGrid",Mesh::_W_4);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","scale",Mesh::_W_5);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","offset",Mesh::_W_6);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","meshSDF",Mesh::_W_7);
++Mesh^ static const Pb::Register _R_$IDX$ ("Mesh","applyToGrid",Mesh::_W_8);
diff --git a/source/blender/python/manta_pp/mesh.h.reg.cpp b/source/blender/python/manta_pp/mesh.h.reg.cpp
new file mode 100644
index 00000000000..37118fcc6c7
--- /dev/null
+++ b/source/blender/python/manta_pp/mesh.h.reg.cpp
@@ -0,0 +1,26 @@
+
+
+
+
+
+// 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_0 ("Mesh","Mesh","PbClass"); template<> const char* Namify<Mesh >::S = "Mesh";
+ static const Pb::Register _R_1 ("Mesh","Mesh",Mesh::_W_0);
+ static const Pb::Register _R_2 ("Mesh","load",Mesh::_W_1);
+ static const Pb::Register _R_3 ("Mesh","fromShape",Mesh::_W_2);
+ static const Pb::Register _R_4 ("Mesh","save",Mesh::_W_3);
+ static const Pb::Register _R_5 ("Mesh","advectInGrid",Mesh::_W_4);
+ static const Pb::Register _R_6 ("Mesh","scale",Mesh::_W_5);
+ static const Pb::Register _R_7 ("Mesh","offset",Mesh::_W_6);
+ static const Pb::Register _R_8 ("Mesh","meshSDF",Mesh::_W_7);
+ static const Pb::Register _R_9 ("Mesh","applyToGrid",Mesh::_W_8);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/movingobs.cpp b/source/blender/python/manta_pp/movingobs.cpp
new file mode 100644
index 00000000000..2893a4fe25e
--- /dev/null
+++ b/source/blender/python/manta_pp/movingobs.cpp
@@ -0,0 +1,105 @@
+
+
+
+
+
+// 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
+ *
+ * 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++) {
+ mShapes[i]->_args.clear();
+ mShapes[i]->_args.add("value", FlagGrid::TypeObstacle | mID);
+ mShapes[i]->applyToGrid(&flags, 0);
+ }
+ // 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
+
+
diff --git a/source/blender/python/manta_pp/movingobs.h b/source/blender/python/manta_pp/movingobs.h
new file mode 100644
index 00000000000..6ffcc59cf40
--- /dev/null
+++ b/source/blender/python/manta_pp/movingobs.h
@@ -0,0 +1,54 @@
+
+
+
+
+
+// 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
+ *
+ * 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); pbPreparePlugin(0, "MovingObstacle::MovingObstacle" ); { 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" ); 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)); pbPreparePlugin(pbo->getParent(), "MovingObstacle::add"); 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"); 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)); pbPreparePlugin(pbo->getParent(), "MovingObstacle::moveLinear"); 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"); 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)); pbPreparePlugin(pbo->getParent(), "MovingObstacle::projectOutside"); 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"); 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
+#endif
+
+
diff --git a/source/blender/python/manta_pp/movingobs.h.reg b/source/blender/python/manta_pp/movingobs.h.reg
new file mode 100644
index 00000000000..7c95949a6de
--- /dev/null
+++ b/source/blender/python/manta_pp/movingobs.h.reg
@@ -0,0 +1,7 @@
+#include "movingobs.h"
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","MovingObstacle","PbClass"); template<> const char* Namify<MovingObstacle >::S = "MovingObstacle";
+>MovingObstacle^
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","MovingObstacle",MovingObstacle::_W_0);
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","add",MovingObstacle::_W_1);
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","moveLinear",MovingObstacle::_W_2);
++MovingObstacle^ static const Pb::Register _R_$IDX$ ("MovingObstacle","projectOutside",MovingObstacle::_W_3);
diff --git a/source/blender/python/manta_pp/movingobs.h.reg.cpp b/source/blender/python/manta_pp/movingobs.h.reg.cpp
new file mode 100644
index 00000000000..4e0dbd8ba95
--- /dev/null
+++ b/source/blender/python/manta_pp/movingobs.h.reg.cpp
@@ -0,0 +1,21 @@
+
+
+
+
+
+// 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_0 ("MovingObstacle","MovingObstacle","PbClass"); template<> const char* Namify<MovingObstacle >::S = "MovingObstacle";
+ static const Pb::Register _R_1 ("MovingObstacle","MovingObstacle",MovingObstacle::_W_0);
+ static const Pb::Register _R_2 ("MovingObstacle","add",MovingObstacle::_W_1);
+ static const Pb::Register _R_3 ("MovingObstacle","moveLinear",MovingObstacle::_W_2);
+ static const Pb::Register _R_4 ("MovingObstacle","projectOutside",MovingObstacle::_W_3);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/noisefield.cpp b/source/blender/python/manta_pp/noisefield.cpp
new file mode 100644
index 00000000000..9fad3d4b286
--- /dev/null
+++ b/source/blender/python/manta_pp/noisefield.cpp
@@ -0,0 +1,309 @@
+
+
+
+
+
+// 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
+ *
+ * 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;
+
+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) return;
+ Real *noise3 = new Real[n3d];
+ if(loadFromFile) {
+ FILE* fp = fopen(TILENAME,"rb");
+ if(fp) {
+ fread(noise3, sizeof(Real), n3d, fp);
+ fclose(fp);
+ debMsg("noise tile loaded from file! " , 1);
+ mNoiseTile = noise3;
+ 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;
+ delete[] temp13;
+ delete[] temp23;
+
+ if(loadFromFile) {
+ FILE* fp = fopen(TILENAME,"wb");
+ if(fp) {
+ fwrite(noise3, sizeof(Real), n3d, fp);
+ fclose(fp);
+ debMsg( "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;
+ }
+}
+
+
+
+
+
+}
+
+
diff --git a/source/blender/python/manta_pp/noisefield.h b/source/blender/python/manta_pp/noisefield.h
new file mode 100644
index 00000000000..c0e69d61dea
--- /dev/null
+++ b/source/blender/python/manta_pp/noisefield.h
@@ -0,0 +1,405 @@
+
+
+
+
+
+// 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
+ *
+ * Wavelet noise field
+ *
+ ******************************************************************************/
+
+#ifndef _NOISEFIELD_H_
+#define _NOISEFIELD_H_
+
+#include "vectorbase.h"
+#include "manta.h"
+
+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); pbPreparePlugin(0, "WaveletNoiseField::WaveletNoiseField" ); { 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" ); return 0; } catch(std::exception& e) { pbSetError("WaveletNoiseField::WaveletNoiseField",e.what()); return -1; } }
+ ~WaveletNoiseField() {
+ if(mNoiseTile) { delete mNoiseTile; mNoiseTile=NULL; }
+ };
+
+ //! evaluate noise
+ inline Real evaluate(Vec3 pos, int tile=0);
+ //! evaluate noise as a vector
+ inline Vec3 evaluateVec(Vec3 pos, int tile=0);
+ //! evaluate curl noise
+ inline Vec3 evaluateCurl(Vec3 pos);
+
+ //! 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() { 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; 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) {
+ 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) {
+ 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) {
+ // 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
+
+#endif
+
+
diff --git a/source/blender/python/manta_pp/noisefield.h.reg b/source/blender/python/manta_pp/noisefield.h.reg
new file mode 100644
index 00000000000..74b1bd96478
--- /dev/null
+++ b/source/blender/python/manta_pp/noisefield.h.reg
@@ -0,0 +1,12 @@
+#include "noisefield.h"
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","NoiseField","PbClass"); template<> const char* Namify<WaveletNoiseField >::S = "WaveletNoiseField";
+>WaveletNoiseField^
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","WaveletNoiseField",WaveletNoiseField::_W_0);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","posOffset",WaveletNoiseField::_GET_mPosOffset,WaveletNoiseField::_SET_mPosOffset);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","posScale",WaveletNoiseField::_GET_mPosScale,WaveletNoiseField::_SET_mPosScale);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","valOffset",WaveletNoiseField::_GET_mValOffset,WaveletNoiseField::_SET_mValOffset);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","valScale",WaveletNoiseField::_GET_mValScale,WaveletNoiseField::_SET_mValScale);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","clamp",WaveletNoiseField::_GET_mClamp,WaveletNoiseField::_SET_mClamp);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","clampNeg",WaveletNoiseField::_GET_mClampNeg,WaveletNoiseField::_SET_mClampNeg);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","clampPos",WaveletNoiseField::_GET_mClampPos,WaveletNoiseField::_SET_mClampPos);
++WaveletNoiseField^ static const Pb::Register _R_$IDX$ ("WaveletNoiseField","timeAnim",WaveletNoiseField::_GET_mTimeAnim,WaveletNoiseField::_SET_mTimeAnim);
diff --git a/source/blender/python/manta_pp/noisefield.h.reg.cpp b/source/blender/python/manta_pp/noisefield.h.reg.cpp
new file mode 100644
index 00000000000..967b3b2cdd1
--- /dev/null
+++ b/source/blender/python/manta_pp/noisefield.h.reg.cpp
@@ -0,0 +1,26 @@
+
+
+
+
+
+// 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_0 ("WaveletNoiseField","NoiseField","PbClass"); template<> const char* Namify<WaveletNoiseField >::S = "WaveletNoiseField";
+ static const Pb::Register _R_1 ("WaveletNoiseField","WaveletNoiseField",WaveletNoiseField::_W_0);
+ static const Pb::Register _R_2 ("WaveletNoiseField","posOffset",WaveletNoiseField::_GET_mPosOffset,WaveletNoiseField::_SET_mPosOffset);
+ static const Pb::Register _R_3 ("WaveletNoiseField","posScale",WaveletNoiseField::_GET_mPosScale,WaveletNoiseField::_SET_mPosScale);
+ static const Pb::Register _R_4 ("WaveletNoiseField","valOffset",WaveletNoiseField::_GET_mValOffset,WaveletNoiseField::_SET_mValOffset);
+ static const Pb::Register _R_5 ("WaveletNoiseField","valScale",WaveletNoiseField::_GET_mValScale,WaveletNoiseField::_SET_mValScale);
+ static const Pb::Register _R_6 ("WaveletNoiseField","clamp",WaveletNoiseField::_GET_mClamp,WaveletNoiseField::_SET_mClamp);
+ static const Pb::Register _R_7 ("WaveletNoiseField","clampNeg",WaveletNoiseField::_GET_mClampNeg,WaveletNoiseField::_SET_mClampNeg);
+ static const Pb::Register _R_8 ("WaveletNoiseField","clampPos",WaveletNoiseField::_GET_mClampPos,WaveletNoiseField::_SET_mClampPos);
+ static const Pb::Register _R_9 ("WaveletNoiseField","timeAnim",WaveletNoiseField::_GET_mTimeAnim,WaveletNoiseField::_SET_mTimeAnim);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/particle.cpp b/source/blender/python/manta_pp/particle.cpp
new file mode 100644
index 00000000000..edeb9c105a3
--- /dev/null
+++ b/source/blender/python/manta_pp/particle.cpp
@@ -0,0 +1,519 @@
+
+
+
+
+
+// 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
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * Particle data functionality
+ *
+ ******************************************************************************/
+
+#include <fstream>
+#include <cstring>
+#include <limits>
+#if NO_ZLIB!=1
+#include <zlib.h>
+#endif
+#include "particle.h"
+#include "levelset.h"
+#include "fileio.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(int i=0; i<(int)mPartData.size(); ++i)
+ mPartData[i]->setParticleSys(NULL);
+
+ if(mFreePdata) {
+ for(int i=0; i<(int)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(int i=0; i<(int)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(int i=0; i<(int)mPartData.size(); ++i) {
+ if(mPartData[i] == pdata) {
+ if(i<(int)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) {
+ _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() );
+ 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(int i=0; i<(int)mPartData.size(); ++i) {
+ mPartData[i]->addEntry();
+ }
+}
+
+
+BasicParticleSystem::BasicParticleSystem(FluidSolver* parent)
+ : ParticleSystem<BasicParticleData>(parent) {
+ this->mAllowCompress = false;
+}
+
+// file io
+
+void BasicParticleSystem::writeParticlesText(string name) {
+ 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(int i=0; i<this->size(); ++i) {
+ ofs << i<<": "<< this->getPos(i) <<" , "<< this->getStatus(i) <<". ";
+ for(int pd=0; pd<(int)mPdataInt.size() ; ++pd) ofs << mPdataInt [pd]->get(i)<<" ";
+ for(int pd=0; pd<(int)mPdataReal.size(); ++pd) ofs << mPdataReal[pd]->get(i)<<" ";
+ for(int pd=0; pd<(int)mPdataVec3.size(); ++pd) ofs << mPdataVec3[pd]->get(i)<<" ";
+ ofs << "\n";
+ }
+ ofs.close();
+}
+
+void BasicParticleSystem::writeParticlesRawPositionsGz(string name) {
+# if NO_ZLIB!=1
+ gzFile gzf = gzopen(name.c_str(), "wb1");
+ if (!gzf) errMsg("can't open file "<<name);
+ for(int 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(string name) {
+# 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(int 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(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<BasicParticleData>(name, this );
+ else
+ errMsg("particle '" + name +"' filetype not supported for loading");
+}
+
+void BasicParticleSystem::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 == ".txt")
+ this->writeParticlesText(name);
+ else if (ext == ".uni")
+ writeParticlesUni<BasicParticleData>(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(int start, int stop, bool printIndex)
+{
+ std::ostringstream sstr;
+ int s = (start>0 ? start : 0 );
+ int e = (stop>0 ? stop : (int)mData.size() );
+ s = Manta::clamp(s, 0, (int)mData.size());
+ e = Manta::clamp(e, 0, (int)mData.size());
+
+ for(int i=s; i<e; ++i) {
+ if(printIndex) sstr << i<<": ";
+ sstr<<mData[i].pos<<" "<<mData[i].flag<<"\n";
+ }
+ debMsg( sstr.str() , 1 );
+}
+
+// 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;
+}
+
+template<class T>
+ParticleDataImpl<T>::~ParticleDataImpl() {
+}
+
+template<class T>
+int 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(int s) {
+ mData.resize(s);
+}
+template<class T>
+void ParticleDataImpl<T>::copyValueSlow(int from, int 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(int idx, Vec3 pos) {
+ if(!mpGridSource)
+ mData[idx] = 0;
+ else {
+ mData[idx] = mpGridSource->getInterpolated(pos);
+ }
+}
+// special handling needed for velocities
+template<>
+void ParticleDataImpl<Vec3>::initNewValue(int 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
+ 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
+ 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> struct knSetPdataConst : public KernelBase { knSetPdataConst(ParticleDataImpl<T>& pdata, T value) : KernelBase(pdata.size()) ,pdata(pdata),value(value) { run(); } inline void op(int idx, ParticleDataImpl<T>& pdata, T value ) { pdata[idx] = value; } inline ParticleDataImpl<T>& getArg0() { return pdata; } typedef ParticleDataImpl<T> type0;inline T& getArg1() { return value; } typedef T type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, pdata,value); } ParticleDataImpl<T>& pdata; T value; };
+
+template <class T, class S> struct knPdataSet : public KernelBase { knPdataSet(ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) { run(); } inline void op(int idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } ParticleDataImpl<T>& me; const ParticleDataImpl<S>& other; };
+template <class T, class S> struct knPdataAdd : public KernelBase { knPdataAdd(ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other) : KernelBase(me.size()) ,me(me),other(other) { run(); } inline void op(int idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } 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) { run(); } inline void op(int idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } 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) { run(); } inline void op(int idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } 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) { run(); } inline void op(int idx, ParticleDataImpl<T>& me, const ParticleDataImpl<S>& other ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } ParticleDataImpl<T>& me; const ParticleDataImpl<S>& other; };
+
+template <class T, class S> struct knPdataSetScalar : public KernelBase { knPdataSetScalar(ParticleDataImpl<T>& me, const S& other) : KernelBase(me.size()) ,me(me),other(other) { run(); } inline void op(int idx, ParticleDataImpl<T>& me, const S& other ) { me[idx] = other; } inline ParticleDataImpl<T>& getArg0() { return me; } typedef ParticleDataImpl<T> type0;inline const S& getArg1() { return other; } typedef S type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } 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) { run(); } inline void op(int idx, ParticleDataImpl<T>& me, const S& other ) { me[idx] += other; } inline ParticleDataImpl<T>& getArg0() { return me; } typedef ParticleDataImpl<T> type0;inline const S& getArg1() { return other; } typedef S type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } 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) { run(); } inline void op(int idx, ParticleDataImpl<T>& me, const S& other ) { me[idx] *= other; } inline ParticleDataImpl<T>& getArg0() { return me; } typedef ParticleDataImpl<T> type0;inline const S& getArg1() { return other; } typedef S type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } 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) { run(); } inline void op(int idx, ParticleDataImpl<T>& me, const ParticleDataImpl<T>& other, const S& factor ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other,factor); } ParticleDataImpl<T>& me; const ParticleDataImpl<T>& other; const S& factor; };
+
+template <class T> struct knPdataSafeDiv : public KernelBase { knPdataSafeDiv(ParticleDataImpl<T>& me, const ParticleDataImpl<T>& other) : KernelBase(me.size()) ,me(me),other(other) { run(); } inline void op(int idx, ParticleDataImpl<T>& me, const ParticleDataImpl<T>& other ) { 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other); } ParticleDataImpl<T>& me; const ParticleDataImpl<T>& other; };
+template <class T> struct knPdataSetConst : public KernelBase { knPdataSetConst(ParticleDataImpl<T>& pdata, T value) : KernelBase(pdata.size()) ,pdata(pdata),value(value) { run(); } inline void op(int idx, ParticleDataImpl<T>& pdata, T value ) { pdata[idx] = value; } inline ParticleDataImpl<T>& getArg0() { return pdata; } typedef ParticleDataImpl<T> type0;inline T& getArg1() { return value; } typedef T type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, pdata,value); } ParticleDataImpl<T>& pdata; T value; };
+
+template <class T> struct knPdataClamp : public KernelBase { knPdataClamp(ParticleDataImpl<T>& me, T min, T max) : KernelBase(me.size()) ,me(me),min(min),max(max) { run(); } inline void op(int idx, ParticleDataImpl<T>& me, T min, T max ) { me[idx] = clamp( me[idx], min, max); } inline ParticleDataImpl<T>& getArg0() { return me; } typedef ParticleDataImpl<T> type0;inline T& getArg1() { return min; } typedef T type1;inline T& getArg2() { return max; } typedef T type2; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,min,max); } ParticleDataImpl<T>& me; T min; T max; };
+
+// 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() );
+ memcpy( &mData[0], &a.mData[0], sizeof(T) * mData.size() );
+ return *this;
+}
+
+template<typename T>
+void ParticleDataImpl<T>::setConst(T s) {
+ knPdataSetScalar<T,T> op( *this, s );
+}
+
+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(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>::multConst(T s) {
+ knPdataMultScalar<T,T> op( *this, s );
+}
+
+template<typename T>
+void ParticleDataImpl<T>::clamp(Real min, Real max) {
+ knPdataClamp<T> op( *this, min,max );
+}
+
+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()) { run(); } inline void op(int 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, val,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()) { run(); } inline void op(int 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, val,maxVal); } const ParticleDataImpl<T>& val; Real maxVal; };
+
+template<typename T>
+Real ParticleDataImpl<T>::getMinValue() {
+ return sqrt(CompPdata_Min<T> (*this));
+}
+
+template<typename T>
+Real ParticleDataImpl<T>::getMaxAbsValue() {
+ Real amin = CompPdata_Min<T> (*this);
+ Real amax = CompPdata_Max<T> (*this);
+ return max( fabs(amin), fabs(amax));
+}
+
+template<typename T>
+Real ParticleDataImpl<T>::getMaxValue() {
+ return sqrt(CompPdata_Max<T> (*this));
+}
+
+template<typename T>
+void ParticleDataImpl<T>::printPdata(int start, int stop, bool printIndex)
+{
+ std::ostringstream sstr;
+ int s = (start>0 ? start : 0 );
+ int e = (stop>0 ? stop : (int)mData.size() );
+ s = Manta::clamp(s, 0, (int)mData.size());
+ e = Manta::clamp(e, 0, (int)mData.size());
+
+ for(int i=s; i<e; ++i) {
+ if(printIndex) sstr << i<<": ";
+ sstr<<mData[i]<<" "<<"\n";
+ }
+ debMsg( sstr.str() , 1 );
+}
+
+// specials for vec3
+
+
+
+ struct CompPdata_MinVec3 : public KernelBase { CompPdata_MinVec3(const ParticleDataImpl<Vec3>& val) : KernelBase(val.size()) ,val(val) ,minVal(-std::numeric_limits<Real>::max()) { run(); } inline void op(int 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, val,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>::min()) { run(); } inline void op(int 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, val,maxVal); } const ParticleDataImpl<Vec3>& val; Real maxVal; };
+
+template<>
+Real ParticleDataImpl<Vec3>::getMinValue() {
+ return sqrt(CompPdata_MinVec3 (*this));
+}
+
+template<>
+Real ParticleDataImpl<Vec3>::getMaxAbsValue() {
+ Real amin = CompPdata_MinVec3 (*this);
+ Real amax = CompPdata_MaxVec3 (*this);
+ return max( fabs(amin), fabs(amax));
+}
+
+template<>
+Real ParticleDataImpl<Vec3>::getMaxValue() {
+ return sqrt(CompPdata_MaxVec3 (*this));
+}
+
+
+// explicit instantiation
+template class ParticleDataImpl<int>;
+template class ParticleDataImpl<Real>;
+template class ParticleDataImpl<Vec3>;
+
+
+} // namespace
+
+
+
diff --git a/source/blender/python/manta_pp/particle.h b/source/blender/python/manta_pp/particle.h
new file mode 100644
index 00000000000..8d2341da47a
--- /dev/null
+++ b/source/blender/python/manta_pp/particle.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
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * 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<<1), // particles newly created in this step
+ 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); pbPreparePlugin(0, "ParticleBase::ParticleBase" ); { 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" ); 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 int 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);
+
+ // 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)); pbPreparePlugin(pbo->getParent(), "ParticleBase::create"); 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"); 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?
+ int getNumPdata() const { return mPartData.size(); }
+ //! access one of the fields
+ ParticleDataBase* getPdata(int i) { return mPartData[i]; }
+
+protected:
+ //! new particle candidates
+ std::vector<Vec3> mNewBuffer;
+
+ //! 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); pbPreparePlugin(0, "ParticleSystem::ParticleSystem" ); { 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" ); 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[](int idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline const S& operator[](int idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ // return size of container
+ inline int size() const { return 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)); pbPreparePlugin(pbo->getParent(), "ParticleSystem::size"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->size()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"ParticleSystem::size"); return _retval; } catch(std::exception& e) { pbSetError("ParticleSystem::size",e.what()); return 0; } }
+ // slow virtual function of base class, also returns size
+ virtual int getSizeSlow() const { return size(); }
+
+ // query status
+ inline int getStatus(int idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx].flag; }
+ inline bool isActive(int idx) { DEBUG_ONLY(checkPartIndex(idx)); return (mData[idx].flag & PDELETE) == 0; }
+
+ //! safe accessor for python
+ void setPos(int 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)); pbPreparePlugin(pbo->getParent(), "ParticleSystem::setPos"); PyObject *_retval = 0; { ArgLocker _lock; int idx = _args.get<int >("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"); return _retval; } catch(std::exception& e) { pbSetError("ParticleSystem::setPos",e.what()); return 0; } }
+ Vec3 getPos(int idx) { 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)); pbPreparePlugin(pbo->getParent(), "ParticleSystem::getPos"); PyObject *_retval = 0; { ArgLocker _lock; int idx = _args.get<int >("idx",0,&_lock); pbo->_args.copy(_args); _retval = toPy(pbo->getPos(idx)); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"ParticleSystem::getPos"); 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); static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleSystem::getPosPdata"); 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"); return _retval; } catch(std::exception& e) { pbSetError("ParticleSystem::getPosPdata",e.what()); return 0; } }
+ void setPosPdata(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)); pbPreparePlugin(pbo->getParent(), "ParticleSystem::setPosPdata"); PyObject *_retval = 0; { ArgLocker _lock; 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"); 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(int newsize);
+
+ // adding and deleting
+ inline void kill(int idx);
+ int 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)); pbPreparePlugin(pbo->getParent(), "ParticleSystem::clear"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"ParticleSystem::clear"); return _retval; } catch(std::exception& e) { pbSetError("ParticleSystem::clear",e.what()); return 0; } }
+
+ //! Advect particle in grid velocity field
+ void advectInGrid(FlagGrid& flags, MACGrid& vel, int integrationMode, bool deleteInObstacle=true ); static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleSystem* pbo = dynamic_cast<ParticleSystem*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleSystem::advectInGrid"); 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); bool deleteInObstacle = _args.getOpt<bool >("deleteInObstacle",3,true ,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->advectInGrid(flags,vel,integrationMode,deleteInObstacle); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"ParticleSystem::advectInGrid"); 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)); pbPreparePlugin(pbo->getParent(), "ParticleSystem::projectOutside"); 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"); return _retval; } catch(std::exception& e) { pbSetError("ParticleSystem::projectOutside",e.what()); return 0; } }
+
+ virtual ParticleBase* clone();
+ virtual std::string infoString() const;
+
+ //! debugging
+ inline void checkPartIndex(int idx) const;
+
+protected:
+ //! deletion count , and interval for re-compressing
+ int 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
+struct BasicParticleData {
+public:
+ BasicParticleData() : pos(0.), flag(0) {}
+ BasicParticleData(const Vec3& p) : pos(p), flag(0) {}
+ static ParticleBase::SystemType getType() { return ParticleBase::PARTICLE; }
+
+ //! data
+ Vec3 pos;
+ int flag;
+};
+
+class BasicParticleSystem : public ParticleSystem<BasicParticleData> {public:
+ BasicParticleSystem(FluidSolver* parent); static int _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "BasicParticleSystem::BasicParticleSystem" ); { 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" ); return 0; } catch(std::exception& e) { pbSetError("BasicParticleSystem::BasicParticleSystem",e.what()); return -1; } }
+
+ //! file io
+ void save(std::string name); static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::save"); 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(),"BasicParticleSystem::save"); return _retval; } catch(std::exception& e) { pbSetError("BasicParticleSystem::save",e.what()); return 0; } }
+ void load(std::string name); static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::load"); 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(),"BasicParticleSystem::load"); return _retval; } catch(std::exception& e) { pbSetError("BasicParticleSystem::load",e.what()); return 0; } }
+
+ // save to text file
+ void writeParticlesText(std::string name);
+ // other output formats
+ void writeParticlesRawPositionsGz(std::string name);
+ void writeParticlesRawVelocityGz(std::string name);
+
+ // add particles in python
+ void addParticle(Vec3 pos) { add(BasicParticleData(pos)); } static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::addParticle"); 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"); 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(int start=-1, int stop=-1, bool printIndex=false); static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); BasicParticleSystem* pbo = dynamic_cast<BasicParticleSystem*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "BasicParticleSystem::printParts"); PyObject *_retval = 0; { ArgLocker _lock; int start = _args.getOpt<int >("start",0,-1,&_lock); int stop = _args.getOpt<int >("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"); return _retval; } catch(std::exception& e) { pbSetError("BasicParticleSystem::printParts",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; }
+
+ int 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_16 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "ParticleIndexSystem::ParticleIndexSystem" ); { 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" ); return 0; } catch(std::exception& e) { pbSetError("ParticleIndexSystem::ParticleIndexSystem",e.what()); return -1; } };
+ //! we only need a resize function...
+ void resize(int 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_17 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "ConnectedParticleSystem::ConnectedParticleSystem" ); { 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" ); 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_18 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "ParticleDataBase::ParticleDataBase" ); { 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" ); 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 int 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(int size) { assertMsg( false , "Dont use, override..."); return; }
+ virtual void copyValueSlow(int from, int to) { assertMsg( false , "Dont use, override..."); return; }
+
+ //! set base pointer
+ void setParticleSys(ParticleBase* set) { mpParticleSys = set; }
+
+ //! debugging
+ inline void checkPartIndex(int 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_19 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { PbClass* obj = Pb::objFromPy(_self); if (obj) delete obj; try { PbArgs _args(_linargs, _kwds); pbPreparePlugin(0, "ParticleDataImpl::ParticleDataImpl" ); { 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" ); 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(int idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline const T get(int idx) const { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline T& operator[](int idx) { DEBUG_ONLY(checkPartIndex(idx)); return mData[idx]; }
+ inline const T operator[](int 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_20 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clear"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->clear(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::clear"); 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_21 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setSource"); 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"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::setSource",e.what()); return 0; } }
+
+ // particle data base interface
+ virtual int getSizeSlow() const;
+ virtual void addEntry();
+ virtual ParticleDataBase* clone();
+ virtual PdataType getType() const;
+ virtual void resize(int s);
+ virtual void copyValueSlow(int from, int to);
+
+ int size() const { return mData.size(); }
+
+ // fast inlined functions for per particle operations
+ inline void copyValue(int from, int to) { get(to) = get(from); }
+ void initNewValue(int idx, Vec3 pos);
+
+ // python interface (similar to grid data)
+ void setConst(T s); static PyObject* _W_22 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::setConst"); 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(),"ParticleDataImpl::setConst"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::setConst",e.what()); return 0; } }
+ ParticleDataImpl<T>& copyFrom(const ParticleDataImpl<T>& a); static PyObject* _W_23 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::copyFrom"); 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"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::copyFrom",e.what()); return 0; } }
+ void add(const ParticleDataImpl<T>& a); static PyObject* _W_24 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::add"); 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"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::add",e.what()); return 0; } }
+ void sub(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)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::sub"); 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"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::sub",e.what()); return 0; } }
+ void addConst(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)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::addConst"); 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(),"ParticleDataImpl::addConst"); 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_27 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::addScaled"); 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"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::addScaled",e.what()); return 0; } }
+ void mult( 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)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::mult"); 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"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::mult",e.what()); return 0; } }
+ void multConst(T s); static PyObject* _W_29 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::multConst"); 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(),"ParticleDataImpl::multConst"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::multConst",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); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::clamp"); 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(),"ParticleDataImpl::clamp"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::clamp",e.what()); return 0; } }
+ Real getMaxAbsValue(); static PyObject* _W_31 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getMaxAbsValue"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMaxAbsValue()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::getMaxAbsValue"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::getMaxAbsValue",e.what()); return 0; } }
+ Real getMaxValue(); static PyObject* _W_32 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getMaxValue"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMaxValue()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::getMaxValue"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::getMaxValue",e.what()); return 0; } }
+ Real getMinValue(); static PyObject* _W_33 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::getMinValue"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getMinValue()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"ParticleDataImpl::getMinValue"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::getMinValue",e.what()); return 0; } }
+
+ void printPdata(int start=-1, int stop=-1, bool printIndex=false); static PyObject* _W_34 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::printPdata"); PyObject *_retval = 0; { ArgLocker _lock; int start = _args.getOpt<int >("start",0,-1,&_lock); int stop = _args.getOpt<int >("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"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::printPdata",e.what()); return 0; } }
+
+ //! file io
+ void save(std::string name); static PyObject* _W_35 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::save"); 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(),"ParticleDataImpl::save"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::save",e.what()); return 0; } }
+ void load(std::string name); static PyObject* _W_36 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); ParticleDataImpl* pbo = dynamic_cast<ParticleDataImpl*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "ParticleDataImpl::load"); 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(),"ParticleDataImpl::load"); return _retval; } catch(std::exception& e) { pbSetError("ParticleDataImpl::load",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) {
+ mNewBuffer.push_back(pos);
+}
+
+template<class S>
+void ParticleSystem<S>::clear() {
+ mDeleteChunk = mDeletes = 0;
+ this->resizeAll(0); // instead of mData.clear
+}
+
+template<class S>
+int 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(int 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) {
+ for(int i=0; i<(int)this->size(); ++i) {
+ target[i] = this->getPos(i);
+ }
+}
+template<class S>
+void ParticleSystem<S>::setPosPdata(ParticleDataImpl<Vec3>& target) {
+ for(int i=0; i<(int)this->size(); ++i) {
+ this->getPos(i) = target[i];
+ }
+}
+
+template<class S>
+void ParticleSystem<S>::transformPositions( Vec3i dimOld, Vec3i dimNew )
+{
+ Vec3 factor = calcGridSizeFactor( dimNew, dimOld );
+ for(int i=0; i<(int)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(std::vector<S>& p, const MACGrid& vel, const FlagGrid& flags, Real dt, bool deleteInObstacle ) : KernelBase(p.size()) ,p(p),vel(vel),flags(flags),dt(dt),deleteInObstacle(deleteInObstacle) ,u((size)) { run(); } inline void op(int idx, std::vector<S>& p, const MACGrid& vel, const FlagGrid& flags, Real dt, bool deleteInObstacle ,std::vector<Vec3> & u) {
+ if (p[idx].flag & ParticleBase::PDELETE) {
+ u[idx] =_0;
+ } else if (!flags.isInBounds(p[idx].pos,1) || flags.isObstacle(p[idx].pos)) {
+ 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;
+ } else {
+ u[idx] = vel.getInterpolated(p[idx].pos) * dt;
+ }
+} 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 Real& getArg3() { return dt; } typedef Real type3;inline bool& getArg4() { return deleteInObstacle; } typedef bool type4; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, p,vel,flags,dt,deleteInObstacle,u); } std::vector<S>& p; const MACGrid& vel; const FlagGrid& flags; Real dt; bool deleteInObstacle; 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) { run(); } inline void op(int idx, std::vector<S>& p, const FlagGrid& flags ) {
+ 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, p,flags); } 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) : KernelBase(p.size()) ,p(p),flags(flags),posOld(posOld) { run(); } inline void op(int idx, std::vector<S>& p, const FlagGrid& flags, ParticleDataImpl<Vec3> *posOld = NULL ) {
+ if (p[idx].flag & ParticleBase::PDELETE) return;
+ if (!flags.isInBounds(p[idx].pos,0) ) {
+ p[idx].pos = clamp( p[idx].pos, Vec3(0.), toVec3(flags.getSize())-Vec3(1.) );
+ }
+ if (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; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, p,flags,posOld); } std::vector<S>& p; const FlagGrid& flags; ParticleDataImpl<Vec3> * posOld; };
+
+// advection plugin
+template<class S>
+void ParticleSystem<S>::advectInGrid(FlagGrid& flags, MACGrid& vel, int integrationMode, bool deleteInObstacle ) {
+ // position clamp requires old positions, backup
+ ParticleDataImpl<Vec3> *posOld = NULL;
+ if(!deleteInObstacle) {
+ posOld = new ParticleDataImpl<Vec3>(this->getParent());
+ posOld->resize(mData.size());
+ for(int i=0; i<mData.size();++i) (*posOld)[i] = mData[i].pos;
+ }
+
+ // update positions
+ GridAdvectKernel<S> kernel(mData, vel, flags, getParent()->getDt(), deleteInObstacle );
+ integratePointSet(kernel, integrationMode);
+
+ if(!deleteInObstacle) {
+ KnClampPositions<S> ( mData, flags, posOld );
+ 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) { run(); } inline void op(int 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 run() { const int _sz = size; for (int 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>
+void ParticleSystem<S>::resizeAll(int size) {
+ // resize all buffers to target size in 1 go
+ mData.resize(size);
+ for(int i=0; i<(int)mPartData.size(); ++i)
+ mPartData[i]->resize(size);
+}
+
+template<class S>
+void ParticleSystem<S>::compress() {
+ int nextRead = mData.size();
+ for (int i=0; i<(int)mData.size(); i++) {
+ while ((mData[i].flag & PDELETE) != 0) {
+ nextRead--;
+ mData[i] = mData[nextRead];
+ // ugly, but prevent virtual function calls here:
+ for(int pd=0; pd<(int)mPdataReal.size(); ++pd) mPdataReal[pd]->copyValue(nextRead, i);
+ for(int pd=0; pd<(int)mPdataVec3.size(); ++pd) mPdataVec3[pd]->copyValue(nextRead, i);
+ for(int pd=0; pd<(int)mPdataInt .size(); ++pd) mPdataInt [pd]->copyValue(nextRead, i);
+ mData[nextRead].flag = PINVALID;
+ }
+ }
+ if(nextRead<(int)mData.size()) debMsg("Deleted "<<((int)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(mNewBuffer.size()==0) return;
+ int newCnt = mData.size();
+ resizeAll(newCnt + mNewBuffer.size());
+
+ // clear new flag everywhere
+ for(int i=0; i<(int)mData.size(); ++i) mData[i].flag &= ~PNEW;
+
+ for(int i=0; i<(int)mNewBuffer.size(); ++i) {
+ // note, other fields are not initialized here...
+ mData[newCnt].pos = mNewBuffer[i];
+ mData[newCnt].flag = PNEW;
+ // now init pdata fields from associated grids...
+ for(int pd=0; pd<(int)mPdataReal.size(); ++pd)
+ mPdataReal[pd]->initNewValue(newCnt, mNewBuffer[i] );
+ for(int pd=0; pd<(int)mPdataVec3.size(); ++pd)
+ mPdataVec3[pd]->initNewValue(newCnt, mNewBuffer[i] );
+ for(int pd=0; pd<(int)mPdataInt.size(); ++pd)
+ mPdataInt[pd]->initNewValue(newCnt, mNewBuffer[i] );
+ newCnt++;
+ }
+ if(mNewBuffer.size()>0) debMsg("Added & initialized "<<(int)mNewBuffer.size()<<" particles", 1); // debug info
+ mNewBuffer.clear();
+}
+
+
+template<class DATA, class CON>
+void ConnectedParticleSystem<DATA,CON>::compress() {
+ const int sz = ParticleSystem<DATA>::size();
+ int *renumber_back = new int[sz];
+ int *renumber = new int[sz];
+ for (int i=0; i<sz; i++)
+ renumber[i] = renumber_back[i] = -1;
+
+ // reorder elements
+ std::vector<DATA>& data = ParticleSystem<DATA>::mData;
+ int nextRead = sz;
+ for (int 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 (int i=0; i<nextRead; i++)
+ renumber[renumber_back[i]] = i;
+
+ // rename indices in filaments
+ for (int i=0; i<(int)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() << "' [" << size() << " parts";
+ if(this->getNumPdata()>0) s<< " "<< this->getNumPdata()<<" pd";
+ s << "]";
+ //for(int i=0; i<(int)mPartData.size(); ++i) { sstr << i<<":" << mPartData[i]->size() <<" "; }
+ return s.str();
+}
+
+template<class S>
+inline void ParticleSystem<S>::checkPartIndex(int idx) const {
+ int mySize = this->size();
+ if (idx<0 || idx > mySize ) {
+ errMsg( "ParticleBase " << " size " << mySize << " : index " << idx << " out of bound " );
+ }
+}
+
+inline void ParticleDataBase::checkPartIndex(int idx) const {
+ int 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(int i=0; i<(int)mData.size(); ++i) mData[i] = 0.;
+}
+
+
+} // namespace
+
+#endif
+
+
+
diff --git a/source/blender/python/manta_pp/particle.h.reg b/source/blender/python/manta_pp/particle.h.reg
new file mode 100644
index 00000000000..1468d7d3e89
--- /dev/null
+++ b/source/blender/python/manta_pp/particle.h.reg
@@ -0,0 +1,58 @@
+#include "particle.h"
++ParticleBase^ static const Pb::Register _R_$IDX$ ("ParticleBase","ParticleBase","PbClass"); template<> const char* Namify<ParticleBase >::S = "ParticleBase";
+>ParticleBase^
++ParticleBase^ static const Pb::Register _R_$IDX$ ("ParticleBase","ParticleBase",ParticleBase::_W_0);
++ParticleBase^ static const Pb::Register _R_$IDX$ ("ParticleBase","create",ParticleBase::_W_1);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","ParticleSystem<$CT$>","ParticleBase"); template<> const char* Namify<ParticleSystem<$CT$> >::S = "ParticleSystem<$CT$>";
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","ParticleSystem",ParticleSystem<$CT$>::_W_2);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","size",ParticleSystem<$CT$>::_W_3);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","setPos",ParticleSystem<$CT$>::_W_4);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","getPos",ParticleSystem<$CT$>::_W_5);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","getPosPdata",ParticleSystem<$CT$>::_W_6);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","setPosPdata",ParticleSystem<$CT$>::_W_7);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","clear",ParticleSystem<$CT$>::_W_8);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","advectInGrid",ParticleSystem<$CT$>::_W_9);
++ParticleSystem^ static const Pb::Register _R_$IDX$ ("ParticleSystem<$CT$>","projectOutside",ParticleSystem<$CT$>::_W_10);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","BasicParticleSystem","ParticleSystem<$BT$>"); template<> const char* Namify<BasicParticleSystem >::S = "BasicParticleSystem";
+>BasicParticleSystem^
+@BasicParticleSystem^^ParticleSystem^BasicParticleData
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","BasicParticleSystem",BasicParticleSystem::_W_11);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","save",BasicParticleSystem::_W_12);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","load",BasicParticleSystem::_W_13);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","addParticle",BasicParticleSystem::_W_14);
++BasicParticleSystem^ static const Pb::Register _R_$IDX$ ("BasicParticleSystem","printParts",BasicParticleSystem::_W_15);
++ParticleIndexSystem^ static const Pb::Register _R_$IDX$ ("ParticleIndexSystem","ParticleIndexSystem","ParticleSystem<$BT$>"); template<> const char* Namify<ParticleIndexSystem >::S = "ParticleIndexSystem";
+>ParticleIndexSystem^
+@ParticleIndexSystem^^ParticleSystem^ParticleIndexData
++ParticleIndexSystem^ static const Pb::Register _R_$IDX$ ("ParticleIndexSystem","ParticleIndexSystem",ParticleIndexSystem::_W_16);
++ConnectedParticleSystem^ static const Pb::Register _R_$IDX$ ("ConnectedParticleSystem<$CT$>","ConnectedParticleSystem<$CT$>","ParticleSystem<$BT$>"); template<> const char* Namify<ConnectedParticleSystem<$CT$> >::S = "ConnectedParticleSystem<$CT$>";
+@ConnectedParticleSystem^DATA,CON^ParticleSystem^DATA
++ConnectedParticleSystem^ static const Pb::Register _R_$IDX$ ("ConnectedParticleSystem<$CT$>","ConnectedParticleSystem",ConnectedParticleSystem<$CT$>::_W_17);
++ParticleDataBase^ static const Pb::Register _R_$IDX$ ("ParticleDataBase","ParticleDataBase","PbClass"); template<> const char* Namify<ParticleDataBase >::S = "ParticleDataBase";
+>ParticleDataBase^
++ParticleDataBase^ static const Pb::Register _R_$IDX$ ("ParticleDataBase","ParticleDataBase",ParticleDataBase::_W_18);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","ParticleDataImpl<$CT$>","ParticleDataBase"); template<> const char* Namify<ParticleDataImpl<$CT$> >::S = "ParticleDataImpl<$CT$>";
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","ParticleDataImpl",ParticleDataImpl<$CT$>::_W_19);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","clear",ParticleDataImpl<$CT$>::_W_20);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","setSource",ParticleDataImpl<$CT$>::_W_21);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","setConst",ParticleDataImpl<$CT$>::_W_22);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","copyFrom",ParticleDataImpl<$CT$>::_W_23);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","add",ParticleDataImpl<$CT$>::_W_24);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","sub",ParticleDataImpl<$CT$>::_W_25);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","addConst",ParticleDataImpl<$CT$>::_W_26);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","addScaled",ParticleDataImpl<$CT$>::_W_27);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","mult",ParticleDataImpl<$CT$>::_W_28);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","multConst",ParticleDataImpl<$CT$>::_W_29);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","clamp",ParticleDataImpl<$CT$>::_W_30);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","getMaxAbsValue",ParticleDataImpl<$CT$>::_W_31);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","getMaxValue",ParticleDataImpl<$CT$>::_W_32);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","getMinValue",ParticleDataImpl<$CT$>::_W_33);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","printPdata",ParticleDataImpl<$CT$>::_W_34);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","save",ParticleDataImpl<$CT$>::_W_35);
++ParticleDataImpl^ static const Pb::Register _R_$IDX$ ("ParticleDataImpl<$CT$>","load",ParticleDataImpl<$CT$>::_W_36);
+>ParticleDataImpl^int
+&static const Pb::Register _R_$IDX$ ("ParticleDataImpl<int>","PdataInt","");
+>ParticleDataImpl^Real
+&static const Pb::Register _R_$IDX$ ("ParticleDataImpl<Real>","PdataReal","");
+>ParticleDataImpl^Vec3
+&static const Pb::Register _R_$IDX$ ("ParticleDataImpl<Vec3>","PdataVec3","");
diff --git a/source/blender/python/manta_pp/particle.h.reg.cpp b/source/blender/python/manta_pp/particle.h.reg.cpp
new file mode 100644
index 00000000000..5d8d832f33b
--- /dev/null
+++ b/source/blender/python/manta_pp/particle.h.reg.cpp
@@ -0,0 +1,119 @@
+
+
+
+
+
+// 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_3 ("BasicParticleSystem","BasicParticleSystem","ParticleSystem<BasicParticleData>"); template<> const char* Namify<BasicParticleSystem >::S = "BasicParticleSystem";
+ static const Pb::Register _R_4 ("BasicParticleSystem","BasicParticleSystem",BasicParticleSystem::_W_11);
+ static const Pb::Register _R_5 ("BasicParticleSystem","save",BasicParticleSystem::_W_12);
+ static const Pb::Register _R_6 ("BasicParticleSystem","load",BasicParticleSystem::_W_13);
+ static const Pb::Register _R_7 ("BasicParticleSystem","addParticle",BasicParticleSystem::_W_14);
+ static const Pb::Register _R_8 ("BasicParticleSystem","printParts",BasicParticleSystem::_W_15);
+#endif
+#ifdef _C_ParticleBase
+ static const Pb::Register _R_9 ("ParticleBase","ParticleBase","PbClass"); template<> const char* Namify<ParticleBase >::S = "ParticleBase";
+ static const Pb::Register _R_10 ("ParticleBase","ParticleBase",ParticleBase::_W_0);
+ static const Pb::Register _R_11 ("ParticleBase","create",ParticleBase::_W_1);
+#endif
+#ifdef _C_ParticleDataBase
+ static const Pb::Register _R_12 ("ParticleDataBase","ParticleDataBase","PbClass"); template<> const char* Namify<ParticleDataBase >::S = "ParticleDataBase";
+ static const Pb::Register _R_13 ("ParticleDataBase","ParticleDataBase",ParticleDataBase::_W_18);
+#endif
+#ifdef _C_ParticleDataImpl
+ static const Pb::Register _R_14 ("ParticleDataImpl<int>","ParticleDataImpl<int>","ParticleDataBase"); template<> const char* Namify<ParticleDataImpl<int> >::S = "ParticleDataImpl<int>";
+ static const Pb::Register _R_15 ("ParticleDataImpl<int>","ParticleDataImpl",ParticleDataImpl<int>::_W_19);
+ static const Pb::Register _R_16 ("ParticleDataImpl<int>","clear",ParticleDataImpl<int>::_W_20);
+ static const Pb::Register _R_17 ("ParticleDataImpl<int>","setSource",ParticleDataImpl<int>::_W_21);
+ static const Pb::Register _R_18 ("ParticleDataImpl<int>","setConst",ParticleDataImpl<int>::_W_22);
+ static const Pb::Register _R_19 ("ParticleDataImpl<int>","copyFrom",ParticleDataImpl<int>::_W_23);
+ static const Pb::Register _R_20 ("ParticleDataImpl<int>","add",ParticleDataImpl<int>::_W_24);
+ static const Pb::Register _R_21 ("ParticleDataImpl<int>","sub",ParticleDataImpl<int>::_W_25);
+ static const Pb::Register _R_22 ("ParticleDataImpl<int>","addConst",ParticleDataImpl<int>::_W_26);
+ static const Pb::Register _R_23 ("ParticleDataImpl<int>","addScaled",ParticleDataImpl<int>::_W_27);
+ static const Pb::Register _R_24 ("ParticleDataImpl<int>","mult",ParticleDataImpl<int>::_W_28);
+ static const Pb::Register _R_25 ("ParticleDataImpl<int>","multConst",ParticleDataImpl<int>::_W_29);
+ static const Pb::Register _R_26 ("ParticleDataImpl<int>","clamp",ParticleDataImpl<int>::_W_30);
+ static const Pb::Register _R_27 ("ParticleDataImpl<int>","getMaxAbsValue",ParticleDataImpl<int>::_W_31);
+ static const Pb::Register _R_28 ("ParticleDataImpl<int>","getMaxValue",ParticleDataImpl<int>::_W_32);
+ static const Pb::Register _R_29 ("ParticleDataImpl<int>","getMinValue",ParticleDataImpl<int>::_W_33);
+ static const Pb::Register _R_30 ("ParticleDataImpl<int>","printPdata",ParticleDataImpl<int>::_W_34);
+ static const Pb::Register _R_31 ("ParticleDataImpl<int>","save",ParticleDataImpl<int>::_W_35);
+ static const Pb::Register _R_32 ("ParticleDataImpl<int>","load",ParticleDataImpl<int>::_W_36);
+ static const Pb::Register _R_33 ("ParticleDataImpl<Real>","ParticleDataImpl<Real>","ParticleDataBase"); template<> const char* Namify<ParticleDataImpl<Real> >::S = "ParticleDataImpl<Real>";
+ static const Pb::Register _R_34 ("ParticleDataImpl<Real>","ParticleDataImpl",ParticleDataImpl<Real>::_W_19);
+ static const Pb::Register _R_35 ("ParticleDataImpl<Real>","clear",ParticleDataImpl<Real>::_W_20);
+ static const Pb::Register _R_36 ("ParticleDataImpl<Real>","setSource",ParticleDataImpl<Real>::_W_21);
+ static const Pb::Register _R_37 ("ParticleDataImpl<Real>","setConst",ParticleDataImpl<Real>::_W_22);
+ static const Pb::Register _R_38 ("ParticleDataImpl<Real>","copyFrom",ParticleDataImpl<Real>::_W_23);
+ static const Pb::Register _R_39 ("ParticleDataImpl<Real>","add",ParticleDataImpl<Real>::_W_24);
+ static const Pb::Register _R_40 ("ParticleDataImpl<Real>","sub",ParticleDataImpl<Real>::_W_25);
+ static const Pb::Register _R_41 ("ParticleDataImpl<Real>","addConst",ParticleDataImpl<Real>::_W_26);
+ static const Pb::Register _R_42 ("ParticleDataImpl<Real>","addScaled",ParticleDataImpl<Real>::_W_27);
+ static const Pb::Register _R_43 ("ParticleDataImpl<Real>","mult",ParticleDataImpl<Real>::_W_28);
+ static const Pb::Register _R_44 ("ParticleDataImpl<Real>","multConst",ParticleDataImpl<Real>::_W_29);
+ static const Pb::Register _R_45 ("ParticleDataImpl<Real>","clamp",ParticleDataImpl<Real>::_W_30);
+ static const Pb::Register _R_46 ("ParticleDataImpl<Real>","getMaxAbsValue",ParticleDataImpl<Real>::_W_31);
+ static const Pb::Register _R_47 ("ParticleDataImpl<Real>","getMaxValue",ParticleDataImpl<Real>::_W_32);
+ static const Pb::Register _R_48 ("ParticleDataImpl<Real>","getMinValue",ParticleDataImpl<Real>::_W_33);
+ static const Pb::Register _R_49 ("ParticleDataImpl<Real>","printPdata",ParticleDataImpl<Real>::_W_34);
+ static const Pb::Register _R_50 ("ParticleDataImpl<Real>","save",ParticleDataImpl<Real>::_W_35);
+ static const Pb::Register _R_51 ("ParticleDataImpl<Real>","load",ParticleDataImpl<Real>::_W_36);
+ static const Pb::Register _R_52 ("ParticleDataImpl<Vec3>","ParticleDataImpl<Vec3>","ParticleDataBase"); template<> const char* Namify<ParticleDataImpl<Vec3> >::S = "ParticleDataImpl<Vec3>";
+ static const Pb::Register _R_53 ("ParticleDataImpl<Vec3>","ParticleDataImpl",ParticleDataImpl<Vec3>::_W_19);
+ static const Pb::Register _R_54 ("ParticleDataImpl<Vec3>","clear",ParticleDataImpl<Vec3>::_W_20);
+ static const Pb::Register _R_55 ("ParticleDataImpl<Vec3>","setSource",ParticleDataImpl<Vec3>::_W_21);
+ static const Pb::Register _R_56 ("ParticleDataImpl<Vec3>","setConst",ParticleDataImpl<Vec3>::_W_22);
+ static const Pb::Register _R_57 ("ParticleDataImpl<Vec3>","copyFrom",ParticleDataImpl<Vec3>::_W_23);
+ static const Pb::Register _R_58 ("ParticleDataImpl<Vec3>","add",ParticleDataImpl<Vec3>::_W_24);
+ static const Pb::Register _R_59 ("ParticleDataImpl<Vec3>","sub",ParticleDataImpl<Vec3>::_W_25);
+ static const Pb::Register _R_60 ("ParticleDataImpl<Vec3>","addConst",ParticleDataImpl<Vec3>::_W_26);
+ static const Pb::Register _R_61 ("ParticleDataImpl<Vec3>","addScaled",ParticleDataImpl<Vec3>::_W_27);
+ static const Pb::Register _R_62 ("ParticleDataImpl<Vec3>","mult",ParticleDataImpl<Vec3>::_W_28);
+ static const Pb::Register _R_63 ("ParticleDataImpl<Vec3>","multConst",ParticleDataImpl<Vec3>::_W_29);
+ static const Pb::Register _R_64 ("ParticleDataImpl<Vec3>","clamp",ParticleDataImpl<Vec3>::_W_30);
+ static const Pb::Register _R_65 ("ParticleDataImpl<Vec3>","getMaxAbsValue",ParticleDataImpl<Vec3>::_W_31);
+ static const Pb::Register _R_66 ("ParticleDataImpl<Vec3>","getMaxValue",ParticleDataImpl<Vec3>::_W_32);
+ static const Pb::Register _R_67 ("ParticleDataImpl<Vec3>","getMinValue",ParticleDataImpl<Vec3>::_W_33);
+ static const Pb::Register _R_68 ("ParticleDataImpl<Vec3>","printPdata",ParticleDataImpl<Vec3>::_W_34);
+ static const Pb::Register _R_69 ("ParticleDataImpl<Vec3>","save",ParticleDataImpl<Vec3>::_W_35);
+ static const Pb::Register _R_70 ("ParticleDataImpl<Vec3>","load",ParticleDataImpl<Vec3>::_W_36);
+#endif
+#ifdef _C_ParticleIndexSystem
+ static const Pb::Register _R_71 ("ParticleIndexSystem","ParticleIndexSystem","ParticleSystem<ParticleIndexData>"); template<> const char* Namify<ParticleIndexSystem >::S = "ParticleIndexSystem";
+ static const Pb::Register _R_72 ("ParticleIndexSystem","ParticleIndexSystem",ParticleIndexSystem::_W_16);
+#endif
+#ifdef _C_ParticleSystem
+ static const Pb::Register _R_73 ("ParticleSystem<BasicParticleData>","ParticleSystem<BasicParticleData>","ParticleBase"); template<> const char* Namify<ParticleSystem<BasicParticleData> >::S = "ParticleSystem<BasicParticleData>";
+ static const Pb::Register _R_74 ("ParticleSystem<BasicParticleData>","ParticleSystem",ParticleSystem<BasicParticleData>::_W_2);
+ static const Pb::Register _R_75 ("ParticleSystem<BasicParticleData>","size",ParticleSystem<BasicParticleData>::_W_3);
+ static const Pb::Register _R_76 ("ParticleSystem<BasicParticleData>","setPos",ParticleSystem<BasicParticleData>::_W_4);
+ static const Pb::Register _R_77 ("ParticleSystem<BasicParticleData>","getPos",ParticleSystem<BasicParticleData>::_W_5);
+ static const Pb::Register _R_78 ("ParticleSystem<BasicParticleData>","getPosPdata",ParticleSystem<BasicParticleData>::_W_6);
+ static const Pb::Register _R_79 ("ParticleSystem<BasicParticleData>","setPosPdata",ParticleSystem<BasicParticleData>::_W_7);
+ static const Pb::Register _R_80 ("ParticleSystem<BasicParticleData>","clear",ParticleSystem<BasicParticleData>::_W_8);
+ static const Pb::Register _R_81 ("ParticleSystem<BasicParticleData>","advectInGrid",ParticleSystem<BasicParticleData>::_W_9);
+ static const Pb::Register _R_82 ("ParticleSystem<BasicParticleData>","projectOutside",ParticleSystem<BasicParticleData>::_W_10);
+ static const Pb::Register _R_83 ("ParticleSystem<ParticleIndexData>","ParticleSystem<ParticleIndexData>","ParticleBase"); template<> const char* Namify<ParticleSystem<ParticleIndexData> >::S = "ParticleSystem<ParticleIndexData>";
+ static const Pb::Register _R_84 ("ParticleSystem<ParticleIndexData>","ParticleSystem",ParticleSystem<ParticleIndexData>::_W_2);
+ static const Pb::Register _R_85 ("ParticleSystem<ParticleIndexData>","size",ParticleSystem<ParticleIndexData>::_W_3);
+ static const Pb::Register _R_86 ("ParticleSystem<ParticleIndexData>","setPos",ParticleSystem<ParticleIndexData>::_W_4);
+ static const Pb::Register _R_87 ("ParticleSystem<ParticleIndexData>","getPos",ParticleSystem<ParticleIndexData>::_W_5);
+ static const Pb::Register _R_88 ("ParticleSystem<ParticleIndexData>","getPosPdata",ParticleSystem<ParticleIndexData>::_W_6);
+ static const Pb::Register _R_89 ("ParticleSystem<ParticleIndexData>","setPosPdata",ParticleSystem<ParticleIndexData>::_W_7);
+ static const Pb::Register _R_90 ("ParticleSystem<ParticleIndexData>","clear",ParticleSystem<ParticleIndexData>::_W_8);
+ static const Pb::Register _R_91 ("ParticleSystem<ParticleIndexData>","advectInGrid",ParticleSystem<ParticleIndexData>::_W_9);
+ static const Pb::Register _R_92 ("ParticleSystem<ParticleIndexData>","projectOutside",ParticleSystem<ParticleIndexData>::_W_10);
+#endif
+static const Pb::Register _R_0 ("ParticleDataImpl<int>","PdataInt","");
+static const Pb::Register _R_1 ("ParticleDataImpl<Real>","PdataReal","");
+static const Pb::Register _R_2 ("ParticleDataImpl<Vec3>","PdataVec3","");
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/plugin/advection.cpp b/source/blender/python/manta_pp/plugin/advection.cpp
new file mode 100644
index 00000000000..fbf04f0ba2e
--- /dev/null
+++ b/source/blender/python/manta_pp/plugin/advection.cpp
@@ -0,0 +1,337 @@
+
+
+
+
+
+// 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
+ *
+ * Plugins for pressure correction:
+ * - solve_pressure
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+
+using namespace std;
+
+namespace Manta {
+
+static inline bool isNotFluid(FlagGrid& flags, int i, int j, int k)
+{
+ if ( flags.isFluid(i,j,k) ) return false;
+ if ( flags.isFluid(i-1,j,k) ) return false;
+ if ( flags.isFluid(i,j-1,k) ) return false;
+ if ( flags.is3D() ) {
+ if ( flags.isFluid(i,j,k-1) ) return false;
+ }
+ return true;
+}
+
+//! Semi-Lagrange interpolation kernel
+
+
+template <class T> struct SemiLagrange : public KernelBase { SemiLagrange(FlagGrid& flags, MACGrid& vel, Grid<T>& dst, Grid<T>& src, Real dt, bool isLevelset) : KernelBase(&flags,1) ,flags(flags),vel(vel),dst(dst),src(src),dt(dt),isLevelset(isLevelset) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, Grid<T>& dst, Grid<T>& src, Real dt, bool isLevelset ) {
+ if (flags.isObstacle(i,j,k)) {
+ dst(i,j,k) = 0;
+ return;
+ }
+ if (!isLevelset && isNotFluid(flags,i,j,k) ) {
+ dst(i,j,k) = src(i,j,k);
+ return;
+ }
+
+ // SL traceback
+ Vec3 pos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getCentered(i,j,k) * dt;
+ dst(i,j,k) = src.getInterpolated(pos);
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline MACGrid& getArg1() { return vel; } typedef MACGrid type1;inline Grid<T>& getArg2() { return dst; } typedef Grid<T> type2;inline 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; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; 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); } FlagGrid& flags; MACGrid& vel; Grid<T>& dst; Grid<T>& src; Real dt; bool isLevelset; };
+
+static inline bool isNotFluidMAC(FlagGrid& flags, int i, int j, int k)
+{
+ if ( flags.isFluid(i,j,k) ) return false;
+ return true;
+}
+
+//! Semi-Lagrange interpolation kernel for MAC grids
+
+
+ struct SemiLagrangeMAC : public KernelBase { SemiLagrangeMAC(FlagGrid& flags, MACGrid& vel, MACGrid& dst, MACGrid& src, Real dt) : KernelBase(&flags,1) ,flags(flags),vel(vel),dst(dst),src(src),dt(dt) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, MACGrid& dst, MACGrid& src, Real dt ) {
+ if (flags.isObstacle(i,j,k)) {
+ dst(i,j,k) = 0;
+ return;
+ }
+ if ( isNotFluidMAC(flags,i,j,k) ) {
+ dst(i,j,k) = src(i,j,k);
+ return;
+ }
+
+ // 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.getInterpolatedComponent<0>(xpos);
+ Vec3 ypos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACY(i,j,k) * dt;
+ Real vy = src.getInterpolatedComponent<1>(ypos);
+ Vec3 zpos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACZ(i,j,k) * dt;
+ Real vz = src.getInterpolatedComponent<2>(zpos);
+
+ dst(i,j,k) = Vec3(vx,vy,vz);
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline MACGrid& getArg1() { return vel; } typedef MACGrid type1;inline MACGrid& getArg2() { return dst; } typedef MACGrid type2;inline MACGrid& getArg3() { return src; } typedef MACGrid type3;inline Real& getArg4() { return dt; } typedef Real type4; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, flags,vel,dst,src,dt); } FlagGrid& flags; MACGrid& vel; MACGrid& dst; MACGrid& src; Real dt; };
+
+//! Kernel: Correct based on forward and backward SL steps (for both centered & mac grids)
+
+
+
+template <class T> struct MacCormackCorrect : public KernelBase { MacCormackCorrect(FlagGrid& flags, Grid<T>& dst, Grid<T>& old, Grid<T>& fwd, 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) { run(); } inline void op(int idx, FlagGrid& flags, Grid<T>& dst, Grid<T>& old, Grid<T>& fwd, Grid<T>& bwd, Real strength, bool isLevelSet, bool isMAC=false ) {
+ // note, replacement for isNotFluidMAC and isNotFluid
+ bool skip = false;
+
+ if (!flags.isFluid(idx)) skip = true;
+ if(!isMAC) {
+ if( (idx>=flags.getStrideX()) && (!flags.isFluid(idx-flags.getStrideX()) )) skip = true;
+ if( (idx>=flags.getStrideY()) && (!flags.isFluid(idx-flags.getStrideY()) )) skip = true;
+ if ( flags.is3D() ) {
+ if( (idx>=flags.getStrideZ()) &&(!flags.isFluid(idx-flags.getStrideZ()) )) skip = true;
+ } }
+ if ( skip ) {
+ dst[idx] = isLevelSet ? fwd[idx] : (T)0.0;
+ return;
+ }
+
+ // note, strenth of correction can be modified here
+ dst[idx] = fwd[idx] + strength * 0.5 * (old[idx] - bwd[idx]);
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<T>& getArg1() { return dst; } typedef Grid<T> type1;inline Grid<T>& getArg2() { return old; } typedef Grid<T> type2;inline Grid<T>& getArg3() { return fwd; } typedef Grid<T> type3;inline 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, flags,dst,old,fwd,bwd,strength,isLevelSet,isMAC); } FlagGrid& flags; Grid<T>& dst; Grid<T>& old; Grid<T>& fwd; 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);
+}
+
+
+//! Helper function for clamping non-mac grids
+template<class T>
+inline T doClampComponent(const Vec3i& upperClamp, Grid<T>& orig, T dst, const Vec3i& posFwd) {
+ // clamp forward lookup to grid
+ const int i0 = clamp(posFwd.x, 0, upperClamp.x-1);
+ const int j0 = clamp(posFwd.y, 0, upperClamp.y-1);
+ const int k0 = clamp(posFwd.z, 0, (orig.is3D() ? (upperClamp.z-1) : 1) );
+ const int i1 = i0+1, j1 = j0+1, k1= (orig.is3D() ? (k0+1) : k0);
+
+ if (!orig.isInBounds(Vec3i(i0,j0,k0),1)) {
+ return dst;
+ }
+
+ // find min/max around fwd pos
+ T minv = orig(i0,j0,k0), maxv = minv;
+ getMinMax(minv, maxv, orig(i1,j0,k0));
+ getMinMax(minv, maxv, orig(i0,j1,k0));
+ getMinMax(minv, maxv, orig(i1,j1,k0));
+ getMinMax(minv, maxv, orig(i0,j0,k1));
+ getMinMax(minv, maxv, orig(i1,j0,k1));
+ getMinMax(minv, maxv, orig(i0,j1,k1));
+ getMinMax(minv, maxv, orig(i1,j1,k1));
+
+ // write clamped value
+ return clamp(dst, minv, maxv);
+}
+
+//! Helper function for clamping MAC grids
+template<int c>
+inline Real doClampComponentMAC(const Vec3i& upperClamp, MACGrid& orig, Real dst, const Vec3i& posFwd) {
+ // clamp forward lookup to grid
+ const int i0 = clamp(posFwd.x, 0, upperClamp.x-1);
+ const int j0 = clamp(posFwd.y, 0, upperClamp.y-1);
+ const int k0 = clamp(posFwd.z, 0, (orig.is3D() ? (upperClamp.z-1) : 1) );
+ const int i1 = i0+1, j1 = j0+1, k1= (orig.is3D() ? (k0+1) : k0);
+ if (!orig.isInBounds(Vec3i(i0,j0,k0),1))
+ return dst;
+
+ // find min/max around fwd pos
+ Real minv = orig(i0,j0,k0)[c], maxv = minv;
+ getMinMax(minv, maxv, orig(i1,j0,k0)[c]);
+ getMinMax(minv, maxv, orig(i0,j1,k0)[c]);
+ getMinMax(minv, maxv, orig(i1,j1,k0)[c]);
+ 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]);
+
+ return clamp(dst, minv, maxv);
+}
+
+//! 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(FlagGrid& flags, MACGrid& vel, Grid<T>& dst, Grid<T>& orig, Grid<T>& fwd, Real dt) : KernelBase(&flags,1) ,flags(flags),vel(vel),dst(dst),orig(orig),fwd(fwd),dt(dt) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, Grid<T>& dst, Grid<T>& orig, Grid<T>& fwd, Real dt ) {
+ if (flags.isObstacle(i,j,k))
+ return;
+ if ( isNotFluid(flags,i,j,k) ) {
+ dst(i,j,k) = fwd(i,j,k);
+ return;
+ }
+
+ T dval = dst(i,j,k);
+ Vec3i upperClamp = flags.getSize() - 1;
+
+ // lookup forward/backward
+ Vec3i posFwd = toVec3i( Vec3(i,j,k) - vel.getCentered(i,j,k) * dt );
+ Vec3i posBwd = toVec3i( Vec3(i,j,k) + vel.getCentered(i,j,k) * dt );
+
+ dval = doClampComponent<T>(upperClamp, orig, dval, posFwd );
+
+ // test if lookups point out of grid or into obstacle
+ if (posFwd.x < 0 || posFwd.y < 0 || posFwd.z < 0 ||
+ posBwd.x < 0 || posBwd.y < 0 || posBwd.z < 0 ||
+ posFwd.x > upperClamp.x || posFwd.y > upperClamp.y || ((posFwd.z > upperClamp.z)&&flags.is3D()) ||
+ posBwd.x > upperClamp.x || posBwd.y > upperClamp.y || ((posBwd.z > upperClamp.z)&&flags.is3D()) ||
+ flags.isObstacle(posFwd) || flags.isObstacle(posBwd) )
+ {
+ dval = fwd(i,j,k);
+ }
+ dst(i,j,k) = dval;
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline MACGrid& getArg1() { return vel; } typedef MACGrid type1;inline Grid<T>& getArg2() { return dst; } typedef Grid<T> type2;inline Grid<T>& getArg3() { return orig; } typedef Grid<T> type3;inline Grid<T>& getArg4() { return fwd; } typedef Grid<T> type4;inline Real& getArg5() { return dt; } typedef Real type5; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; 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); } FlagGrid& flags; MACGrid& vel; Grid<T>& dst; Grid<T>& orig; Grid<T>& fwd; Real dt; };
+
+//! Kernel: same as MacCormackClamp above, but specialized version for MAC grids
+
+
+ struct MacCormackClampMAC : public KernelBase { MacCormackClampMAC(FlagGrid& flags, MACGrid& vel, MACGrid& dst, MACGrid& orig, MACGrid& fwd, Real dt) : KernelBase(&flags,1) ,flags(flags),vel(vel),dst(dst),orig(orig),fwd(fwd),dt(dt) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, MACGrid& dst, MACGrid& orig, MACGrid& fwd, Real dt ) {
+ if (flags.isObstacle(i,j,k))
+ return;
+ if ( isNotFluidMAC(flags,i,j,k) ) {
+ dst(i,j,k) = fwd(i,j,k);
+ return;
+ }
+
+ Vec3 pos(i,j,k);
+ Vec3 dval = dst(i,j,k);
+ Vec3i upperClamp = flags.getSize() - 1;
+
+ // get total fwd lookup
+ Vec3i posFwd = toVec3i( Vec3(i,j,k) - vel.getCentered(i,j,k) * dt );
+ Vec3i posBwd = toVec3i( Vec3(i,j,k) + vel.getCentered(i,j,k) * dt );
+
+ // clamp individual components
+ dval.x = doClampComponentMAC<0>(upperClamp, orig, dval.x, toVec3i( pos - vel.getAtMACX(i,j,k) * dt) );
+ dval.y = doClampComponentMAC<1>(upperClamp, orig, dval.y, toVec3i( pos - vel.getAtMACY(i,j,k) * dt) );
+ dval.z = doClampComponentMAC<2>(upperClamp, orig, dval.z, toVec3i( pos - vel.getAtMACZ(i,j,k) * dt) );
+
+ // test if lookups point out of grid or into obstacle
+ if (posFwd.x < 0 || posFwd.y < 0 || posFwd.z < 0 ||
+ posBwd.x < 0 || posBwd.y < 0 || posBwd.z < 0 ||
+ posFwd.x > upperClamp.x || posFwd.y > upperClamp.y || ((posFwd.z > upperClamp.z)&&flags.is3D()) ||
+ posBwd.x > upperClamp.x || posBwd.y > upperClamp.y || ((posBwd.z > upperClamp.z)&&flags.is3D())
+ //|| flags.isObstacle(posFwd) || flags.isObstacle(posBwd) // note - this unfortunately introduces asymmetry... TODO update
+ )
+ {
+ dval = fwd(i,j,k);
+ }
+
+ // writeback
+ dst(i,j,k) = dval;
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline MACGrid& getArg1() { return vel; } typedef MACGrid type1;inline MACGrid& getArg2() { return dst; } typedef MACGrid type2;inline MACGrid& getArg3() { return orig; } typedef MACGrid type3;inline MACGrid& getArg4() { return fwd; } typedef MACGrid type4;inline Real& getArg5() { return dt; } typedef Real type5; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; 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); } FlagGrid& flags; MACGrid& vel; MACGrid& dst; MACGrid& orig; MACGrid& fwd; Real dt; };
+
+//! template function for performing SL advection
+template<class GridType>
+void fnAdvectSemiLagrange(FluidSolver* parent, FlagGrid& flags, MACGrid& vel, GridType& orig, int order, Real strength) {
+ 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);
+
+ 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);
+
+ // newGrid <- compute correction
+ MacCormackCorrect<T> (flags, newGrid, orig, fwd, bwd, strength, levelset);
+
+ // clamp values
+ MacCormackClamp<T> (flags, vel, newGrid, orig, fwd, dt);
+
+ orig.swap(newGrid);
+ }
+}
+
+//! template function for performing SL advection: specialized version for MAC grids
+template<>
+void fnAdvectSemiLagrange<MACGrid>(FluidSolver* parent, FlagGrid& flags, MACGrid& vel, MACGrid& orig, int order, Real strength) {
+ Real dt = parent->getDt();
+
+ // forward step
+ MACGrid fwd(parent);
+ SemiLagrangeMAC (flags, vel, fwd, orig, dt);
+
+ if (order == 1) {
+ orig.swap(fwd);
+ }
+ else if (order == 2) { // MacCormack
+ MACGrid bwd(parent);
+ MACGrid newGrid(parent);
+
+ // bwd <- backwards step
+ SemiLagrangeMAC (flags, vel, bwd, fwd, -dt);
+
+ // newGrid <- compute correction
+ MacCormackCorrect<Vec3> (flags, newGrid, orig, fwd, bwd, strength, false, true);
+
+ // clamp values
+ MacCormackClampMAC (flags, vel, newGrid, orig, fwd, dt);
+
+ orig.swap(newGrid);
+ }
+}
+
+//! Perform semi-lagrangian advection of target Real- or Vec3 grid
+
+
+void advectSemiLagrange(FlagGrid* flags, MACGrid* vel, GridBase* grid, int order = 1, Real strength = 1.0) {
+ assertMsg(order==1 || order==2, "AdvectSemiLagrange: Only order 1 (regular SL) and 2 (MacCormack) supported");
+
+ // determine type of grid
+ if (grid->getType() & GridBase::TypeReal) {
+ fnAdvectSemiLagrange< Grid<Real> >(flags->getParent(), *flags, *vel, *((Grid<Real>*) grid), order, strength);
+ }
+ else if (grid->getType() & GridBase::TypeMAC) {
+ fnAdvectSemiLagrange< MACGrid >(flags->getParent(), *flags, *vel, *((MACGrid*) grid), order, strength);
+ }
+ else if (grid->getType() & GridBase::TypeVec3) {
+ fnAdvectSemiLagrange< Grid<Vec3> >(flags->getParent(), *flags, *vel, *((Grid<Vec3>*) grid), order, strength);
+ }
+ else
+ errMsg("AdvectSemiLagrange: Grid Type is not supported (only Real, Vec3, MAC, Levelset)");
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "advectSemiLagrange" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid* flags = _args.getPtr<FlagGrid >("flags",0,&_lock); 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); _retval = getPyNone(); advectSemiLagrange(flags,vel,grid,order,strength); _args.check(); } pbFinalizePlugin(parent,"advectSemiLagrange" ); return _retval; } catch(std::exception& e) { pbSetError("advectSemiLagrange",e.what()); return 0; } } static const Pb::Register _RP_advectSemiLagrange ("","advectSemiLagrange",_W_0);
+
+} // end namespace DDF
+
+
+
diff --git a/source/blender/python/manta_pp/plugin/extforces.cpp b/source/blender/python/manta_pp/plugin/extforces.cpp
new file mode 100644
index 00000000000..b0de81ee2cf
--- /dev/null
+++ b/source/blender/python/manta_pp/plugin/extforces.cpp
@@ -0,0 +1,207 @@
+
+
+
+
+
+// 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"
+
+using namespace std;
+
+namespace Manta {
+
+// MLE 2014-07-05 copy from pressure.cpp
+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 Forces between fl/fl and fl/em cells
+ struct KnAddForceField : public KernelBase { KnAddForceField(FlagGrid& flags, MACGrid& vel, Grid<Vec3>& force) : KernelBase(&flags,1) ,flags(flags),vel(vel),force(force) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, Grid<Vec3>& force ) {
+ 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)))
+ vel(i,j,k).x += 0.5*(force(i-1,j,k).x + force(i,j,k).x);
+ if (flags.isFluid(i,j-1,k) || (curFluid && flags.isEmpty(i,j-1,k)))
+ vel(i,j,k).y += 0.5*(force(i,j-1,k).y + force(i,j,k).y);
+ if (vel.is3D() && (flags.isFluid(i,j,k-1) || (curFluid && flags.isEmpty(i,j,k-1))))
+ vel(i,j,k).z += 0.5*(force(i,j,k-1).z + force(i,j,k).z);
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline MACGrid& getArg1() { return vel; } typedef MACGrid type1;inline Grid<Vec3>& getArg2() { return force; } typedef Grid<Vec3> type2; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, flags,vel,force); } FlagGrid& flags; MACGrid& vel; Grid<Vec3>& force; };
+
+//! add Forces between fl/fl and fl/em cells
+ struct KnAddForce : public KernelBase { KnAddForce(FlagGrid& flags, MACGrid& vel, Vec3 force) : KernelBase(&flags,1) ,flags(flags),vel(vel),force(force) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, Vec3 force ) {
+ 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)))
+ vel(i,j,k).x += force.x;
+ if (flags.isFluid(i,j-1,k) || (curFluid && flags.isEmpty(i,j-1,k)))
+ vel(i,j,k).y += force.y;
+ if (vel.is3D() && (flags.isFluid(i,j,k-1) || (curFluid && flags.isEmpty(i,j,k-1))))
+ vel(i,j,k).z += force.z;
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline MACGrid& getArg1() { return vel; } typedef MACGrid type1;inline Vec3& getArg2() { return force; } typedef Vec3 type2; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, flags,vel,force); } FlagGrid& flags; MACGrid& vel; Vec3 force; };
+
+//! add external force fields to all fluid cells
+void addForceField(FlagGrid& flags, MACGrid& vel, Grid<Vec3>& force){
+ KnAddForceField(flags, vel, force);
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "addForceField" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); Grid<Vec3>& force = *_args.getPtr<Grid<Vec3> >("force",2,&_lock); _retval = getPyNone(); addForceField(flags,vel,force); _args.check(); } pbFinalizePlugin(parent,"addForceField" ); return _retval; } catch(std::exception& e) { pbSetError("addForceField",e.what()); return 0; } } static const Pb::Register _RP_addForceField ("","addForceField",_W_0);
+
+//! add gravity forces to all fluid cells
+void addGravity(FlagGrid& flags, MACGrid& vel, Vec3 gravity) {
+ Vec3 f = gravity * flags.getParent()->getDt() / flags.getDx();
+ KnAddForce(flags, vel, f);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "addGravity" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); Vec3 gravity = _args.get<Vec3 >("gravity",2,&_lock); _retval = getPyNone(); addGravity(flags,vel,gravity); _args.check(); } pbFinalizePlugin(parent,"addGravity" ); return _retval; } catch(std::exception& e) { pbSetError("addGravity",e.what()); return 0; } } static const Pb::Register _RP_addGravity ("","addGravity",_W_1);
+
+//! add Buoyancy force based on smoke density
+ struct KnAddBuoyancy : public KernelBase { KnAddBuoyancy(FlagGrid& flags, Grid<Real>& density, MACGrid& vel, Vec3 strength) : KernelBase(&flags,1) ,flags(flags),density(density),vel(vel),strength(strength) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<Real>& density, MACGrid& vel, Vec3 strength ) {
+ if (!flags.isFluid(i,j,k)) return;
+ if (flags.isFluid(i-1,j,k))
+ vel(i,j,k).x += (0.5 * strength.x) * (density(i,j,k)+density(i-1,j,k));
+ if (flags.isFluid(i,j-1,k))
+ vel(i,j,k).y += (0.5 * strength.y) * (density(i,j,k)+density(i,j-1,k));
+ if (vel.is3D() && flags.isFluid(i,j,k-1))
+ vel(i,j,k).z += (0.5 * strength.z) * (density(i,j,k)+density(i,j,k-1));
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Real>& getArg1() { return density; } typedef Grid<Real> type1;inline MACGrid& getArg2() { return vel; } typedef MACGrid type2;inline Vec3& getArg3() { return strength; } typedef Vec3 type3; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, flags,density,vel,strength); } FlagGrid& flags; Grid<Real>& density; MACGrid& vel; Vec3 strength; };
+
+//! add Buoyancy force based on smoke density
+void addBuoyancy(FlagGrid& flags, Grid<Real>& density, MACGrid& vel, Vec3 gravity) {
+ Vec3 f = - gravity * flags.getParent()->getDt() / flags.getParent()->getDx();
+ KnAddBuoyancy(flags,density, vel, f);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "addBuoyancy" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); 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); _retval = getPyNone(); addBuoyancy(flags,density,vel,gravity); _args.check(); } pbFinalizePlugin(parent,"addBuoyancy" ); return _retval; } catch(std::exception& e) { pbSetError("addBuoyancy",e.what()); return 0; } } static const Pb::Register _RP_addBuoyancy ("","addBuoyancy",_W_2);
+
+//! add Buoyancy force based on density and heat field
+ struct KnAddHeatBuoyancy : public KernelBase { KnAddHeatBuoyancy(FlagGrid& flags, Grid<Real>& density,float densCoeff, MACGrid& vel, Vec3 strength, Grid<Real>& heat, float heatCoeff) : KernelBase(&flags,1) ,flags(flags),density(density),densCoeff(densCoeff),vel(vel),strength(strength),heat(heat),heatCoeff(heatCoeff) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<Real>& density,float densCoeff, MACGrid& vel, Vec3 strength, Grid<Real>& heat, float heatCoeff ) {
+ if (!flags.isFluid(i,j,k)) return;
+ vel(i,j,k).x += (strength.x) * (densCoeff * density(i,j,k) - heatCoeff * heat(i,j,k));
+ vel(i,j,k).y += (strength.y) * (densCoeff * density(i,j,k) - heatCoeff * heat(i,j,k));
+ vel(i,j,k).z += (strength.z) * (densCoeff * density(i,j,k) - heatCoeff * heat(i,j,k));
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Real>& getArg1() { return density; } typedef Grid<Real> type1;inline float& getArg2() { return densCoeff; } typedef float type2;inline MACGrid& getArg3() { return vel; } typedef MACGrid type3;inline Vec3& getArg4() { return strength; } typedef Vec3 type4;inline Grid<Real>& getArg5() { return heat; } typedef Grid<Real> type5;inline float& getArg6() { return heatCoeff; } typedef float type6; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, flags,density,densCoeff,vel,strength,heat,heatCoeff); } FlagGrid& flags; Grid<Real>& density; float densCoeff; MACGrid& vel; Vec3 strength; Grid<Real>& heat; float heatCoeff; };
+//! add Buoyancy force based on density and heat field
+void addHeatBuoyancy(FlagGrid& flags, Grid<Real>& density,float densCoeff, MACGrid& vel, Vec3 gravity, Grid<Real>& heat, float heatCoeff) {
+ Vec3 f = - gravity;
+ KnAddHeatBuoyancy(flags,density,densCoeff, vel, f, heat, heatCoeff);
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "addHeatBuoyancy" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); float densCoeff = _args.get<float >("densCoeff",2,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",3,&_lock); Vec3 gravity = _args.get<Vec3 >("gravity",4,&_lock); Grid<Real>& heat = *_args.getPtr<Grid<Real> >("heat",5,&_lock); float heatCoeff = _args.get<float >("heatCoeff",6,&_lock); _retval = getPyNone(); addHeatBuoyancy(flags,density,densCoeff,vel,gravity,heat,heatCoeff); _args.check(); } pbFinalizePlugin(parent,"addHeatBuoyancy" ); return _retval; } catch(std::exception& e) { pbSetError("addHeatBuoyancy",e.what()); return 0; } } static const Pb::Register _RP_addHeatBuoyancy ("","addHeatBuoyancy",_W_3);
+
+//! set no-stick wall boundary condition between ob/fl and ob/ob cells
+ struct KnSetWallBcs : public KernelBase { KnSetWallBcs(FlagGrid& flags, MACGrid& vel, Vector3D<bool> lo, Vector3D<bool> up, bool admm) : KernelBase(&flags,0) ,flags(flags),vel(vel),lo(lo),up(up),admm(admm) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, Vector3D<bool> lo, Vector3D<bool> up, bool admm ) {
+
+ bool curFluid = flags.isFluid(i,j,k);
+ bool curObstacle = flags.isObstacle(i,j,k);
+ if (!curFluid && !curObstacle) return;
+
+ // MLE 2014-07-04
+ // if not admm, leave it as in orig
+ // if openBound, don't correct anything (solid is as empty)
+ // if admm, correct if vel is pointing outwards
+
+ // if "inner" obstacle vel
+ if(i>0 && curObstacle && !flags.isFluid(i-1,j,k)) vel(i,j,k).x = 0;
+ if(j>0 && curObstacle && !flags.isFluid(i,j-1,k)) vel(i,j,k).y = 0;
+
+ // check lo.x
+ if(!lo.x && i>0 && curFluid && flags.isObstacle(i-1,j,k) && ((admm&&vel(i,j,k).x<0)||!admm)) vel(i,j,k).x = 0;
+ // check up.x
+ if(!up.x && i>0 && curObstacle && flags.isFluid(i-1,j,k) && ((admm&&vel(i,j,k).x>0)||!admm)) vel(i,j,k).x = 0;
+ // check lo.y
+ if(!lo.y && j>0 && curFluid && flags.isObstacle(i,j-1,k) && ((admm&&vel(i,j,k).y<0)||!admm)) vel(i,j,k).y = 0;
+ // check up.y
+ if(!up.y && j>0 && curObstacle && flags.isFluid(i,j-1,k) && ((admm&&vel(i,j,k).y>0)||!admm)) vel(i,j,k).y = 0;
+ // check lo.z
+ if(!lo.z && k>0 && curFluid && flags.isObstacle(i,j,k-1) && ((admm&&vel(i,j,k).z<0)||!admm)) vel(i,j,k).z = 0;
+ // check up.z
+ if(!up.z && k>0 && curObstacle && flags.isFluid(i,j,k-1) && ((admm&&vel(i,j,k).z>0)||!admm)) vel(i,j,k).z = 0;
+
+
+ /* MLE consider later
+ 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 FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline MACGrid& getArg1() { return vel; } typedef MACGrid type1;inline Vector3D<bool> & getArg2() { return lo; } typedef Vector3D<bool> type2;inline Vector3D<bool> & getArg3() { return up; } typedef Vector3D<bool> type3;inline bool& getArg4() { return admm; } typedef bool type4; 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,vel,lo,up,admm); } FlagGrid& flags; MACGrid& vel; Vector3D<bool> lo; Vector3D<bool> up; bool admm; };
+
+// MLE 2014-07-04
+//! set no-stick boundary condition on walls
+void setWallBcs(FlagGrid& flags, MACGrid& vel, string openBound="", bool admm=false) {
+ Vector3D<bool> lo, up;
+ convertDescToVec(openBound, lo, up);
+ KnSetWallBcs(flags, vel, lo, up, admm);
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "setWallBcs" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); string openBound = _args.getOpt<string >("openBound",2,"",&_lock); bool admm = _args.getOpt<bool >("admm",3,false,&_lock); _retval = getPyNone(); setWallBcs(flags,vel,openBound,admm); _args.check(); } pbFinalizePlugin(parent,"setWallBcs" ); return _retval; } catch(std::exception& e) { pbSetError("setWallBcs",e.what()); return 0; } } static const Pb::Register _RP_setWallBcs ("","setWallBcs",_W_4);
+//! Kernel: gradient norm operator
+ struct KnConfForce : public KernelBase { KnConfForce(Grid<Vec3>& force, const Grid<Real>& grid, const Grid<Vec3>& curl, Real str) : KernelBase(&force,1) ,force(force),grid(grid),curl(curl),str(str) { run(); } inline void op(int i, int j, int k, Grid<Vec3>& force, const Grid<Real>& grid, const Grid<Vec3>& curl, Real str ) {
+ 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);
+ 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; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, force,grid,curl,str); } Grid<Vec3>& force; const Grid<Real>& grid; const Grid<Vec3>& curl; Real str; };
+
+void vorticityConfinement(MACGrid& vel, FlagGrid& flags, Real strength) {
+ 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, strength);
+ KnAddForceField(flags, vel, force);
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "vorticityConfinement" ); PyObject *_retval = 0; { ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); Real strength = _args.get<Real >("strength",2,&_lock); _retval = getPyNone(); vorticityConfinement(vel,flags,strength); _args.check(); } pbFinalizePlugin(parent,"vorticityConfinement" ); return _retval; } catch(std::exception& e) { pbSetError("vorticityConfinement",e.what()); return 0; } } static const Pb::Register _RP_vorticityConfinement ("","vorticityConfinement",_W_5);
+
+//! 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) { run(); } inline void op(int i, int j, int k, MACGrid& vel, int dim, int p0, const Vec3& val ) {
+ 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 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, vel,dim,p0,val); } 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_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "setInflowBcs" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("setInflowBcs",e.what()); return 0; } } static const Pb::Register _RP_setInflowBcs ("","setInflowBcs",_W_6);
+
+} // namespace
+
+
diff --git a/source/blender/python/manta_pp/plugin/flip.cpp b/source/blender/python/manta_pp/plugin/flip.cpp
new file mode 100644
index 00000000000..a0a5a681dc3
--- /dev/null
+++ b/source/blender/python/manta_pp/plugin/flip.cpp
@@ -0,0 +1,500 @@
+
+
+
+
+
+// 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
+ *
+ * FLIP (fluid implicit particles)
+ * for use with particle data fields
+ *
+ ******************************************************************************/
+
+#include "particle.h"
+#include "grid.h"
+#include "randomstream.h"
+#include "levelset.h"
+
+using namespace std;
+namespace Manta {
+
+
+
+
+// init
+
+
+
+void sampleFlagsWithParticles( FlagGrid& flags, BasicParticleSystem& parts, int discretization, Real randomness ) {
+ bool is3D = flags.is3D();
+ Real jlen = randomness / discretization;
+ Vec3 disp (1.0 / discretization, 1.0 / discretization, 1.0/discretization);
+ RandomStream mRand(9832);
+
+ //clear();
+
+ FOR_IJK_BND(flags, 0) {
+ if ( flags.isObstacle(i,j,k) ) continue;
+ if ( flags.isFluid(i,j,k) ) {
+ 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.add( BasicParticleData(subpos) );
+ }
+ }
+ }
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "sampleFlagsWithParticles" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",1,&_lock); int discretization = _args.get<int >("discretization",2,&_lock); Real randomness = _args.get<Real >("randomness",3,&_lock); _retval = getPyNone(); sampleFlagsWithParticles(flags,parts,discretization,randomness); _args.check(); } pbFinalizePlugin(parent,"sampleFlagsWithParticles" ); return _retval; } catch(std::exception& e) { pbSetError("sampleFlagsWithParticles",e.what()); return 0; } } static const Pb::Register _RP_sampleFlagsWithParticles ("","sampleFlagsWithParticles",_W_0);
+
+
+
+void sampleLevelsetWithParticles( LevelsetGrid& phi, FlagGrid& flags, BasicParticleSystem& parts, int discretization, Real randomness ) {
+ bool is3D = phi.is3D();
+ Real jlen = randomness / discretization;
+ Vec3 disp (1.0 / discretization, 1.0 / discretization, 1.0/discretization);
+ RandomStream mRand(9832);
+
+ //clear();
+
+ FOR_IJK_BND(phi, 0) {
+ if ( flags.isObstacle(i,j,k) ) continue;
+ if ( phi(i,j,k) < 1.733 ) {
+ 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;
+ parts.add( BasicParticleData(subpos) );
+ }
+ }
+ }
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "sampleLevelsetWithParticles" ); PyObject *_retval = 0; { ArgLocker _lock; LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",0,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); int discretization = _args.get<int >("discretization",3,&_lock); Real randomness = _args.get<Real >("randomness",4,&_lock); _retval = getPyNone(); sampleLevelsetWithParticles(phi,flags,parts,discretization,randomness); _args.check(); } pbFinalizePlugin(parent,"sampleLevelsetWithParticles" ); return _retval; } catch(std::exception& e) { pbSetError("sampleLevelsetWithParticles",e.what()); return 0; } } static const Pb::Register _RP_sampleLevelsetWithParticles ("","sampleLevelsetWithParticles",_W_1);
+
+void markFluidCells(BasicParticleSystem& parts, FlagGrid& flags) {
+ // remove all fluid cells
+ FOR_IJK(flags) {
+ if (flags.isFluid(i,j,k)) {
+ flags(i,j,k) = (flags(i,j,k) | FlagGrid::TypeEmpty) & ~FlagGrid::TypeFluid;
+ }
+ }
+
+ // mark all particles in flaggrid as fluid
+ for(int idx=0;idx<parts.size();idx++) {
+ if (!parts.isActive(idx)) continue;
+ Vec3i p = toVec3i( parts.getPos(idx) );
+ if (flags.isInBounds(p) && flags.isEmpty(p))
+ flags(p) = (flags(p) | FlagGrid::TypeFluid) & ~FlagGrid::TypeEmpty;
+ }
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "markFluidCells" ); PyObject *_retval = 0; { ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",1,&_lock); _retval = getPyNone(); markFluidCells(parts,flags); _args.check(); } pbFinalizePlugin(parent,"markFluidCells" ); return _retval; } catch(std::exception& e) { pbSetError("markFluidCells",e.what()); return 0; } } static const Pb::Register _RP_markFluidCells ("","markFluidCells",_W_2);
+
+// for testing purposes only...
+void testInitGridWithPos(Grid<Real>& grid) {
+ FOR_IJK(grid) { grid(i,j,k) = norm( Vec3(i,j,k) ); }
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "testInitGridWithPos" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<Real>& grid = *_args.getPtr<Grid<Real> >("grid",0,&_lock); _retval = getPyNone(); testInitGridWithPos(grid); _args.check(); } pbFinalizePlugin(parent,"testInitGridWithPos" ); return _retval; } catch(std::exception& e) { pbSetError("testInitGridWithPos",e.what()); return 0; } } static const Pb::Register _RP_testInitGridWithPos ("","testInitGridWithPos",_W_3);
+
+
+//! helper to calculate particle radius factor to cover the diagonal of a cell in 2d/3d
+inline Real calculateRadiusFactor(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
+
+
+void adjustNumber( BasicParticleSystem& parts, MACGrid& vel, FlagGrid& flags, int minParticles, int maxParticles, LevelsetGrid& phi, Real radiusFactor=1. ) {
+ // 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 (int 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;
+ }
+ int num = tmp(p);
+
+ bool atSurface = false;
+ Real phiv = phi.getInterpolated( parts.getPos(idx) );
+ if (phiv > SURFACE_LS) atSurface = true;
+
+ // 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 (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_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "adjustNumber" ); PyObject *_retval = 0; { ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); int minParticles = _args.get<int >("minParticles",3,&_lock); int maxParticles = _args.get<int >("maxParticles",4,&_lock); LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",5,&_lock); Real radiusFactor = _args.getOpt<Real >("radiusFactor",6,1. ,&_lock); _retval = getPyNone(); adjustNumber(parts,vel,flags,minParticles,maxParticles,phi,radiusFactor); _args.check(); } pbFinalizePlugin(parent,"adjustNumber" ); return _retval; } catch(std::exception& e) { pbSetError("adjustNumber",e.what()); return 0; } } static const Pb::Register _RP_adjustNumber ("","adjustNumber",_W_4);
+
+// 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( 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_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "debugIntToReal" ); PyObject *_retval = 0; { ArgLocker _lock; 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" ); return _retval; } catch(std::exception& e) { pbSetError("debugIntToReal",e.what()); return 0; } } static const Pb::Register _RP_debugIntToReal ("","debugIntToReal",_W_5);
+
+// 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)] alreadu belongs to cell i+1,j,k)
+
+
+void gridParticleIndex( BasicParticleSystem& parts, ParticleIndexSystem& indexSys, 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 (int idx=0; idx<(int)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
+ int 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 (int idx=0; idx<(int)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_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "gridParticleIndex" ); PyObject *_retval = 0; { ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleIndexSystem& indexSys = *_args.getPtr<ParticleIndexSystem >("indexSys",1,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("gridParticleIndex",e.what()); return 0; } } static const Pb::Register _RP_gridParticleIndex ("","gridParticleIndex",_W_6);
+
+
+
+
+ struct ComputeUnionLevelsetPindex : public KernelBase { ComputeUnionLevelsetPindex(Grid<int>& index, BasicParticleSystem& parts, ParticleIndexSystem& indexSys, LevelsetGrid& phi, Real radius=1.) : KernelBase(&index,0) ,index(index),parts(parts),indexSys(indexSys),phi(phi),radius(radius) { run(); } inline void op(int i, int j, int k, Grid<int>& index, BasicParticleSystem& parts, ParticleIndexSystem& indexSys, LevelsetGrid& phi, Real radius=1. ) {
+ const Vec3 gridPos = Vec3(i,j,k) + Vec3(0.5); // shifted by half cell
+ Real phiv = radius * 1.732; // 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)
+ int isysIdxS = phi.index(xj,yj,zj);
+ int 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(int p=pStart; p<pEnd; ++p) {
+ const int psrc = indexSys[p].sourceIndex;
+ const Vec3 pos = parts[psrc].pos;
+ phiv = std::min( phiv , fabs( norm(gridPos-pos) )-radius );
+ }
+ }
+ phi(i,j,k) = phiv;
+} inline Grid<int>& getArg0() { return index; } typedef Grid<int> type0;inline BasicParticleSystem& getArg1() { return parts; } typedef BasicParticleSystem type1;inline ParticleIndexSystem& getArg2() { return indexSys; } typedef ParticleIndexSystem type2;inline LevelsetGrid& getArg3() { return phi; } typedef LevelsetGrid type3;inline Real& getArg4() { return radius; } typedef Real type4; 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, index,parts,indexSys,phi,radius); } Grid<int>& index; BasicParticleSystem& parts; ParticleIndexSystem& indexSys; LevelsetGrid& phi; Real radius; };
+
+
+
+void unionParticleLevelset( BasicParticleSystem& parts, ParticleIndexSystem& indexSys, FlagGrid& flags, Grid<int>& index, LevelsetGrid& phi, Real radiusFactor=1. ) {
+ // 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);
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "unionParticleLevelset" ); PyObject *_retval = 0; { ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleIndexSystem& indexSys = *_args.getPtr<ParticleIndexSystem >("indexSys",1,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); Grid<int>& index = *_args.getPtr<Grid<int> >("index",3,&_lock); LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",4,&_lock); Real radiusFactor = _args.getOpt<Real >("radiusFactor",5,1. ,&_lock); _retval = getPyNone(); unionParticleLevelset(parts,indexSys,flags,index,phi,radiusFactor); _args.check(); } pbFinalizePlugin(parent,"unionParticleLevelset" ); return _retval; } catch(std::exception& e) { pbSetError("unionParticleLevelset",e.what()); return 0; } } static const Pb::Register _RP_unionParticleLevelset ("","unionParticleLevelset",_W_7);
+
+
+
+
+
+
+ struct ComputeAveragedLevelsetWeight : public KernelBase { ComputeAveragedLevelsetWeight(BasicParticleSystem& parts, Grid<int>& index, ParticleIndexSystem& indexSys, LevelsetGrid& phi, Real radius=1.) : KernelBase(&index,0) ,parts(parts),index(index),indexSys(indexSys),phi(phi),radius(radius) { run(); } inline void op(int i, int j, int k, BasicParticleSystem& parts, Grid<int>& index, ParticleIndexSystem& indexSys, LevelsetGrid& phi, Real radius=1. ) {
+ const Vec3 gridPos = Vec3(i,j,k) + Vec3(0.5); // shifted by half cell
+ Real phiv = radius * 1.732; // 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;
+
+ int isysIdxS = phi.index(xj,yj,zj);
+ int pStart = index(isysIdxS), pEnd=0;
+ if(phi.isInBounds(isysIdxS+1)) pEnd = index(isysIdxS+1);
+ else pEnd = indexSys.size();
+ for(int p=pStart; p<pEnd; ++p) {
+ int psrc = indexSys[p].sourceIndex;
+ Vec3 pos = parts[psrc].pos;
+ Real s = normSquare(gridPos-pos) * sradiusInv;
+ Real w = std::max(0., cubed(1.-s) );
+ wacc += w;
+ racc += radius * w;
+ pacc += pos * w;
+ }
+ }
+
+ if(wacc > VECTOR_EPSILON) {
+ racc /= wacc;
+ pacc /= wacc;
+ phiv = fabs( norm(gridPos-pacc) )-racc;
+ }
+ phi(i,j,k) = phiv;
+} inline BasicParticleSystem& getArg0() { return parts; } typedef BasicParticleSystem type0;inline Grid<int>& getArg1() { return index; } typedef Grid<int> type1;inline ParticleIndexSystem& getArg2() { return indexSys; } typedef ParticleIndexSystem type2;inline LevelsetGrid& getArg3() { return phi; } typedef LevelsetGrid type3;inline Real& getArg4() { return radius; } typedef Real type4; 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, parts,index,indexSys,phi,radius); } BasicParticleSystem& parts; Grid<int>& index; ParticleIndexSystem& indexSys; LevelsetGrid& phi; Real radius; };
+
+// smoothing, and
+
+template <class T> struct knSmoothGrid : public KernelBase { knSmoothGrid(Grid<T>& me, Grid<T>& tmp, Real factor) : KernelBase(&me,1) ,me(me),tmp(tmp),factor(factor) { run(); } inline void op(int i, int j, int k, Grid<T>& me, Grid<T>& tmp, Real factor ) {
+ 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 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, me,tmp,factor); } Grid<T>& me; Grid<T>& tmp; Real factor; };
+
+
+template <class T> struct knSmoothGridNeg : public KernelBase { knSmoothGridNeg(Grid<T>& me, Grid<T>& tmp, Real factor) : KernelBase(&me,1) ,me(me),tmp(tmp),factor(factor) { run(); } inline void op(int i, int j, int k, Grid<T>& me, Grid<T>& tmp, Real factor ) {
+ 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 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, me,tmp,factor); } Grid<T>& me; Grid<T>& tmp; Real factor; };
+
+
+
+
+
+void averagedParticleLevelset( BasicParticleSystem& parts, ParticleIndexSystem& indexSys, FlagGrid& flags, Grid<int>& index, LevelsetGrid& phi, Real radiusFactor=1. , int smoothen=1 , int smoothenNeg=1 ) {
+ // use half a cell diagonal as base radius
+ const Real radius = 0.5 * calculateRadiusFactor(phi, radiusFactor);
+ ComputeAveragedLevelsetWeight(parts, index, indexSys, phi, radius);
+
+ // post-process level-set
+ for(int i=0; i<smoothen; ++i) {
+ LevelsetGrid tmp(flags.getParent());
+ knSmoothGrid<Real>(phi,tmp, 1./(phi.is3D() ? 7. : 5.) );
+ phi.swap(tmp);
+ }
+ for(int i=0; i<smoothenNeg; ++i) {
+ LevelsetGrid tmp(flags.getParent());
+ knSmoothGridNeg<Real>(phi,tmp, 1./(phi.is3D() ? 7. : 5.) );
+ phi.swap(tmp);
+ }
+ // NT_DEBUG , todo copy border
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "averagedParticleLevelset" ); PyObject *_retval = 0; { ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleIndexSystem& indexSys = *_args.getPtr<ParticleIndexSystem >("indexSys",1,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); Grid<int>& index = *_args.getPtr<Grid<int> >("index",3,&_lock); LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",4,&_lock); Real radiusFactor = _args.getOpt<Real >("radiusFactor",5,1. ,&_lock); int smoothen = _args.getOpt<int >("smoothen",6,1 ,&_lock); int smoothenNeg = _args.getOpt<int >("smoothenNeg",7,1 ,&_lock); _retval = getPyNone(); averagedParticleLevelset(parts,indexSys,flags,index,phi,radiusFactor,smoothen,smoothenNeg); _args.check(); } pbFinalizePlugin(parent,"averagedParticleLevelset" ); return _retval; } catch(std::exception& e) { pbSetError("averagedParticleLevelset",e.what()); return 0; } } static const Pb::Register _RP_averagedParticleLevelset ("","averagedParticleLevelset",_W_8);
+
+
+
+
+//******************************************************************************
+// 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) { run(); } inline void op(int idx, Grid<T>& me, const Grid<Real>& other, Real cutoff=VECTOR_EPSILON ) {
+ 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, me,other,cutoff); } Grid<T>& me; const Grid<Real>& other; Real cutoff; };
+
+// Set velocities on the grid from the particle system
+
+
+ struct knStompVec3PerComponent : public KernelBase { knStompVec3PerComponent(Grid<Vec3>& grid, Real threshold) : KernelBase(&grid,0) ,grid(grid),threshold(threshold) { run(); } inline void op(int idx, Grid<Vec3>& grid, Real threshold ) {
+ if(grid[idx][0] < threshold) grid[idx][0] = 0.;
+ if(grid[idx][1] < threshold) grid[idx][1] = 0.;
+ if(grid[idx][2] < threshold) grid[idx][2] = 0.;
+} inline Grid<Vec3>& getArg0() { return grid; } typedef Grid<Vec3> type0;inline Real& getArg1() { return threshold; } typedef Real type1; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, grid,threshold); } Grid<Vec3>& grid; Real threshold; };
+
+
+
+
+ struct knMapLinearVec3ToMACGrid : public KernelBase { knMapLinearVec3ToMACGrid( BasicParticleSystem& p, FlagGrid& flags, MACGrid& vel, Grid<Vec3>& tmp, ParticleDataImpl<Vec3>& pvel ) : KernelBase(p.size()) ,p(p),flags(flags),vel(vel),tmp(tmp),pvel(pvel) { run(); } inline void op(int idx, BasicParticleSystem& p, FlagGrid& flags, MACGrid& vel, Grid<Vec3>& tmp, ParticleDataImpl<Vec3>& pvel ) {
+ unusedParameter(flags);
+ if (!p.isActive(idx)) return;
+ vel.setInterpolated( p[idx].pos, pvel[idx], &tmp[0] );
+} inline BasicParticleSystem& getArg0() { return p; } typedef BasicParticleSystem type0;inline FlagGrid& getArg1() { return flags; } typedef FlagGrid type1;inline MACGrid& getArg2() { return vel; } typedef MACGrid type2;inline Grid<Vec3>& getArg3() { return tmp; } typedef Grid<Vec3> type3;inline ParticleDataImpl<Vec3>& getArg4() { return pvel; } typedef ParticleDataImpl<Vec3> type4; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, p,flags,vel,tmp,pvel); } BasicParticleSystem& p; FlagGrid& flags; MACGrid& vel; Grid<Vec3>& tmp; ParticleDataImpl<Vec3>& pvel; };
+
+// 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( FlagGrid& flags, MACGrid& vel , MACGrid& velOld , BasicParticleSystem& parts , ParticleDataImpl<Vec3>& partVel , Grid<Vec3>* weight=NULL ) {
+ // 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 );
+
+ // stomp small values in weight to zero to prevent roundoff errors
+ knStompVec3PerComponent( *weight, VECTOR_EPSILON );
+ vel.safeDivide(*weight);
+
+ // store original state
+ velOld.copyFrom( vel );
+ if(freeTmp) delete weight;
+} static PyObject* _W_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "mapPartsToMAC" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); MACGrid& velOld = *_args.getPtr<MACGrid >("velOld",2,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",3,&_lock); ParticleDataImpl<Vec3>& partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",4,&_lock); Grid<Vec3>* weight = _args.getPtrOpt<Grid<Vec3> >("weight",5,NULL ,&_lock); _retval = getPyNone(); mapPartsToMAC(flags,vel,velOld,parts,partVel,weight); _args.check(); } pbFinalizePlugin(parent,"mapPartsToMAC" ); return _retval; } catch(std::exception& e) { pbSetError("mapPartsToMAC",e.what()); return 0; } } static const Pb::Register _RP_mapPartsToMAC ("","mapPartsToMAC",_W_9);
+
+
+
+
+
+template <class T> struct knMapLinear : public KernelBase { knMapLinear( BasicParticleSystem& p, FlagGrid& flags, Grid<T>& target, Grid<Real>& gtmp, ParticleDataImpl<T>& psource ) : KernelBase(p.size()) ,p(p),flags(flags),target(target),gtmp(gtmp),psource(psource) { run(); } inline void op(int idx, BasicParticleSystem& p, FlagGrid& flags, Grid<T>& target, Grid<Real>& gtmp, ParticleDataImpl<T>& psource ) {
+ unusedParameter(flags);
+ if (!p.isActive(idx)) return;
+ target.setInterpolated( p[idx].pos, psource[idx], gtmp );
+} inline BasicParticleSystem& getArg0() { return p; } typedef BasicParticleSystem type0;inline FlagGrid& getArg1() { return flags; } typedef FlagGrid type1;inline Grid<T>& getArg2() { return target; } typedef Grid<T> type2;inline Grid<Real>& getArg3() { return gtmp; } typedef Grid<Real> type3;inline ParticleDataImpl<T>& getArg4() { return psource; } typedef ParticleDataImpl<T> type4; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, p,flags,target,gtmp,psource); } BasicParticleSystem& p; FlagGrid& flags; Grid<T>& target; Grid<Real>& gtmp; ParticleDataImpl<T>& psource; };
+template<class T>
+void mapLinearRealHelper( FlagGrid& flags, Grid<T>& target ,
+ BasicParticleSystem& parts , ParticleDataImpl<T>& source )
+{
+ Grid<Real> tmp(flags.getParent());
+ target.clear();
+ knMapLinear<T>( parts, flags, target, tmp, source );
+ knSafeDivReal<T>( target, tmp );
+}
+
+void mapPartsToGrid( FlagGrid& flags, Grid<Real>& target , BasicParticleSystem& parts , ParticleDataImpl<Real>& source ) {
+ mapLinearRealHelper<Real>(flags,target,parts,source);
+} static PyObject* _W_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "mapPartsToGrid" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",1,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); ParticleDataImpl<Real>& source = *_args.getPtr<ParticleDataImpl<Real> >("source",3,&_lock); _retval = getPyNone(); mapPartsToGrid(flags,target,parts,source); _args.check(); } pbFinalizePlugin(parent,"mapPartsToGrid" ); return _retval; } catch(std::exception& e) { pbSetError("mapPartsToGrid",e.what()); return 0; } } static const Pb::Register _RP_mapPartsToGrid ("","mapPartsToGrid",_W_10);
+void mapPartsToGridVec3( FlagGrid& flags, Grid<Vec3>& target , BasicParticleSystem& parts , ParticleDataImpl<Vec3>& source ) {
+ mapLinearRealHelper<Vec3>(flags,target,parts,source);
+} static PyObject* _W_11 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "mapPartsToGridVec3" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); ParticleDataImpl<Vec3>& source = *_args.getPtr<ParticleDataImpl<Vec3> >("source",3,&_lock); _retval = getPyNone(); mapPartsToGridVec3(flags,target,parts,source); _args.check(); } pbFinalizePlugin(parent,"mapPartsToGridVec3" ); return _retval; } catch(std::exception& e) { pbSetError("mapPartsToGridVec3",e.what()); return 0; } } static const Pb::Register _RP_mapPartsToGridVec3 ("","mapPartsToGridVec3",_W_11);
+// 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( BasicParticleSystem& p, Grid<T>& gsrc, ParticleDataImpl<T>& target ) : KernelBase(p.size()) ,p(p),gsrc(gsrc),target(target) { run(); } inline void op(int idx, BasicParticleSystem& p, Grid<T>& gsrc, ParticleDataImpl<T>& target ) {
+ if (!p.isActive(idx)) return;
+ target[idx] = gsrc.getInterpolated( p[idx].pos );
+} inline BasicParticleSystem& getArg0() { return p; } typedef BasicParticleSystem type0;inline Grid<T>& getArg1() { return gsrc; } typedef Grid<T> type1;inline ParticleDataImpl<T>& getArg2() { return target; } typedef ParticleDataImpl<T> type2; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, p,gsrc,target); } BasicParticleSystem& p; Grid<T>& gsrc; ParticleDataImpl<T>& target; };
+void mapGridToParts( Grid<Real>& source , BasicParticleSystem& parts , ParticleDataImpl<Real>& target ) {
+ knMapFromGrid<Real>(parts, source, target);
+} static PyObject* _W_12 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "mapGridToParts" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<Real>& source = *_args.getPtr<Grid<Real> >("source",0,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("mapGridToParts",e.what()); return 0; } } static const Pb::Register _RP_mapGridToParts ("","mapGridToParts",_W_12);
+void mapGridToPartsVec3( Grid<Vec3>& source , BasicParticleSystem& parts , ParticleDataImpl<Vec3>& target ) {
+ knMapFromGrid<Vec3>(parts, source, target);
+} static PyObject* _W_13 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "mapGridToPartsVec3" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<Vec3>& source = *_args.getPtr<Grid<Vec3> >("source",0,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("mapGridToPartsVec3",e.what()); return 0; } } static const Pb::Register _RP_mapGridToPartsVec3 ("","mapGridToPartsVec3",_W_13);
+
+
+// Get velocities from grid
+
+
+
+ struct knMapLinearMACGridToVec3_PIC : public KernelBase { knMapLinearMACGridToVec3_PIC( BasicParticleSystem& p, FlagGrid& flags, MACGrid& vel, ParticleDataImpl<Vec3>& pvel ) : KernelBase(p.size()) ,p(p),flags(flags),vel(vel),pvel(pvel) { run(); } inline void op(int idx, BasicParticleSystem& p, FlagGrid& flags, MACGrid& vel, ParticleDataImpl<Vec3>& pvel ) {
+ if (!p.isActive(idx)) return;
+ // pure PIC
+ pvel[idx] = vel.getInterpolated( p[idx].pos );
+} inline BasicParticleSystem& getArg0() { return p; } typedef BasicParticleSystem type0;inline FlagGrid& getArg1() { return flags; } typedef FlagGrid type1;inline MACGrid& getArg2() { return vel; } typedef MACGrid type2;inline ParticleDataImpl<Vec3>& getArg3() { return pvel; } typedef ParticleDataImpl<Vec3> type3; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, p,flags,vel,pvel); } BasicParticleSystem& p; FlagGrid& flags; MACGrid& vel; ParticleDataImpl<Vec3>& pvel; };
+
+void mapMACToParts(FlagGrid& flags, MACGrid& vel , BasicParticleSystem& parts , ParticleDataImpl<Vec3>& partVel ) {
+ knMapLinearMACGridToVec3_PIC( parts, flags, vel, partVel );
+} static PyObject* _W_14 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "mapMACToParts" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",2,&_lock); ParticleDataImpl<Vec3>& partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",3,&_lock); _retval = getPyNone(); mapMACToParts(flags,vel,parts,partVel); _args.check(); } pbFinalizePlugin(parent,"mapMACToParts" ); return _retval; } catch(std::exception& e) { pbSetError("mapMACToParts",e.what()); return 0; } } static const Pb::Register _RP_mapMACToParts ("","mapMACToParts",_W_14);
+
+// with flip delta interpolation
+
+
+ struct knMapLinearMACGridToVec3_FLIP : public KernelBase { knMapLinearMACGridToVec3_FLIP( BasicParticleSystem& p, FlagGrid& flags, MACGrid& vel, MACGrid& oldVel, ParticleDataImpl<Vec3>& pvel , Real flipRatio) : KernelBase(p.size()) ,p(p),flags(flags),vel(vel),oldVel(oldVel),pvel(pvel),flipRatio(flipRatio) { run(); } inline void op(int idx, BasicParticleSystem& p, FlagGrid& flags, MACGrid& vel, MACGrid& oldVel, ParticleDataImpl<Vec3>& pvel , Real flipRatio ) {
+ if (!p.isActive(idx)) 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 BasicParticleSystem& getArg0() { return p; } typedef BasicParticleSystem type0;inline FlagGrid& getArg1() { return flags; } typedef FlagGrid type1;inline MACGrid& getArg2() { return vel; } typedef MACGrid type2;inline MACGrid& getArg3() { return oldVel; } typedef MACGrid type3;inline ParticleDataImpl<Vec3>& getArg4() { return pvel; } typedef ParticleDataImpl<Vec3> type4;inline Real& getArg5() { return flipRatio; } typedef Real type5; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, p,flags,vel,oldVel,pvel,flipRatio); } BasicParticleSystem& p; FlagGrid& flags; MACGrid& vel; MACGrid& oldVel; ParticleDataImpl<Vec3>& pvel; Real flipRatio; };
+
+
+void flipVelocityUpdate(FlagGrid& flags, MACGrid& vel , MACGrid& velOld , BasicParticleSystem& parts , ParticleDataImpl<Vec3>& partVel , Real flipRatio ) {
+ knMapLinearMACGridToVec3_FLIP( parts, flags, vel, velOld, partVel, flipRatio );
+} static PyObject* _W_15 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "flipVelocityUpdate" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); MACGrid& velOld = *_args.getPtr<MACGrid >("velOld",2,&_lock); BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",3,&_lock); ParticleDataImpl<Vec3>& partVel = *_args.getPtr<ParticleDataImpl<Vec3> >("partVel",4,&_lock); Real flipRatio = _args.get<Real >("flipRatio",5,&_lock); _retval = getPyNone(); flipVelocityUpdate(flags,vel,velOld,parts,partVel,flipRatio); _args.check(); } pbFinalizePlugin(parent,"flipVelocityUpdate" ); return _retval; } catch(std::exception& e) { pbSetError("flipVelocityUpdate",e.what()); return 0; } } static const Pb::Register _RP_flipVelocityUpdate ("","flipVelocityUpdate",_W_15);
+
+
+} // namespace
+
+
+
diff --git a/source/blender/python/manta_pp/plugin/initplugins.cpp b/source/blender/python/manta_pp/plugin/initplugins.cpp
new file mode 100644
index 00000000000..6d2c0d2f160
--- /dev/null
+++ b/source/blender/python/manta_pp/plugin/initplugins.cpp
@@ -0,0 +1,201 @@
+
+
+
+
+
+// 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
+ *
+ * Tools to setup fields and inflows
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include "shapes.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include "noisefield.h"
+#include "mesh.h"
+
+using namespace std;
+
+namespace Manta {
+
+//! Apply noise to grid
+
+
+ struct KnApplyNoise : public KernelBase { KnApplyNoise(FlagGrid& flags, Grid<Real>& density, WaveletNoiseField& noise, Grid<Real>& sdf, Real scale, Real sigma) : KernelBase(&flags,0) ,flags(flags),density(density),noise(noise),sdf(sdf),scale(scale),sigma(sigma) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<Real>& density, WaveletNoiseField& noise, Grid<Real>& sdf, Real scale, Real sigma ) {
+ 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 FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Real>& getArg1() { return density; } typedef Grid<Real> type1;inline WaveletNoiseField& getArg2() { return noise; } typedef WaveletNoiseField type2;inline 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 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,density,noise,sdf,scale,sigma); } FlagGrid& flags; Grid<Real>& density; WaveletNoiseField& noise; Grid<Real>& sdf; Real scale; Real sigma; };
+
+
+
+ struct KnApplyDensity : public KernelBase { KnApplyDensity(FlagGrid& flags, Grid<Real>& density, Grid<Real>& sdf, Real value, Real sigma) : KernelBase(&flags,0) ,flags(flags),density(density),sdf(sdf),value(value),sigma(sigma) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<Real>& density, Grid<Real>& sdf, Real value, Real sigma ) {
+ if (!flags.isFluid(i,j,k) || sdf(i,j,k) > sigma) return;
+ density(i,j,k) = value;
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Real>& getArg1() { return density; } typedef Grid<Real> type1;inline 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 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,density,sdf,value,sigma); } FlagGrid& flags; Grid<Real>& density; Grid<Real>& sdf; Real value; Real sigma; };
+
+
+
+ struct KnApplyEmission : public KernelBase { KnApplyEmission(FlagGrid& flags, Grid<Real>& density, Grid<Real>& emission, bool isAbsolute) : KernelBase(&flags,0) ,flags(flags),density(density),emission(emission),isAbsolute(isAbsolute) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<Real>& density, Grid<Real>& emission, bool isAbsolute ) {
+ if (!flags.isFluid(i,j,k) || emission(i,j,k) == 0.) return;
+ if (isAbsolute)
+ density(i,j,k) = emission(i,j,k);
+ else
+ density(i,j,k) += emission(i,j,k);
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Real>& getArg1() { return density; } typedef Grid<Real> type1;inline Grid<Real>& getArg2() { return emission; } typedef Grid<Real> type2;inline bool& getArg3() { return isAbsolute; } typedef bool type3; 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,density,emission,isAbsolute); } FlagGrid& flags; Grid<Real>& density; Grid<Real>& emission; bool isAbsolute; };
+
+//! Init noise-modulated density inside shape
+
+void densityInflow(FlagGrid& flags, Grid<Real>& density, WaveletNoiseField& noise, Shape* shape, Real scale=1.0, Real sigma=0) {
+ Grid<Real> sdf = shape->computeLevelset();
+ KnApplyNoise(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(); pbPreparePlugin(parent, "densityInflow" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("densityInflow",e.what()); return 0; } } static const Pb::Register _RP_densityInflow ("","densityInflow",_W_0);
+
+
+//! Init noise-modulated density inside mesh
+
+void densityInflowMeshNoise(FlagGrid& flags, Grid<Real>& density, WaveletNoiseField& noise, Mesh* mesh, Real scale=1.0, Real sigma=0) {
+ FluidSolver dummy(density.getSize());
+ LevelsetGrid sdf(&dummy, false);
+ mesh->meshSDF(*mesh, sdf, 1.);
+ KnApplyNoise(flags, density, noise, sdf, scale, sigma);
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "densityInflowMeshNoise" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("densityInflowMeshNoise",e.what()); return 0; } } static const Pb::Register _RP_densityInflowMeshNoise ("","densityInflowMeshNoise",_W_1);
+//! Init still density inside mesh
+
+void densityInflowMesh(FlagGrid& flags, Grid<Real>& density, Mesh* mesh, Real value=1., Real cutoff = 7, Real sigma=0) {
+ FluidSolver dummy(density.getSize());
+ LevelsetGrid sdf(&dummy, false);
+ mesh->meshSDF(*mesh, sdf, 2.,cutoff);
+ KnApplyDensity(flags, density, sdf, value, sigma);
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "densityInflowMesh" ); PyObject *_retval = 0; { ArgLocker _lock; 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" ); return _retval; } catch(std::exception& e) { pbSetError("densityInflowMesh",e.what()); return 0; } } static const Pb::Register _RP_densityInflowMesh ("","densityInflowMesh",_W_2);
+//! Add emission values
+//isAbsolute: whether to add emission values to existing, or replace
+
+void applyEmission(FlagGrid& flags, Grid<Real>& density, Grid<Real>& emission, bool isAbsolute) {
+ FluidSolver dummy(density.getSize());
+ KnApplyEmission(flags, density, emission, isAbsolute);
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "applyEmission" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& density = *_args.getPtr<Grid<Real> >("density",1,&_lock); Grid<Real>& emission = *_args.getPtr<Grid<Real> >("emission",2,&_lock); bool isAbsolute = _args.get<bool >("isAbsolute",3,&_lock); _retval = getPyNone(); applyEmission(flags,density,emission,isAbsolute); _args.check(); } pbFinalizePlugin(parent,"applyEmission" ); return _retval; } catch(std::exception& e) { pbSetError("applyEmission",e.what()); return 0; } } static const Pb::Register _RP_applyEmission ("","applyEmission",_W_3);
+//! sample noise field and set pdata with its values (for convenience, scale the noise values)
+
+template <class T> struct knSetPdataNoise : public KernelBase { knSetPdataNoise(BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, WaveletNoiseField& noise, Real scale) : KernelBase(parts.size()) ,parts(parts),pdata(pdata),noise(noise),scale(scale) { run(); } inline void op(int idx, BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, WaveletNoiseField& noise, Real scale ) {
+ pdata[idx] = noise.evaluate( parts.getPos(idx) ) * scale;
+} inline BasicParticleSystem& getArg0() { return parts; } typedef BasicParticleSystem type0;inline ParticleDataImpl<T>& getArg1() { return pdata; } typedef ParticleDataImpl<T> type1;inline WaveletNoiseField& getArg2() { return noise; } typedef WaveletNoiseField type2;inline Real& getArg3() { return scale; } typedef Real type3; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, parts,pdata,noise,scale); } BasicParticleSystem& parts; ParticleDataImpl<T>& pdata; WaveletNoiseField& noise; Real scale; };
+
+template <class T> struct knSetPdataNoiseVec : public KernelBase { knSetPdataNoiseVec(BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, WaveletNoiseField& noise, Real scale) : KernelBase(parts.size()) ,parts(parts),pdata(pdata),noise(noise),scale(scale) { run(); } inline void op(int idx, BasicParticleSystem& parts, ParticleDataImpl<T>& pdata, WaveletNoiseField& noise, Real scale ) {
+ pdata[idx] = noise.evaluateVec( parts.getPos(idx) ) * scale;
+} inline BasicParticleSystem& getArg0() { return parts; } typedef BasicParticleSystem type0;inline ParticleDataImpl<T>& getArg1() { return pdata; } typedef ParticleDataImpl<T> type1;inline WaveletNoiseField& getArg2() { return noise; } typedef WaveletNoiseField type2;inline Real& getArg3() { return scale; } typedef Real type3; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, parts,pdata,noise,scale); } BasicParticleSystem& parts; ParticleDataImpl<T>& pdata; WaveletNoiseField& noise; Real scale; };
+void setNoisePdata(BasicParticleSystem& parts, ParticleDataImpl<Real>& pd, WaveletNoiseField& noise, Real scale=1.) { knSetPdataNoise<Real>(parts, pd,noise,scale); } static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "setNoisePdata" ); PyObject *_retval = 0; { ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<Real>& pd = *_args.getPtr<ParticleDataImpl<Real> >("pd",1,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("setNoisePdata",e.what()); return 0; } } static const Pb::Register _RP_setNoisePdata ("","setNoisePdata",_W_4);
+void setNoisePdataVec3(BasicParticleSystem& parts, ParticleDataImpl<Vec3>& pd, WaveletNoiseField& noise, Real scale=1.) { knSetPdataNoiseVec<Vec3>(parts, pd,noise,scale); } static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "setNoisePdataVec3" ); PyObject *_retval = 0; { ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<Vec3>& pd = *_args.getPtr<ParticleDataImpl<Vec3> >("pd",1,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("setNoisePdataVec3",e.what()); return 0; } } static const Pb::Register _RP_setNoisePdataVec3 ("","setNoisePdataVec3",_W_5);
+void setNoisePdataInt(BasicParticleSystem& parts, ParticleDataImpl<int >& pd, WaveletNoiseField& noise, Real scale=1.) { knSetPdataNoise<int> (parts, pd,noise,scale); } static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "setNoisePdataInt" ); PyObject *_retval = 0; { ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); ParticleDataImpl<int >& pd = *_args.getPtr<ParticleDataImpl<int > >("pd",1,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("setNoisePdataInt",e.what()); return 0; } } static const Pb::Register _RP_setNoisePdataInt ("","setNoisePdataInt",_W_6);
+
+//! SDF gradient from obstacle flags
+Grid<Vec3> obstacleGradient(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_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "obstacleGradient" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); _retval = toPy(obstacleGradient(flags)); _args.check(); } pbFinalizePlugin(parent,"obstacleGradient" ); return _retval; } catch(std::exception& e) { pbSetError("obstacleGradient",e.what()); return 0; } } static const Pb::Register _RP_obstacleGradient ("","obstacleGradient",_W_7);
+
+LevelsetGrid obstacleLevelset(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);
+
+ return levelset;
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "obstacleLevelset" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); _retval = toPy(obstacleLevelset(flags)); _args.check(); } pbFinalizePlugin(parent,"obstacleLevelset" ); return _retval; } catch(std::exception& e) { pbSetError("obstacleLevelset",e.what()); return 0; } } static const Pb::Register _RP_obstacleLevelset ("","obstacleLevelset",_W_8);
+
+// 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_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "addTestParts" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("addTestParts",e.what()); return 0; } } static const Pb::Register _RP_addTestParts ("","addTestParts",_W_9);
+
+// calculate the difference between two pdata fields (note - slow!, not parallelized)
+
+Real pdataMaxDiff( ParticleDataBase* a, 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)
+ {
+ ParticleDataImpl<Real>& av = *dynamic_cast<ParticleDataImpl<Real>*>(a);
+ ParticleDataImpl<Real>& bv = *dynamic_cast<ParticleDataImpl<Real>*>(b);
+ FOR_PARTS(av) {
+ maxVal = std::max(maxVal, (double)fabs( av[idx]-bv[idx] ));
+ }
+ } else if (a->getType() & ParticleDataBase::TypeInt)
+ {
+ ParticleDataImpl<int>& av = *dynamic_cast<ParticleDataImpl<int>*>(a);
+ ParticleDataImpl<int>& bv = *dynamic_cast<ParticleDataImpl<int>*>(b);
+ FOR_PARTS(av) {
+ maxVal = std::max(maxVal, (double)fabs( (double)av[idx]-bv[idx] ));
+ }
+ } else if (a->getType() & ParticleDataBase::TypeVec3) {
+ ParticleDataImpl<Vec3>& av = *dynamic_cast<ParticleDataImpl<Vec3>*>(a);
+ ParticleDataImpl<Vec3>& bv = *dynamic_cast<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_10 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "pdataMaxDiff" ); PyObject *_retval = 0; { ArgLocker _lock; ParticleDataBase* a = _args.getPtr<ParticleDataBase >("a",0,&_lock); ParticleDataBase* b = _args.getPtr<ParticleDataBase >("b",1,&_lock); _retval = toPy(pdataMaxDiff(a,b)); _args.check(); } pbFinalizePlugin(parent,"pdataMaxDiff" ); return _retval; } catch(std::exception& e) { pbSetError("pdataMaxDiff",e.what()); return 0; } } static const Pb::Register _RP_pdataMaxDiff ("","pdataMaxDiff",_W_10);
+
+} // namespace
+
+
+
diff --git a/source/blender/python/manta_pp/plugin/kepsilon.cpp b/source/blender/python/manta_pp/plugin/kepsilon.cpp
new file mode 100644
index 00000000000..bbec1a9d2fb
--- /dev/null
+++ b/source/blender/python/manta_pp/plugin/kepsilon.cpp
@@ -0,0 +1,195 @@
+
+
+
+
+
+// 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
+ *
+ * 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) { run(); } inline void op(int idx, Grid<Real>& kgrid, Grid<Real>& egrid, Real minK, Real maxK, Real minNu, Real maxNu ) {
+ 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, kgrid,egrid,minK,maxK,minNu,maxNu); } 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) { 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 ) {
+ 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; 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); } 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(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(); pbPreparePlugin(parent, "KEpsilonComputeProduction" ); PyObject *_retval = 0; { ArgLocker _lock; 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" ); return _retval; } catch(std::exception& e) { pbSetError("KEpsilonComputeProduction",e.what()); return 0; } } static const Pb::Register _RP_KEpsilonComputeProduction ("","KEpsilonComputeProduction",_W_0);
+
+//! 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) { run(); } inline void op(int idx, Grid<Real>& kgrid, Grid<Real>& egrid, const Grid<Real>& pgrid, Real dt ) {
+ 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, kgrid,egrid,pgrid,dt); } 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(); pbPreparePlugin(parent, "KEpsilonSources" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("KEpsilonSources",e.what()); return 0; } } static const Pb::Register _RP_KEpsilonSources ("","KEpsilonSources",_W_1);
+
+//! Initialize the domain or boundary conditions
+void KEpsilonBcs(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(); pbPreparePlugin(parent, "KEpsilonBcs" ); PyObject *_retval = 0; { ArgLocker _lock; 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" ); return _retval; } catch(std::exception& e) { pbSetError("KEpsilonBcs",e.what()); return 0; } } static const Pb::Register _RP_KEpsilonBcs ("","KEpsilonBcs",_W_2);
+
+//! 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(); pbPreparePlugin(parent, "KEpsilonGradientDiffusion" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("KEpsilonGradientDiffusion",e.what()); return 0; } } static const Pb::Register _RP_KEpsilonGradientDiffusion ("","KEpsilonGradientDiffusion",_W_3);
+
+
+
+} // namespace
+
diff --git a/source/blender/python/manta_pp/plugin/meshplugins.cpp b/source/blender/python/manta_pp/plugin/meshplugins.cpp
new file mode 100644
index 00000000000..ec6e554553e
--- /dev/null
+++ b/source/blender/python/manta_pp/plugin/meshplugins.cpp
@@ -0,0 +1,636 @@
+
+
+
+
+
+// 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
+ *
+ * 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);
+ 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/len);
+ totalLen += len;
+ } else {
+ totalLen = _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)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(); pbPreparePlugin(parent, "smoothMesh" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("smoothMesh",e.what()); return 0; } } static const Pb::Register _RP_smoothMesh ("","smoothMesh",_W_0);
+
+//! 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(); pbPreparePlugin(parent, "subdivideMesh" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("subdivideMesh",e.what()); return 0; } } static const Pb::Register _RP_subdivideMesh ("","subdivideMesh",_W_1);
+
+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(); pbPreparePlugin(parent, "killSmallComponents" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("killSmallComponents",e.what()); return 0; } } static const Pb::Register _RP_killSmallComponents ("","killSmallComponents",_W_2);
+
+
+} //namespace
+
+
+
diff --git a/source/blender/python/manta_pp/plugin/pressure.cpp b/source/blender/python/manta_pp/plugin/pressure.cpp
new file mode 100644
index 00000000000..3fa6f2da1c8
--- /dev/null
+++ b/source/blender/python/manta_pp/plugin/pressure.cpp
@@ -0,0 +1,327 @@
+
+
+
+
+
+// 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
+ *
+ * Plugins for pressure correction: solve_pressure, and ghost fluid helpers
+ *
+ ******************************************************************************/
+#include "vectorbase.h"
+#include "kernel.h"
+#include "conjugategrad.h"
+
+using namespace std;
+namespace Manta {
+
+//! Kernel: Construct the right-hand side of the poisson equation
+
+
+
+ struct MakeRhs : public KernelBase { MakeRhs(FlagGrid& flags, Grid<Real>& rhs, MACGrid& vel, Grid<Real>* perCellCorr) : KernelBase(&flags,1) ,flags(flags),rhs(rhs),vel(vel),perCellCorr(perCellCorr) ,cnt(0),sum(0) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<Real>& rhs, MACGrid& vel, Grid<Real>* perCellCorr ,int& cnt,double& sum) {
+ if (!flags.isFluid(i,j,k)) {
+ rhs(i,j,k) = 0;
+ return;
+ }
+
+ // compute divergence
+ // no flag checks: assumes vel at obstacle interfaces is set to zero
+ Real 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;
+
+ // per cell divergence correction
+ if(perCellCorr)
+ set += perCellCorr->get(i,j,k);
+
+ // obtain sum, cell count
+ sum += set;
+ cnt++;
+
+ rhs(i,j,k) = set;
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Real>& getArg1() { return rhs; } typedef Grid<Real> type1;inline MACGrid& getArg2() { return vel; } typedef MACGrid type2;inline Grid<Real>* getArg3() { return perCellCorr; } typedef Grid<Real> type3; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, flags,rhs,vel,perCellCorr,cnt,sum); } FlagGrid& flags; Grid<Real>& rhs; MACGrid& vel; Grid<Real>* perCellCorr; int cnt; double sum; };
+
+//! Kernel: Apply velocity update from poisson equation
+
+
+ struct CorrectVelocity : public KernelBase { CorrectVelocity(FlagGrid& flags, MACGrid& vel, Grid<Real>& pressure) : KernelBase(&flags,1) ,flags(flags),vel(vel),pressure(pressure) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, Grid<Real>& pressure ) {
+ int 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))
+ {
+ 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 FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline MACGrid& getArg1() { return vel; } typedef MACGrid type1;inline Grid<Real>& getArg2() { return pressure; } typedef Grid<Real> type2; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, flags,vel,pressure); } FlagGrid& flags; MACGrid& vel; Grid<Real>& pressure; };
+
+
+
+
+
+ struct SetOpenBound : public KernelBase { SetOpenBound(Grid<Real> &A0,Grid<Real> &Ai,Grid<Real> &Aj,Grid<Real> &Ak,FlagGrid& flags,MACGrid& vel, Vector3D<bool> lo, Vector3D<bool> up) : KernelBase(&A0,0) ,A0(A0),Ai(Ai),Aj(Aj),Ak(Ak),flags(flags),vel(vel),lo(lo),up(up) { run(); } inline void op(int i, int j, int k, Grid<Real> &A0,Grid<Real> &Ai,Grid<Real> &Aj,Grid<Real> &Ak,FlagGrid& flags,MACGrid& vel, Vector3D<bool> lo, Vector3D<bool> up ) {
+
+ if (!flags.isFluid(i,j,k))
+ return;
+
+ int b = flags.getBoundaryWidth();
+
+ // set matrix stencil in and at boundary to empty
+ if((lo.x && i <= b+1)||(up.x && i >= maxX-b-2)||(lo.y && j <= b+1)||(up.y && j >= maxY-b-2))
+ A0(i,j,k) = (flags.is3D()) ? 6. : 4.;
+
+ if ((lo.x && i <= b)||(up.x && i >= maxX-b-2)) Ai(i,j,k) = .0;
+ if ((lo.y && j <= b)||(up.y && j >= maxY-b-2)) Aj(i,j,k) = .0;
+ if (flags.is3D() && ((lo.z && k <= b)||(up.z && k >= maxZ-b-2))) Ak(i,j,k) = .0;
+
+ // set velocity boundary conditions
+ if (lo.x && i == b) vel(b,j,k) = vel(b+1,j,k);
+ if (lo.y && j == b) vel(i,b,k) = vel(i,b+1,k);
+ if (up.x && i == maxX-b-1) vel(maxX-b-1,j,k) = vel(maxX-b-2,j,k);
+ if (up.y && j == maxY-b-1) vel(i,maxY-b-1,k) = vel(i,maxY-b-2,k);
+ if(flags.is3D()) {
+ if (lo.z && k == b) vel(i,j,b) = vel(i,j,b+1);
+ if (up.z && k == maxZ-b-1) vel(i,j,maxZ-b-1) = vel(i,j,maxZ-b-2);
+ }
+} inline Grid<Real> & getArg0() { return A0; } typedef Grid<Real> type0;inline Grid<Real> & getArg1() { return Ai; } typedef Grid<Real> type1;inline Grid<Real> & getArg2() { return Aj; } typedef Grid<Real> type2;inline Grid<Real> & getArg3() { return Ak; } typedef Grid<Real> type3;inline FlagGrid& getArg4() { return flags; } typedef FlagGrid type4;inline MACGrid& getArg5() { return vel; } typedef MACGrid type5;inline Vector3D<bool> & getArg6() { return lo; } typedef Vector3D<bool> type6;inline Vector3D<bool> & getArg7() { return up; } typedef Vector3D<bool> type7; 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, A0,Ai,Aj,Ak,flags,vel,lo,up); } Grid<Real> & A0; Grid<Real> & Ai; Grid<Real> & Aj; Grid<Real> & Ak; FlagGrid& flags; MACGrid& vel; Vector3D<bool> lo; Vector3D<bool> up; };
+
+
+//! Kernel: Set matrix rhs for outflow
+
+ struct SetOutflow : public KernelBase { SetOutflow(Grid<Real>& rhs, Vector3D<bool> lowerBound, Vector3D<bool> upperBound, int height) : KernelBase(&rhs,0) ,rhs(rhs),lowerBound(lowerBound),upperBound(upperBound),height(height) { run(); } inline void op(int i, int j, int k, Grid<Real>& rhs, Vector3D<bool> lowerBound, Vector3D<bool> upperBound, int height ) {
+ if ((lowerBound.x && i < height) || (upperBound.x && i >= maxX-1-height) ||
+ (lowerBound.y && j < height) || (upperBound.y && j >= maxY-1-height) ||
+ (lowerBound.z && k < height) || (upperBound.z && k >= maxZ-1-height))
+ rhs(i,j,k) = 0;
+} inline Grid<Real>& getArg0() { return rhs; } typedef Grid<Real> type0;inline Vector3D<bool> & getArg1() { return lowerBound; } typedef Vector3D<bool> type1;inline Vector3D<bool> & getArg2() { return upperBound; } typedef Vector3D<bool> type2;inline int& getArg3() { return height; } typedef int type3; 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, rhs,lowerBound,upperBound,height); } Grid<Real>& rhs; Vector3D<bool> lowerBound; Vector3D<bool> upperBound; int height; };
+
+
+// *****************************************************************************
+// Ghost fluid helpers
+
+// calculate fraction filled with liquid (note, assumes inside value is < outside!)
+inline static Real thetaHelper(Real inside, Real outside)
+{
+ 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(int idx, int offset, const Grid<Real> &phi, Real gfClamp)
+{
+ Real alpha = thetaHelper(phi[idx], phi[idx+offset]);
+ if (alpha < gfClamp) return alpha = gfClamp;
+ return (1-(1/alpha));
+}
+
+//! Kernel: Adapt A0 for ghost fluid
+
+
+ struct ApplyGhostFluidDiagonal : public KernelBase { ApplyGhostFluidDiagonal(Grid<Real> &A0, const FlagGrid &flags, const Grid<Real> &phi, Real gfClamp) : KernelBase(&A0,1) ,A0(A0),flags(flags),phi(phi),gfClamp(gfClamp) { run(); } inline void op(int i, int j, int k, Grid<Real> &A0, const FlagGrid &flags, const Grid<Real> &phi, Real gfClamp ) {
+ const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ int 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 Real& getArg3() { return gfClamp; } typedef Real type3; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, A0,flags,phi,gfClamp); } Grid<Real> & A0; const FlagGrid& flags; const Grid<Real> & phi; Real gfClamp; };
+
+//! Kernel: Apply velocity update: ghost fluid contribution
+
+
+ struct CorrectVelocityGhostFluid : public KernelBase { CorrectVelocityGhostFluid(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) { 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 int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ const int 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))
+ {
+ 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;
+ }
+ }
+} 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, vel,flags,pressure,phi,gfClamp); } MACGrid& vel; const FlagGrid& flags; const Grid<Real> & pressure; const Grid<Real> & phi; Real gfClamp; };
+
+
+// improve behavior of clamping for large time steps:
+
+inline static Real ghostFluidWasClamped(int idx, int offset, const Grid<Real> &phi, Real gfClamp)
+{
+ Real alpha = thetaHelper(phi[idx], phi[idx+offset]);
+ if (alpha < gfClamp) return true;
+ return false;
+}
+
+
+
+
+ struct ReplaceClampedGhostFluidVels : public KernelBase { ReplaceClampedGhostFluidVels(MACGrid &vel, 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) { run(); } inline void op(int i, int j, int k, MACGrid &vel, FlagGrid &flags, const Grid<Real> &pressure, const Grid<Real> &phi, Real gfClamp ) {
+ const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
+ const int idx = flags.index(i,j,k);
+ if (flags.isFluid(idx))
+ {
+ if( (flags.isEmpty(i-1,j,k)) && (ghostFluidWasClamped(idx, -X, phi, gfClamp)) )
+ vel[idx-X][0] = vel[idx][0];
+ if( (flags.isEmpty(i,j-1,k)) && (ghostFluidWasClamped(idx, -Y, phi, gfClamp)) )
+ vel[idx-Y][1] = vel[idx][1];
+ if( flags.is3D() &&
+ (flags.isEmpty(i,j,k-1)) && (ghostFluidWasClamped(idx, -Z, phi, gfClamp)) )
+ vel[idx-Z][2] = vel[idx][2];
+ }
+ else if (flags.isEmpty(idx))
+ {
+ if( (i>-1) && (flags.isFluid(i-1,j,k)) && ( ghostFluidWasClamped(idx-X, +X, phi, gfClamp) ) )
+ vel[idx][0] = vel[idx-X][0];
+ if( (j>-1) && (flags.isFluid(i,j-1,k)) && ( ghostFluidWasClamped(idx-Y, +Y, phi, gfClamp) ) )
+ vel[idx][1] = vel[idx-Y][1];
+ if( flags.is3D() &&
+ ( (k>-1) && (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 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, vel,flags,pressure,phi,gfClamp); } MACGrid& vel; FlagGrid& flags; const Grid<Real> & pressure; const Grid<Real> & phi; Real gfClamp; };
+
+
+// *****************************************************************************
+// Main pressure solve
+
+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.");
+ }
+}
+
+//! Perform pressure projection of the velocity grid
+
+
+
+
+
+
+
+
+
+
+
+void solvePressure(MACGrid& vel, Grid<Real>& pressure, FlagGrid& flags, string openBound="", Grid<Real>* phi = 0, Grid<Real>* perCellCorr = 0, Real gfClamp = 1e-04, Real cgMaxIterFac = 1.5, Real cgAccuracy = 1e-3, string outflow = "", int outflowHeight = 1, bool precondition = true, bool enforceCompatibility = false, bool useResNorm = true ) {
+ // parse strings
+ Vector3D<bool> loOpenBound, upOpenBound, loOutflow, upOutflow;
+ convertDescToVec(openBound, loOpenBound, upOpenBound);
+ convertDescToVec(outflow, loOutflow, upOutflow);
+ if (vel.is2D() && (loOpenBound.z || upOpenBound.z))
+ errMsg("open boundaries for z specified for 2D grid");
+
+ // 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);
+ Grid<Real> pca0(parent);
+ Grid<Real> pca1(parent);
+ Grid<Real> pca2(parent);
+ Grid<Real> pca3(parent);
+
+ // setup matrix and boundaries
+ MakeLaplaceMatrix (flags, A0, Ai, Aj, Ak);
+ SetOpenBound (A0, Ai, Aj, Ak, flags, vel, loOpenBound, upOpenBound);
+
+ if (phi) {
+ ApplyGhostFluidDiagonal(A0, flags, *phi, gfClamp);
+ }
+
+ // compute divergence and init right hand side
+ MakeRhs kernMakeRhs (flags, rhs, vel, perCellCorr);
+
+ if (!outflow.empty())
+ SetOutflow (rhs, loOutflow, upOutflow, outflowHeight);
+
+ if (enforceCompatibility)
+ rhs += (Real)(-kernMakeRhs.sum / (Real)kernMakeRhs.cnt);
+
+ // CG setup
+ // note: the last factor increases the max iterations for 2d, which right now can't use a preconditioner
+ const int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
+ 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->setUseResNorm( useResNorm );
+
+ // optional preconditioning
+ gcg->setPreconditioner( precondition ? GridCgInterface::PC_mICP : GridCgInterface::PC_None, &pca0, &pca1, &pca2, &pca3);
+
+ for (int iter=0; iter<maxIter; iter++) {
+ if (!gcg->iterate()) iter=maxIter;
+ }
+ debMsg("FluidSolver::solvePressure iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma(), 1);
+ delete gcg;
+
+ CorrectVelocity(flags, vel, pressure );
+ if (phi) {
+ CorrectVelocityGhostFluid (vel, flags, pressure, *phi, gfClamp);
+ // improve behavior of clamping for large time steps:
+ ReplaceClampedGhostFluidVels (vel, flags, pressure, *phi, gfClamp);
+ }
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "solvePressure" ); PyObject *_retval = 0; { ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Real>& pressure = *_args.getPtr<Grid<Real> >("pressure",1,&_lock); FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",2,&_lock); string openBound = _args.getOpt<string >("openBound",3,"",&_lock); Grid<Real>* phi = _args.getPtrOpt<Grid<Real> >("phi",4,0,&_lock); Grid<Real>* perCellCorr = _args.getPtrOpt<Grid<Real> >("perCellCorr",5,0,&_lock); Real gfClamp = _args.getOpt<Real >("gfClamp",6,1e-04,&_lock); Real cgMaxIterFac = _args.getOpt<Real >("cgMaxIterFac",7,1.5,&_lock); Real cgAccuracy = _args.getOpt<Real >("cgAccuracy",8,1e-3,&_lock); string outflow = _args.getOpt<string >("outflow",9,"",&_lock); int outflowHeight = _args.getOpt<int >("outflowHeight",10,1,&_lock); bool precondition = _args.getOpt<bool >("precondition",11,true,&_lock); bool enforceCompatibility = _args.getOpt<bool >("enforceCompatibility",12,false,&_lock); bool useResNorm = _args.getOpt<bool >("useResNorm",13,true ,&_lock); _retval = getPyNone(); solvePressure(vel,pressure,flags,openBound,phi,perCellCorr,gfClamp,cgMaxIterFac,cgAccuracy,outflow,outflowHeight,precondition,enforceCompatibility,useResNorm); _args.check(); } pbFinalizePlugin(parent,"solvePressure" ); return _retval; } catch(std::exception& e) { pbSetError("solvePressure",e.what()); return 0; } } static const Pb::Register _RP_solvePressure ("","solvePressure",_W_0);
+
+} // end namespace
+
+
+
diff --git a/source/blender/python/manta_pp/plugin/vortexplugins.cpp b/source/blender/python/manta_pp/plugin/vortexplugins.cpp
new file mode 100644
index 00000000000..c0133697bee
--- /dev/null
+++ b/source/blender/python/manta_pp/plugin/vortexplugins.cpp
@@ -0,0 +1,324 @@
+
+
+
+
+
+// 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
+ *
+ * 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, 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(); pbPreparePlugin(parent, "markAsFixed" ); PyObject *_retval = 0; { ArgLocker _lock; Mesh& mesh = *_args.getPtr<Mesh >("mesh",0,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("markAsFixed",e.what()); return 0; } } static const Pb::Register _RP_markAsFixed ("","markAsFixed",_W_0);
+
+//! Adapt texture coordinates of mesh inside shape
+//! to obtain an effective inflow effect
+
+void texcoordInflow(VortexSheetMesh& mesh, Shape* shape, MACGrid& vel) {
+ static Vec3 t0 = Vec3::Zero;
+
+ // get mean velocity
+ int cnt=0;
+ Vec3 meanV(_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(); pbPreparePlugin(parent, "texcoordInflow" ); PyObject *_retval = 0; { ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); Shape* shape = _args.getPtr<Shape >("shape",1,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",2,&_lock); _retval = getPyNone(); texcoordInflow(mesh,shape,vel); _args.check(); } pbFinalizePlugin(parent,"texcoordInflow" ); return _retval; } catch(std::exception& e) { pbSetError("texcoordInflow",e.what()); return 0; } } static const Pb::Register _RP_texcoordInflow ("","texcoordInflow",_W_1); ;
+
+//! Init smoke density values of the mesh surface inside source shape
+
+void meshSmokeInflow(VortexSheetMesh& mesh, 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(); pbPreparePlugin(parent, "meshSmokeInflow" ); PyObject *_retval = 0; { ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("meshSmokeInflow",e.what()); return 0; } } static const Pb::Register _RP_meshSmokeInflow ("","meshSmokeInflow",_W_2);
+
+
+ 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) { run(); } inline void op(int idx, MACGrid& a, const MACGrid& v1, const MACGrid& v0, const Real idt ) {
+ 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, a,v1,v0,idt); } 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, MACGrid* vel=NULL, 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(); pbPreparePlugin(parent, "vorticitySource" ); PyObject *_retval = 0; { ArgLocker _lock; VortexSheetMesh& mesh = *_args.getPtr<VortexSheetMesh >("mesh",0,&_lock); Vec3 gravity = _args.get<Vec3 >("gravity",1,&_lock); MACGrid* vel = _args.getPtrOpt<MACGrid >("vel",2,NULL,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("vorticitySource",e.what()); return 0; } } static const Pb::Register _RP_vorticitySource ("","vorticitySource",_W_3);
+
+
+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(); pbPreparePlugin(parent, "smoothVorticity" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("smoothVorticity",e.what()); return 0; } } static const Pb::Register _RP_smoothVorticity ("","smoothVorticity",_W_4);
+
+//! Seed Vortex Particles inside shape with K41 characteristics
+void VPseedK41(VortexParticleSystem& system, 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(); pbPreparePlugin(parent, "VPseedK41" ); PyObject *_retval = 0; { ArgLocker _lock; VortexParticleSystem& system = *_args.getPtr<VortexParticleSystem >("system",0,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("VPseedK41",e.what()); return 0; } } static const Pb::Register _RP_VPseedK41 ("","VPseedK41",_W_5);
+
+//! Vortex-in-cell integration
+
+void VICintegration(VortexSheetMesh& mesh, Real sigma, Grid<Vec3>& vel, 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->setUseResNorm(true);
+ gcg->setPreconditioner( (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(); pbPreparePlugin(parent, "VICintegration" ); 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); 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" ); return _retval; } catch(std::exception& e) { pbSetError("VICintegration",e.what()); return 0; } } static const Pb::Register _RP_VICintegration ("","VICintegration",_W_6);
+
+//! Obtain density field from levelset with linear gradient of size sigma over the interface
+void densityFromLevelset(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))), _0, value);
+ }
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "densityFromLevelset" ); PyObject *_retval = 0; { ArgLocker _lock; 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" ); return _retval; } catch(std::exception& e) { pbSetError("densityFromLevelset",e.what()); return 0; } } static const Pb::Register _RP_densityFromLevelset ("","densityFromLevelset",_W_7);
+
+} // namespace
+
diff --git a/source/blender/python/manta_pp/plugin/waveletturbulence.cpp b/source/blender/python/manta_pp/plugin/waveletturbulence.cpp
new file mode 100644
index 00000000000..819fd35fb6f
--- /dev/null
+++ b/source/blender/python/manta_pp/plugin/waveletturbulence.cpp
@@ -0,0 +1,309 @@
+
+
+
+
+
+// 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
+ *
+ * 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 {
+
+
+//! Apply vector noise to grid, this is a simplified version - no position scaling or UVs
+
+
+
+ struct knApplySimpleNoiseVec : public KernelBase { knApplySimpleNoiseVec(FlagGrid& flags, Grid<Vec3>& target, WaveletNoiseField& noise, Real scale, Grid<Real>* weight ) : KernelBase(&flags,0) ,flags(flags),target(target),noise(noise),scale(scale),weight(weight) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<Vec3>& target, WaveletNoiseField& noise, Real scale, Grid<Real>* weight ) {
+ 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) ) * scale * factor;
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Vec3>& getArg1() { return target; } typedef Grid<Vec3> type1;inline WaveletNoiseField& getArg2() { return noise; } typedef WaveletNoiseField type2;inline Real& getArg3() { return scale; } typedef Real type3;inline Grid<Real>* getArg4() { return weight; } typedef Grid<Real> type4; 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,target,noise,scale,weight); } FlagGrid& flags; Grid<Vec3>& target; WaveletNoiseField& noise; Real scale; Grid<Real>* weight; };
+
+
+void applySimpleNoiseVec3(FlagGrid& flags, Grid<Vec3>& target, WaveletNoiseField& noise, Real scale=1.0 , Grid<Real>* weight=NULL ) {
+ // note - passing a MAC grid here is slightly inaccurate, we should evaluate each component separately
+ knApplySimpleNoiseVec(flags, target, noise, scale , weight );
+} static PyObject* _W_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "applySimpleNoiseVec3" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.0 ,&_lock); Grid<Real>* weight = _args.getPtrOpt<Grid<Real> >("weight",4,NULL ,&_lock); _retval = getPyNone(); applySimpleNoiseVec3(flags,target,noise,scale,weight); _args.check(); } pbFinalizePlugin(parent,"applySimpleNoiseVec3" ); return _retval; } catch(std::exception& e) { pbSetError("applySimpleNoiseVec3",e.what()); return 0; } } static const Pb::Register _RP_applySimpleNoiseVec3 ("","applySimpleNoiseVec3",_W_0);
+
+
+//! Simple noise for a real grid , follows applySimpleNoiseVec3
+
+
+
+ struct knApplySimpleNoiseReal : public KernelBase { knApplySimpleNoiseReal(FlagGrid& flags, Grid<Real>& target, WaveletNoiseField& noise, Real scale, Grid<Real>* weight ) : KernelBase(&flags,0) ,flags(flags),target(target),noise(noise),scale(scale),weight(weight) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<Real>& target, WaveletNoiseField& noise, Real scale, Grid<Real>* weight ) {
+ 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) ) * scale * factor;
+} inline FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Real>& getArg1() { return target; } typedef Grid<Real> type1;inline WaveletNoiseField& getArg2() { return noise; } typedef WaveletNoiseField type2;inline Real& getArg3() { return scale; } typedef Real type3;inline Grid<Real>* getArg4() { return weight; } typedef Grid<Real> type4; 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,target,noise,scale,weight); } FlagGrid& flags; Grid<Real>& target; WaveletNoiseField& noise; Real scale; Grid<Real>* weight; };
+
+
+void applySimpleNoiseReal(FlagGrid& flags, Grid<Real>& target, WaveletNoiseField& noise, Real scale=1.0 , Grid<Real>* weight=NULL ) {
+ knApplySimpleNoiseReal(flags, target, noise, scale , weight );
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "applySimpleNoiseReal" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",1,&_lock); WaveletNoiseField& noise = *_args.getPtr<WaveletNoiseField >("noise",2,&_lock); Real scale = _args.getOpt<Real >("scale",3,1.0 ,&_lock); Grid<Real>* weight = _args.getPtrOpt<Grid<Real> >("weight",4,NULL ,&_lock); _retval = getPyNone(); applySimpleNoiseReal(flags,target,noise,scale,weight); _args.check(); } pbFinalizePlugin(parent,"applySimpleNoiseReal" ); return _retval; } catch(std::exception& e) { pbSetError("applySimpleNoiseReal",e.what()); return 0; } } static const Pb::Register _RP_applySimpleNoiseReal ("","applySimpleNoiseReal",_W_1);
+
+
+
+//! 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 knApplyNoiseVec : public KernelBase { knApplyNoiseVec(FlagGrid& flags, Grid<Vec3>& target, WaveletNoiseField& noise, Real scale, Real scaleSpatial, Grid<Real>* weight, 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) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<Vec3>& target, WaveletNoiseField& noise, Real scale, Real scaleSpatial, Grid<Real>* weight, Grid<Vec3>* uv, bool uvInterpol, const Vec3& sourceFactor ) {
+ 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);
+ 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 FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Vec3>& getArg1() { return target; } typedef Grid<Vec3> type1;inline WaveletNoiseField& getArg2() { return noise; } typedef WaveletNoiseField type2;inline Real& getArg3() { return scale; } typedef Real type3;inline Real& getArg4() { return scaleSpatial; } typedef Real type4;inline Grid<Real>* getArg5() { return weight; } typedef Grid<Real> type5;inline 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 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,target,noise,scale,scaleSpatial,weight,uv,uvInterpol,sourceFactor); } FlagGrid& flags; Grid<Vec3>& target; WaveletNoiseField& noise; Real scale; Real scaleSpatial; Grid<Real>* weight; Grid<Vec3>* uv; bool uvInterpol; const Vec3& sourceFactor; };
+
+
+void applyNoiseVec3(FlagGrid& flags, Grid<Vec3>& target, WaveletNoiseField& noise, Real scale=1.0 , Real scaleSpatial=1.0 , Grid<Real>* weight=NULL , 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
+ knApplyNoiseVec(flags, target, noise, scale, scaleSpatial, weight , uv,uvInterpol,sourceFactor );
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "applyNoiseVec3" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); Grid<Vec3>& target = *_args.getPtr<Grid<Vec3> >("target",1,&_lock); 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); Grid<Real>* weight = _args.getPtrOpt<Grid<Real> >("weight",5,NULL ,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("applyNoiseVec3",e.what()); return 0; } } static const Pb::Register _RP_applyNoiseVec3 ("","applyNoiseVec3",_W_2);
+
+
+
+//! Compute energy of a staggered velocity field (at cell center)
+
+
+ struct KnApplyComputeEnergy : public KernelBase { KnApplyComputeEnergy( FlagGrid& flags, MACGrid& vel, Grid<Real>& energy ) : KernelBase(&flags,0) ,flags(flags),vel(vel),energy(energy) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, MACGrid& vel, Grid<Real>& energy ) {
+ 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 FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline MACGrid& getArg1() { return vel; } typedef MACGrid type1;inline Grid<Real>& getArg2() { return energy; } typedef Grid<Real> type2; 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,vel,energy); } FlagGrid& flags; MACGrid& vel; Grid<Real>& energy; };
+
+
+void computeEnergy( FlagGrid& flags, MACGrid& vel, Grid<Real>& energy ) {
+ KnApplyComputeEnergy( flags, vel, energy );
+} static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "computeEnergy" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); 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" ); return _retval; } catch(std::exception& e) { pbSetError("computeEnergy",e.what()); return 0; } } static const Pb::Register _RP_computeEnergy ("","computeEnergy",_W_3);
+
+
+
+//!interpolate grid from one size to another size
+
+
+ struct KnInterpolateGrid : public KernelBase { KnInterpolateGrid(Grid<Real>& target, Grid<Real>& source, const Vec3& sourceFactor) : KernelBase(&target,0) ,target(target),source(source),sourceFactor(sourceFactor) { run(); } inline void op(int i, int j, int k, Grid<Real>& target, Grid<Real>& source, const Vec3& sourceFactor ) {
+ Vec3 pos = Vec3(i,j,k) * sourceFactor;
+ if(!source.is3D()) pos[2] = 0; // allow 2d -> 3d
+ target(i,j,k) = source.getInterpolated(pos);
+} inline Grid<Real>& getArg0() { return target; } typedef Grid<Real> type0;inline Grid<Real>& getArg1() { return source; } typedef Grid<Real> type1;inline const Vec3& getArg2() { return sourceFactor; } typedef Vec3 type2; 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, target,source,sourceFactor); } Grid<Real>& target; Grid<Real>& source; const Vec3& sourceFactor; };
+
+
+void interpolateGrid( Grid<Real>& target, Grid<Real>& source ) {
+ Vec3 sourceFactor = calcGridSizeFactor( source.getSize(), target.getSize() );
+
+ // 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).
+
+ KnInterpolateGrid(target, source, sourceFactor);
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "interpolateGrid" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<Real>& target = *_args.getPtr<Grid<Real> >("target",0,&_lock); Grid<Real>& source = *_args.getPtr<Grid<Real> >("source",1,&_lock); _retval = getPyNone(); interpolateGrid(target,source); _args.check(); } pbFinalizePlugin(parent,"interpolateGrid" ); return _retval; } catch(std::exception& e) { pbSetError("interpolateGrid",e.what()); return 0; } } static const Pb::Register _RP_interpolateGrid ("","interpolateGrid",_W_4);
+
+
+//!interpolate a mac velocity grid from one size to another size
+
+
+ struct KnInterpolateMACGrid : public KernelBase { KnInterpolateMACGrid(MACGrid& target, MACGrid& source, const Vec3& sourceFactor) : KernelBase(&target,0) ,target(target),source(source),sourceFactor(sourceFactor) { run(); } inline void op(int i, int j, int k, MACGrid& target, MACGrid& source, const Vec3& sourceFactor ) {
+ Vec3 pos = Vec3(i,j,k) * sourceFactor;
+
+ Real vx = source.getInterpolated(pos - Vec3(0.5,0,0))[0];
+ Real vy = source.getInterpolated(pos - Vec3(0,0.5,0))[1];
+ Real vz = 0.f;
+ if(source.is3D()) vz = source.getInterpolated(pos - Vec3(0,0,0.5))[2];
+
+ target(i,j,k) = Vec3(vx,vy,vz);
+} inline MACGrid& getArg0() { return target; } typedef MACGrid type0;inline MACGrid& getArg1() { return source; } typedef MACGrid type1;inline const Vec3& getArg2() { return sourceFactor; } typedef Vec3 type2; 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, target,source,sourceFactor); } MACGrid& target; MACGrid& source; const Vec3& sourceFactor; };
+
+
+void interpolateMACGrid(MACGrid& target, MACGrid& source) {
+ Vec3 sourceFactor = calcGridSizeFactor( source.getSize(), target.getSize() );
+
+ // see interpolateGrid for why the target grid needs to come first in the parameters!
+
+ KnInterpolateMACGrid(target, source, sourceFactor);
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "interpolateMACGrid" ); PyObject *_retval = 0; { ArgLocker _lock; MACGrid& target = *_args.getPtr<MACGrid >("target",0,&_lock); MACGrid& source = *_args.getPtr<MACGrid >("source",1,&_lock); _retval = getPyNone(); interpolateMACGrid(target,source); _args.check(); } pbFinalizePlugin(parent,"interpolateMACGrid" ); return _retval; } catch(std::exception& e) { pbSetError("interpolateMACGrid",e.what()); return 0; } } static const Pb::Register _RP_interpolateMACGrid ("","interpolateMACGrid",_W_5);
+
+
+void computeWaveletCoeffs(Grid<Real>& input) {
+ Grid<Real> temp1(input.getParent()), temp2(input.getParent());
+ WaveletNoiseField::computeCoefficients(input, temp1, temp2);
+} static PyObject* _W_6 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "computeWaveletCoeffs" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<Real>& input = *_args.getPtr<Grid<Real> >("input",0,&_lock); _retval = getPyNone(); computeWaveletCoeffs(input); _args.check(); } pbFinalizePlugin(parent,"computeWaveletCoeffs" ); return _retval; } catch(std::exception& e) { pbSetError("computeWaveletCoeffs",e.what()); return 0; } } static const Pb::Register _RP_computeWaveletCoeffs ("","computeWaveletCoeffs",_W_6);
+
+// note - alomst the same as for vorticity confinement
+void computeVorticity(MACGrid& vel, Grid<Vec3>& vorticity, Grid<Real>* norm) {
+ Grid<Vec3> velCenter(vel.getParent());
+ GetCentered(velCenter, vel);
+ CurlOp(velCenter, vorticity);
+ if(norm) GridNorm( *norm, vorticity);
+} static PyObject* _W_7 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "computeVorticity" ); PyObject *_retval = 0; { ArgLocker _lock; MACGrid& vel = *_args.getPtr<MACGrid >("vel",0,&_lock); Grid<Vec3>& vorticity = *_args.getPtr<Grid<Vec3> >("vorticity",1,&_lock); Grid<Real>* norm = _args.getPtr<Grid<Real> >("norm",2,&_lock); _retval = getPyNone(); computeVorticity(vel,vorticity,norm); _args.check(); } pbFinalizePlugin(parent,"computeVorticity" ); return _retval; } catch(std::exception& e) { pbSetError("computeVorticity",e.what()); return 0; } } static const Pb::Register _RP_computeVorticity ("","computeVorticity",_W_7);
+
+// 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) { run(); } inline void op(int i, int j, int k, const MACGrid& vel, const Grid<Vec3>& velCenter, Grid<Real>& prod ) {
+ // 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, vel,velCenter,prod); } const MACGrid& vel; const Grid<Vec3>& velCenter; Grid<Real>& prod; };
+void computeStrainRateMag(MACGrid& vel, Grid<Real>& mag) {
+ Grid<Vec3> velCenter(vel.getParent());
+ GetCentered(velCenter, vel);
+ KnComputeStrainRateMag(vel, velCenter, mag);
+} static PyObject* _W_8 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "computeStrainRateMag" ); PyObject *_retval = 0; { ArgLocker _lock; 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" ); return _retval; } catch(std::exception& e) { pbSetError("computeStrainRateMag",e.what()); return 0; } } static const Pb::Register _RP_computeStrainRateMag ("","computeStrainRateMag",_W_8);
+
+
+// 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 (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(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_9 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "extrapolateSimpleFlags" ); PyObject *_retval = 0; { ArgLocker _lock; 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" ); return _retval; } catch(std::exception& e) { pbSetError("extrapolateSimpleFlags",e.what()); return 0; } } static const Pb::Register _RP_extrapolateSimpleFlags ("","extrapolateSimpleFlags",_W_9);
+
+} // namespace
+
+
diff --git a/source/blender/python/manta_pp/plugin/waves.cpp b/source/blender/python/manta_pp/plugin/waves.cpp
new file mode 100644
index 00000000000..0181b3de5f2
--- /dev/null
+++ b/source/blender/python/manta_pp/plugin/waves.cpp
@@ -0,0 +1,174 @@
+
+
+
+
+
+// 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
+ *
+ * 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) { run(); } inline void op(int i, int j, int k, const Grid<Real>& v, Grid<Real>& ret ) {
+
+ 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, v,ret); } const Grid<Real>& v; Grid<Real>& ret; };;
+
+
+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(); pbPreparePlugin(parent, "calcSecDeriv2d" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("calcSecDeriv2d",e.what()); return 0; } } static const Pb::Register _RP_calcSecDeriv2d ("","calcSecDeriv2d",_W_0);
+
+
+// mass conservation
+
+
+ struct knTotalSum : public KernelBase { knTotalSum(Grid<Real>& h) : KernelBase(&h,1) ,h(h) ,sum(0) { run(); } inline void op(int i, int j, int k, Grid<Real>& h ,double& sum) { sum += h(i,j,k); } inline Grid<Real>& getArg0() { return h; } typedef Grid<Real> type0; void run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; k++) for (int j=1; j< _maxY; j++) for (int i=1; i< _maxX; i++) op(i,j,k, h,sum); } Grid<Real>& h; double sum; };
+
+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(); pbPreparePlugin(parent, "totalSum" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<Real>& height = *_args.getPtr<Grid<Real> >("height",0,&_lock); _retval = toPy(totalSum(height)); _args.check(); } pbFinalizePlugin(parent,"totalSum" ); return _retval; } catch(std::exception& e) { pbSetError("totalSum",e.what()); return 0; } } static const Pb::Register _RP_totalSum ("","totalSum",_W_1);
+
+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(); pbPreparePlugin(parent, "normalizeSumTo" ); 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" ); return _retval; } catch(std::exception& e) { pbSetError("normalizeSumTo",e.what()); return 0; } } static const Pb::Register _RP_normalizeSumTo ("","normalizeSumTo",_W_2);
+
+
+/******************************************************************************
+ *
+ * implicit time integration
+ *
+ ******************************************************************************/
+
+
+
+//! Kernel: Construct the right-hand side of the poisson equation
+
+
+
+ struct MakeRhsWE : public KernelBase { MakeRhsWE(FlagGrid& flags, Grid<Real>& rhs, Grid<Real>& ut, Grid<Real>& utm1, Real s, bool crankNic=false) : KernelBase(&flags,1) ,flags(flags),rhs(rhs),ut(ut),utm1(utm1),s(s),crankNic(crankNic) { run(); } inline void op(int i, int j, int k, FlagGrid& flags, Grid<Real>& rhs, Grid<Real>& ut, Grid<Real>& utm1, Real s, bool crankNic=false ) {
+ 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 FlagGrid& getArg0() { return flags; } typedef FlagGrid type0;inline Grid<Real>& getArg1() { return rhs; } typedef Grid<Real> type1;inline Grid<Real>& getArg2() { return ut; } typedef Grid<Real> type2;inline 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 run() { const int _maxX = maxX; const int _maxY = maxY; for (int k=minZ; k< maxZ; 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); } FlagGrid& flags; Grid<Real>& rhs; Grid<Real>& ut; Grid<Real>& utm1; Real s; bool crankNic; };
+
+
+
+
+
+//! do a CG solve (note, out grid only there for debugging... could be removed)
+
+
+
+
+
+void cgSolveWE(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);
+ //Grid<Real> pca0(parent);
+ //Grid<Real> pca1(parent);
+ //Grid<Real> pca2(parent);
+ //Grid<Real> pca3(parent);
+ // solution...
+ //Grid<Real> pressure(parent);
+ 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 );
+ gcg->setUseResNorm( true );
+
+ // optional preconditioning
+ //gcg->setPreconditioner( precondition ? GridCgInterface::PC_mICP : GridCgInterface::PC_None, &pca0, &pca1, &pca2, &pca3);
+
+ for (int iter=0; iter<maxIter; iter++) {
+ if (!gcg->iterate()) iter=maxIter;
+ }
+ debMsg("FluidSolver::solvePressure 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(); pbPreparePlugin(parent, "cgSolveWE" ); PyObject *_retval = 0; { ArgLocker _lock; 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" ); return _retval; } catch(std::exception& e) { pbSetError("cgSolveWE",e.what()); return 0; } } static const Pb::Register _RP_cgSolveWE ("","cgSolveWE",_W_3);
+
+
+
+
+} //namespace
+
+
+
diff --git a/source/blender/python/manta_pp/pwrapper/manta.h b/source/blender/python/manta_pp/pwrapper/manta.h
new file mode 100644
index 00000000000..87e5c95252d
--- /dev/null
+++ b/source/blender/python/manta_pp/pwrapper/manta.h
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Main
+ *
+ ******************************************************************************/
+
+#ifndef _MANTA_H
+#define _MANTA_H
+
+// Remove preprocessor keywords, so there won't infere with autocompletion etc.
+#define KERNEL
+#define PYTHON
+
+// Define plugin documentation group
+// all plugin functions and classes will automatically be added to this group
+//! @defgroup Plugins Plugins
+//! @defgroup PyClasses Classes exposed to Python
+
+#include "general.h"
+#include "vectorbase.h"
+#include "registry.h"
+#include "pclass.h"
+#include "pconvert.h"
+#include "fluidsolver.h"
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_pp/pwrapper/manta_api.cpp b/source/blender/python/manta_pp/pwrapper/manta_api.cpp
new file mode 100644
index 00000000000..4184a32ec6f
--- /dev/null
+++ b/source/blender/python/manta_pp/pwrapper/manta_api.cpp
@@ -0,0 +1,27 @@
+#include "Python.h"
+//#include "manta_api.h"
+#include "manta.h"
+#include "../general.h"
+
+using namespace std;
+using namespace Manta;
+
+#if PY_MAJOR_VERSION >= 3
+typedef wchar_t pyChar;
+typedef wstring pyString;
+#else
+typedef char pyChar;
+typedef string pyString;
+#endif
+
+//#ifdef __cplusplus
+extern "C" {
+//#endif
+PyObject * PyInit_Manta(void)
+{
+ return Pb::PyInit_Main_Obj();
+}
+
+//#ifdef __cplusplus
+}
+//#endif
diff --git a/source/blender/python/manta_pp/pwrapper/manta_api.h b/source/blender/python/manta_pp/pwrapper/manta_api.h
new file mode 100644
index 00000000000..3fbfe6f522c
--- /dev/null
+++ b/source/blender/python/manta_pp/pwrapper/manta_api.h
@@ -0,0 +1,6 @@
+#ifndef _MANTA_API_H_
+#define _MANTA_API_H_
+//#include "pythonInclude.h"
+PyObject * PyInit_Manta(void);
+PyMODINIT_FUNC PyInit_Main_Link(void);
+#endif
diff --git a/source/blender/python/manta_pp/pwrapper/pclass.cpp b/source/blender/python/manta_pp/pwrapper/pclass.cpp
new file mode 100644
index 00000000000..838ae3f3b84
--- /dev/null
+++ b/source/blender/python/manta_pp/pwrapper/pclass.cpp
@@ -0,0 +1,177 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Functions for property setting/getting via python
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include "structmember.h"
+#include "manta.h"
+#include "general.h"
+#include "timing.h"
+
+using namespace std;
+namespace Manta {
+
+//******************************************************************************
+// Free functions
+
+#ifdef GUI
+ extern void updateQtGui(bool full, int frame, const std::string& curPlugin);
+#else
+ inline void updateQtGui(bool full, int frame, const std::string& curPlugin) {}
+#endif
+
+void pbPreparePlugin(FluidSolver* parent, const string& name) {
+ TimingData::instance().start(parent, name);
+}
+
+void pbFinalizePlugin(FluidSolver *parent, const string& name) {
+ 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, msg.str() );
+
+ debMsg(name<<" done", 2);
+ // name unnamed PbClass Objects from var name
+ PbClass::renameObjects();
+}
+
+void pbSetError(const string& fn, const string& ex) {
+ cout << "Error in " << fn << endl;
+ 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(), mParent(parent), mPyObject(obj), mName(name), mHidden(false)
+{
+}
+
+PbClass::PbClass(const PbClass& a) : mMutex(), mParent(a.mParent), mPyObject(0), mName("_unnamed"), mHidden(false)
+{
+}
+
+
+PbClass::~PbClass() {
+ for(vector<PbClass*>::iterator it = mInstances.begin(); it != mInstances.end(); ++it) {
+ if (*it == this) {
+ mInstances.erase(it);
+ break;
+ }
+ }
+}
+
+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;
+}
+
+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
diff --git a/source/blender/python/manta_pp/pwrapper/pclass.h b/source/blender/python/manta_pp/pwrapper/pclass.h
new file mode 100644
index 00000000000..418d0d8dfaf
--- /dev/null
+++ b/source/blender/python/manta_pp/pwrapper/pclass.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
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * 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>
+
+#ifdef GUI
+# include <QMutex>
+#else
+struct QMutex {
+ void lock() {};
+ void unlock() {};
+ bool tryLock() {return true;};
+};
+#endif
+
+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 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);
+void pbPreparePlugin(FluidSolver* parent, const std::string& name);
+void pbSetError(const std::string& fn, const std::string& ex);
+
+//!\endcond
+
+} // namespace
+
+#endif
+#endif
diff --git a/source/blender/python/manta_pp/pwrapper/pconvert.cpp b/source/blender/python/manta_pp/pwrapper/pconvert.cpp
new file mode 100644
index 00000000000..916ffa7a98f
--- /dev/null
+++ b/source/blender/python/manta_pp/pwrapper/pconvert.cpp
@@ -0,0 +1,410 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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;
+struct PbVec3 {
+ PyObject_HEAD
+ float data[3];
+};
+
+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<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<> 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<> 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<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
diff --git a/source/blender/python/manta_pp/pwrapper/pconvert.h b/source/blender/python/manta_pp/pwrapper/pconvert.h
new file mode 100644
index 00000000000..7b8721254a5
--- /dev/null
+++ b/source/blender/python/manta_pp/pwrapper/pconvert.h
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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))
+ 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);
+
+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))
+ 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? (you shouldn't)");
+}
+
+// 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<> 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);
+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<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 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
+#endif
+#endif
diff --git a/source/blender/python/manta_pp/pwrapper/pvec3.cpp b/source/blender/python/manta_pp/pwrapper/pvec3.cpp
new file mode 100644
index 00000000000..0743fe6914b
--- /dev/null
+++ b/source/blender/python/manta_pp/pwrapper/pvec3.cpp
@@ -0,0 +1,286 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Vec3 class extension for python
+ *
+ ******************************************************************************/
+
+#include "pythonInclude.h"
+#include <math.h>
+#include <string>
+#include <sstream>
+#include <limits>
+#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 {
+ 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));
+}
+
+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);
+}
+const static Pb::Register _REG(PbVecInitialize);
+
+} // namespace \ No newline at end of file
diff --git a/source/blender/python/manta_pp/pwrapper/pymain.cpp b/source/blender/python/manta_pp/pwrapper/pymain.cpp
new file mode 100644
index 00000000000..83bc58738e6
--- /dev/null
+++ b/source/blender/python/manta_pp/pwrapper/pymain.cpp
@@ -0,0 +1,264 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Main file
+ *
+ ******************************************************************************/
+#ifndef _MANTA_PYMAIN_CPP_
+#define _MANTA_PYMAIN_CPP_
+
+#include "pythonInclude.h"
+#include <stdio.h>
+#include "manta.h"
+#include "../general.h"
+#include "grid.h"
+#include "fileio.h"
+#include "wchar.h"
+#include <fstream>
+using namespace std;
+namespace Manta {
+ extern void guiMain(int argc, char* argv[]);
+ extern void guiWaitFinish();
+}
+
+using namespace std;
+using namespace Manta;
+
+#if PY_MAJOR_VERSION >= 3
+typedef wchar_t pyChar;
+typedef wstring pyString;
+#else
+typedef char pyChar;
+typedef string pyString;
+#endif
+
+//*****************************************************************************
+// main...
+static bool manta_initialized = false;
+//def del_var(x):\n\
+// if globals().has_key(x):\n\
+// del x \n\
+// except NameError as e:\n\
+print (\'not deleted\') \n\
+
+const string clean_code1 = "\n\
+if 's' in globals() : del s \n\
+if 'uvs' in globals() : del uvs \n\
+if 'velInflow' in globals() : del velInflow \n\
+if 'res' in globals() : del res \n\
+if 'gs' in globals() : del gs \n\
+if 'noise' in globals() : del noise \n\
+if 'source' in globals() : del source \n\
+if 'sourceVel' in globals() : del sourceVel \n\
+if 'flags' in globals() : del flags \n\
+if 'vel' in globals() : del vel \n\
+if 'density' in globals() : del density \n\
+if 'pressure' in globals() : del pressure \n\
+if 'energy' in globals() : del energy \n\
+if 'tempFlag' in globals() : del tempFlag \n\
+if 'sdf_flow' in globals() : del sdf_flow \n\
+if 'source_shape' in globals() : del source_shape\n";
+const static string clean_code2 = "del s;del noise;del xl;del xl_noise;del xl_wltnoise;";
+ //for latter full object release
+ //const static string clean_code2 = "del [s, noise, source, sourceVel, xl, xl_vel, xl_density, xl_flags,xl_source, xl_noise, flags, vel, density, pressure, energy, tempFlag, sdf_flow, forces, source,source_shape, xl_wltnoise]";
+
+void export_fields(int size_x, int size_y, int size_z, float *f_x, float*f_y, float*f_z, char *filename)
+{
+ assert(size_x>0 && size_y>0 && size_z>0);
+ assert(f_x != NULL);
+ assert(f_y != NULL);
+ assert(f_z != NULL);
+ FluidSolver dummy(Vec3i(size_x,size_y,size_z));
+ Grid<Vec3> force_fields(&dummy, false);
+ for (int x=0; x < size_x; ++x)
+ {
+ for (int y=0; y < size_y; ++y)
+ {
+ for (int z=0; z < size_z; ++z)
+ {
+ force_fields.get(x, y, z) = Vec3(f_x[x],f_y[y],f_z[z]);
+ }
+ }
+ }
+ writeGridUni(filename, &force_fields);
+ /*rename after export successful*/
+
+// writeGridTxt("s.txt", &force_fields);
+}
+
+void export_em_fields(float *em_map, float flow_density, int min_x, int min_y, int min_z, int max_x, int max_y, int max_z, int d_x, int d_y, int d_z, float *inf, float *vel)
+{
+// assert(size_x>0 && size_y>0 && size_z>0);
+ assert(inf != NULL);
+// assert(vel != NULL);
+
+ FluidSolver dummy(Vec3i(d_x,d_y,d_z));
+ Grid<Real> em_inf_fields(&dummy, false);
+ em_inf_fields.clear();
+ const char* influence_name = "manta_em_influence.uni";
+// const char* velocity_name = "em_vel_fields.uni";
+ ifstream em_file(influence_name);
+ if (em_file.good()) {
+// em_inf_fields.load(influence_name);
+ }
+ em_file.close();
+
+// Grid<Vec3> em_vel_fields(&dummy, false);
+// ifstream vel_file(velocity_name);
+// if (vel_file.good()) {
+// em_vel_fields.load(velocity_name);
+// }
+// vel_file.close();
+ int index(0);
+ Vec3i em_size(max_x - min_x, max_y - min_y, max_z - min_z);
+ int em_size_x =em_size[0];
+ int em_size_xy = em_size[0] * em_size[1];
+ for (int x=0; x < em_size[0]; ++x)
+ {
+ for (int y=0; y < em_size[1]; ++y)
+ {
+ for (int z=0; z < em_size[2]; ++z)
+ {
+ index = x + y * em_size_x + z * em_size_xy;
+ em_inf_fields.get(x + min_x, y + min_y, z + min_z) += flow_density * inf[index];//f_x[x],f_y[y],f_z[z]);
+// if(vel != NULL)
+// em_vel_fields.get(x, y, z) = Vec3(vel[index*3],vel[index*3+1],vel[index*3+2]);
+ }
+ }
+ }
+ /*testing grid passing to Python directly*/
+// PyGILState_STATE gilstate = PyGILState_Ensure();
+// PyObject *main = PyImport_AddModule("__main__"); // borrowed
+// if (main == NULL){
+// printf("ERROR: No Main python Module");
+// return;
+// }
+// PyObject *globals = PyModule_GetDict(main); // borrowed
+// PyObject *value = 0;
+// em_inf_fields.registerObject(value, NULL);
+// PyObject *test = 0;
+// test = em_inf_fields.getPyObject();
+// if (value == NULL){
+// printf("ERROR: can't retrieve value");
+// return;
+// }
+// if (PyDict_SetItemString(globals, "source_grid", value) < 0){
+// printf("ERROR: Can't set value");
+// return;
+// }
+// Py_DECREF(value);
+// PyGILState_Release(gilstate);
+ writeGridUni("manta_em_influence.uni", &em_inf_fields);
+ writeGridTxt("manta_em_influence.txt", &em_inf_fields);
+// if (vel != NULL){
+// writeGridUni("em_vel_fields.uni", &em_vel_fields);
+// writeGridTxt("em_vel_fields.txt", &em_vel_fields);
+// }
+}
+
+void export_force_fields(int size_x, int size_y, int size_z, float *f_x, float*f_y, float*f_z)
+{
+ export_fields(size_x, size_y, size_z, f_x, f_y, f_z, "manta_forces.uni");
+}
+
+void runMantaScript(const string& ss,vector<string>& args) {
+ string filename = args[0];
+
+ // Initialize extension classes and wrappers
+ srand(0);
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ /*cleaning possible previous setups*/
+ PyRun_SimpleString(clean_code1.c_str());
+
+ if (! manta_initialized)
+ {
+ debMsg("running manta init?", 0);
+ Pb::setup(filename, args);
+ manta_initialized = true;
+ }
+ // Pass through the command line arguments
+ // for Py3k compatability, convert to wstring
+ vector<pyString> pyArgs(args.size());
+ const pyChar ** cargs = new const pyChar* [args.size()];
+ for (size_t i=0; i<args.size(); i++) {
+ pyArgs[i] = pyString(args[i].begin(), args[i].end());
+ cargs[i] = pyArgs[i].c_str();
+ }
+ PySys_SetArgv( args.size(), (pyChar**) cargs);
+
+ // Try to load python script
+// FILE* fp = fopen(filename.c_str(),"rb");
+// if (fp == NULL) {
+// debMsg("Cannot open '" << filename << "'", 0);
+// Pb::finalize();
+// return;
+// }
+
+ // Run the python script file
+ debMsg("Loading script '" << filename << "'", 0);
+#if defined(WIN32) || defined(_WIN32)
+ // known bug workaround: use simplestring
+ fseek(fp,0,SEEK_END);
+ long filelen=ftell(fp);
+ fseek(fp,0,SEEK_SET);
+ char* buf = new char[filelen+1];
+ fread(buf,filelen,1,fp);
+ buf[filelen] = '\0';
+ fclose(fp);
+ PyRun_SimpleString(buf);
+ delete[] buf;
+#else
+ // for linux, use this as it produces nicer error messages
+ string toExec = "";
+
+ PyRun_SimpleString(ss.c_str());
+// PyRun_SimpleFileEx(fp, filename.c_str(), 0);
+// for (int frame=0; frame < 4; ++frame)
+// {
+// std::string frame_str = static_cast<ostringstream*>( &(ostringstream() << frame) )->str();
+// std::string py_string_0 = string("sim_step(").append(frame_str);
+// std::string py_string_1 = py_string_0.append(")\0");
+// PyRun_SimpleString(py_string_1.c_str());
+// }
+// if (fp != NULL){
+// fclose(fp);
+// }
+#endif
+
+ debMsg("Script finished.", 0);
+#ifdef GUI
+// guiWaitFinish();
+#endif
+
+ // finalize
+// Pb::finalize();
+ PyGILState_Release(gilstate);
+
+ delete [] cargs;
+}
+
+//int manta_main(int argc,char* argv[]) {
+// debMsg("Version: "<< buildInfoString() , 1);
+//
+//#ifdef GUI
+// guiMain(argc, argv);
+//#else
+// if (argc<=1) {
+// cerr << "Usage : Syntax is 'manta <config.py>'" << endl;
+// return 1;
+// }
+//
+// vector<string> args;
+// for (int i=1; i<argc; i++) args.push_back(argv[i]);
+// runMantaScript(args);
+//#endif
+//
+// return 0;
+//}
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_pp/pwrapper/pythonInclude.h b/source/blender/python/manta_pp/pwrapper/pythonInclude.h
new file mode 100755
index 00000000000..127fb92449f
--- /dev/null
+++ b/source/blender/python/manta_pp/pwrapper/pythonInclude.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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>
+
+ #ifdef _DEBUG
+
+ // special handling for windows
+ // disable linking with debug version of python libs
+ #undef _DEBUG
+ #define NDEBUG
+ #include <Python.h>
+ #define _DEBUG
+ #undef NDEBUG
+
+ #else
+ #include <Python.h>
+ #endif
+#else
+ #include <Python.h>
+#endif
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_pp/pwrapper/registry.cpp b/source/blender/python/manta_pp/pwrapper/registry.cpp
new file mode 100644
index 00000000000..183ad9db778
--- /dev/null
+++ b/source/blender/python/manta_pp/pwrapper/registry.cpp
@@ -0,0 +1,681 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * Auto python registry
+ *
+ ******************************************************************************/
+
+#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 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 construct_lite();
+ void cleanup();
+ void renameObjects();
+ void runPreInit();
+ PyObject* initModule();
+ ClassData* lookup(const std::string& name);
+ bool canConvert(ClassData* from, ClassData* to);
+ void addScriptData(const std::string& scriptname, const vector<string>& args);
+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;
+};
+
+//******************************************************************************
+// 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) {
+ // don't delete top-level objects
+ if (self->instance->getParent() != self->instance)
+ delete self->instance;
+ }
+ 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) {
+#if PY_MAJOR_VERSION >= 3
+ WrapperRegistry::instance().construct_lite();
+ return WrapperRegistry::instance().initModule();
+#else
+ WrapperRegistry::instance().construct_lite();
+ WrapperRegistry::instance().initModule();
+#endif
+}
+
+PyMODINIT_FUNC PyInit_Main_Link(void) {
+#if PY_MAJOR_VERSION >= 3
+ return PyInit_Main();
+#else
+ PyInit_Main();
+#endif
+
+}
+
+PyObject *PyInit_Main_Obj(void)
+{
+ return PyInit_Main();
+}
+
+//******************************************************
+// 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::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 CUDA
+ PyModule_AddObject(module,"CUDA",Manta::toPy<bool>(true));
+#else
+ PyModule_AddObject(module,"CUDA",Manta::toPy<bool>(false));
+#endif
+#ifdef DEBUG
+ PyModule_AddObject(module,"DEBUG",Manta::toPy<bool>(true));
+#else
+ PyModule_AddObject(module,"DEBUG",Manta::toPy<bool>(false));
+#endif
+#ifdef 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
+}
+
+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();
+
+ // load main extension module
+ PyImport_AppendInittab((char*)gDefaultModuleName.c_str(), PyInit_Main);
+}
+void WrapperRegistry::addScriptData(const std::string &scriptname, const vector<string> &args)
+{
+ mScriptName = scriptname;
+ this->args = args;
+}
+
+void WrapperRegistry::construct_lite() {
+ registerBaseclasses();
+ registerMeta();
+ registerDummyTypes();
+}
+
+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().addScriptData(filename, args);
+ 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& file, const string& pythonCode) {
+ WrapperRegistry::instance().addPythonCode(file, pythonCode);
+}
+Register::Register(InitFunc func) {
+ WrapperRegistry::instance().addExternalInitializer(func);
+}
+
+} // namespace \ No newline at end of file
diff --git a/source/blender/python/manta_pp/pwrapper/registry.h b/source/blender/python/manta_pp/pwrapper/registry.h
new file mode 100644
index 00000000000..75d5a272f90
--- /dev/null
+++ b/source/blender/python/manta_pp/pwrapper/registry.h
@@ -0,0 +1,87 @@
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011-2014 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
+ *
+ * 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;
+}
+
+// **************************************************
+// 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 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);
+
+// callback type
+typedef void (*InitFunc)(PyObject*);
+extern "C" PyObject *PyInit_Main_Obj(void);
+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 python code
+ Register(const std::string& file, const std::string& pythonCode);
+ //! register external code
+ Register(InitFunc func);
+};
+
+}
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_pp/python/defines.py b/source/blender/python/manta_pp/python/defines.py
new file mode 100644
index 00000000000..1c7f01ab034
--- /dev/null
+++ b/source/blender/python/manta_pp/python/defines.py
@@ -0,0 +1,11 @@
+
+
+
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+
+
+
diff --git a/source/blender/python/manta_pp/python/defines.py.reg b/source/blender/python/manta_pp/python/defines.py.reg
new file mode 100644
index 00000000000..6ef1bc7fceb
--- /dev/null
+++ b/source/blender/python/manta_pp/python/defines.py.reg
@@ -0,0 +1,2 @@
+#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# GNU General Public License (GPL) \n# http://www.gnu.org/licenses\n#\n# Defines some constants for use in python subprograms\n#\n#################################################################################\n\n# mantaflow conventions\nReal = float\n\n# grid flags\nFlagFluid = 1\nFlagObstacle = 2\nFlagEmpty = 4\nFlagStick = 128\nFlagReserved = 256\n\n# integration mode\nIntEuler = 0\nIntRK2 = 1\nIntRK4 = 2\n\n\n\n");
diff --git a/source/blender/python/manta_pp/python/defines.py.reg.cpp b/source/blender/python/manta_pp/python/defines.py.reg.cpp
new file mode 100644
index 00000000000..6ef1bc7fceb
--- /dev/null
+++ b/source/blender/python/manta_pp/python/defines.py.reg.cpp
@@ -0,0 +1,2 @@
+#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# GNU General Public License (GPL) \n# http://www.gnu.org/licenses\n#\n# Defines some constants for use in python subprograms\n#\n#################################################################################\n\n# mantaflow conventions\nReal = float\n\n# grid flags\nFlagFluid = 1\nFlagObstacle = 2\nFlagEmpty = 4\nFlagStick = 128\nFlagReserved = 256\n\n# integration mode\nIntEuler = 0\nIntRK2 = 1\nIntRK4 = 2\n\n\n\n");
diff --git a/source/blender/python/manta_pp/shapes.cpp b/source/blender/python/manta_pp/shapes.cpp
new file mode 100644
index 00000000000..6210f4c4ec3
--- /dev/null
+++ b/source/blender/python/manta_pp/shapes.cpp
@@ -0,0 +1,394 @@
+
+
+
+
+
+// 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
+ *
+ * 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) { run(); } inline void op(int i, int j, int k, Grid<T>* grid, Shape* shape, T value, FlagGrid* respectFlags ) {
+ 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 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, grid,shape,value,respectFlags); } 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) { run(); } inline void op(int i, int j, int k, Grid<T>* grid, Grid<Real>& phi, Real sigma, Real shift, T value, FlagGrid* respectFlags ) {
+ 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 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, grid,phi,sigma,shift,value,respectFlags); } 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) { run(); } inline void op(int i, int j, int k, MACGrid* grid, Shape* shape, Vec3 value, FlagGrid* respectFlags ) {
+ 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 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, grid,shape,value,respectFlags); } MACGrid* grid; Shape* shape; Vec3 value; FlagGrid* respectFlags; };
+
+void Shape::applyToGrid(GridBase* grid, FlagGrid* respectFlags) {
+ 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");
+}
+
+void Shape::applyToGridSmooth(GridBase* grid, Real sigma, Real shift, FlagGrid* respectFlags) {
+ Grid<Real> phi(grid->getParent());
+ generateLevelset(phi);
+
+ 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");
+}
+
+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) { run(); } inline void op(int i, int j, int k, Grid<Real>& phi, const Vec3& p1, const Vec3& p2 ) {
+ 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);
+ 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 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,p1,p2); } 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) { run(); } inline void op(int i, int j, int k, Grid<Real>& phi, Vec3 center, Real radius, Vec3 scale ) {
+ 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 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,center,radius,scale); } 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) { run(); } inline void op(int i, int j, int k, Grid<Real>& phi, Vec3 center, Real radius, Vec3 zaxis, Real maxz ) {
+ 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 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,center,radius,zaxis,maxz); } Grid<Real>& phi; Vec3 center; Real radius; Vec3 zaxis; Real maxz; };
+void Cylinder::generateLevelset(Grid<Real>& phi) {
+ CylinderSDF(phi, mCenter, mRadius, mZDir, mZ);
+}
+
+} //namespace
+
+
diff --git a/source/blender/python/manta_pp/shapes.h b/source/blender/python/manta_pp/shapes.h
new file mode 100644
index 00000000000..b5f003985ba
--- /dev/null
+++ b/source/blender/python/manta_pp/shapes.h
@@ -0,0 +1,142 @@
+
+
+
+
+
+// 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
+ *
+ * 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 };
+
+ 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); pbPreparePlugin(0, "Shape::Shape" ); { 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" ); 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)); pbPreparePlugin(pbo->getParent(), "Shape::applyToGrid"); 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"); 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)); pbPreparePlugin(pbo->getParent(), "Shape::applyToGridSmooth"); 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"); 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)); pbPreparePlugin(pbo->getParent(), "Shape::computeLevelset"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->computeLevelset()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Shape::computeLevelset"); 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)); pbPreparePlugin(pbo->getParent(), "Shape::collideMesh"); 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"); 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)); pbPreparePlugin(pbo->getParent(), "Shape::getCenter"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getCenter()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Shape::getCenter"); 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)); pbPreparePlugin(pbo->getParent(), "Shape::setCenter"); 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"); 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)); pbPreparePlugin(pbo->getParent(), "Shape::getExtent"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = toPy(pbo->getExtent()); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Shape::getExtent"); 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); pbPreparePlugin(0, "NullShape::NullShape" ); { 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" ); 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); pbPreparePlugin(0, "Box::Box" ); { 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" ); 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); pbPreparePlugin(0, "Sphere::Sphere" ); { 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" ); 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); pbPreparePlugin(0, "Cylinder::Cylinder" ); { 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" ); 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)); pbPreparePlugin(pbo->getParent(), "Cylinder::setRadius"); 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"); 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)); pbPreparePlugin(pbo->getParent(), "Cylinder::setZ"); 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"); 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
+;
+
+
+
+} //namespace
+#endif
+
+
diff --git a/source/blender/python/manta_pp/shapes.h.reg b/source/blender/python/manta_pp/shapes.h.reg
new file mode 100644
index 00000000000..019a2bd40f8
--- /dev/null
+++ b/source/blender/python/manta_pp/shapes.h.reg
@@ -0,0 +1,25 @@
+#include "shapes.h"
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","Shape","PbClass"); template<> const char* Namify<Shape >::S = "Shape";
+>Shape^
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","Shape",Shape::_W_0);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","applyToGrid",Shape::_W_1);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","applyToGridSmooth",Shape::_W_2);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","computeLevelset",Shape::_W_3);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","collideMesh",Shape::_W_4);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","getCenter",Shape::_W_5);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","setCenter",Shape::_W_6);
++Shape^ static const Pb::Register _R_$IDX$ ("Shape","getExtent",Shape::_W_7);
++NullShape^ static const Pb::Register _R_$IDX$ ("NullShape","NullShape","Shape"); template<> const char* Namify<NullShape >::S = "NullShape";
+>NullShape^
++NullShape^ static const Pb::Register _R_$IDX$ ("NullShape","NullShape",NullShape::_W_8);
++Box^ static const Pb::Register _R_$IDX$ ("Box","Box","Shape"); template<> const char* Namify<Box >::S = "Box";
+>Box^
++Box^ static const Pb::Register _R_$IDX$ ("Box","Box",Box::_W_9);
++Sphere^ static const Pb::Register _R_$IDX$ ("Sphere","Sphere","Shape"); template<> const char* Namify<Sphere >::S = "Sphere";
+>Sphere^
++Sphere^ static const Pb::Register _R_$IDX$ ("Sphere","Sphere",Sphere::_W_10);
++Cylinder^ static const Pb::Register _R_$IDX$ ("Cylinder","Cylinder","Shape"); template<> const char* Namify<Cylinder >::S = "Cylinder";
+>Cylinder^
++Cylinder^ static const Pb::Register _R_$IDX$ ("Cylinder","Cylinder",Cylinder::_W_11);
++Cylinder^ static const Pb::Register _R_$IDX$ ("Cylinder","setRadius",Cylinder::_W_12);
++Cylinder^ static const Pb::Register _R_$IDX$ ("Cylinder","setZ",Cylinder::_W_13);
diff --git a/source/blender/python/manta_pp/shapes.h.reg.cpp b/source/blender/python/manta_pp/shapes.h.reg.cpp
new file mode 100644
index 00000000000..af287c0821f
--- /dev/null
+++ b/source/blender/python/manta_pp/shapes.h.reg.cpp
@@ -0,0 +1,43 @@
+
+
+
+
+
+// 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_0 ("Box","Box","Shape"); template<> const char* Namify<Box >::S = "Box";
+ static const Pb::Register _R_1 ("Box","Box",Box::_W_9);
+#endif
+#ifdef _C_Cylinder
+ static const Pb::Register _R_2 ("Cylinder","Cylinder","Shape"); template<> const char* Namify<Cylinder >::S = "Cylinder";
+ static const Pb::Register _R_3 ("Cylinder","Cylinder",Cylinder::_W_11);
+ static const Pb::Register _R_4 ("Cylinder","setRadius",Cylinder::_W_12);
+ static const Pb::Register _R_5 ("Cylinder","setZ",Cylinder::_W_13);
+#endif
+#ifdef _C_NullShape
+ static const Pb::Register _R_6 ("NullShape","NullShape","Shape"); template<> const char* Namify<NullShape >::S = "NullShape";
+ static const Pb::Register _R_7 ("NullShape","NullShape",NullShape::_W_8);
+#endif
+#ifdef _C_Shape
+ static const Pb::Register _R_8 ("Shape","Shape","PbClass"); template<> const char* Namify<Shape >::S = "Shape";
+ static const Pb::Register _R_9 ("Shape","Shape",Shape::_W_0);
+ static const Pb::Register _R_10 ("Shape","applyToGrid",Shape::_W_1);
+ static const Pb::Register _R_11 ("Shape","applyToGridSmooth",Shape::_W_2);
+ static const Pb::Register _R_12 ("Shape","computeLevelset",Shape::_W_3);
+ static const Pb::Register _R_13 ("Shape","collideMesh",Shape::_W_4);
+ static const Pb::Register _R_14 ("Shape","getCenter",Shape::_W_5);
+ static const Pb::Register _R_15 ("Shape","setCenter",Shape::_W_6);
+ static const Pb::Register _R_16 ("Shape","getExtent",Shape::_W_7);
+#endif
+#ifdef _C_Sphere
+ static const Pb::Register _R_17 ("Sphere","Sphere","Shape"); template<> const char* Namify<Sphere >::S = "Sphere";
+ static const Pb::Register _R_18 ("Sphere","Sphere",Sphere::_W_10);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/test.cpp b/source/blender/python/manta_pp/test.cpp
new file mode 100644
index 00000000000..3eb5467a65f
--- /dev/null
+++ b/source/blender/python/manta_pp/test.cpp
@@ -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
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * Use this file to test new functionality
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "commonkernels.h"
+#include "particle.h"
+#include <cmath>
+
+using namespace std;
+
+namespace Manta {
+
+
+
+template <class S> void addToGrid(Grid<S>& a, S v) {
+ FOR_IDX(a) a[idx] += v;
+}template <class S> static PyObject* _W_T_0 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "addToGrid" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<S>& a = *_args.getPtr<Grid<S> >("a",0,&_lock); S v = _args.get<S >("v",1,&_lock); _retval = getPyNone(); addToGrid(a,v); _args.check(); } pbFinalizePlugin(parent,"addToGrid" ); return _retval; } catch(std::exception& e) { pbSetError("addToGrid",e.what()); return 0; } }template <class S> static bool _K_0 (PbArgs& A) { return A.typeCheck<Grid<S> >(0,"a") && A.typeCheck<S >(1,"v"); }static PyObject* _W_0 (PyObject* s, PyObject* l, PyObject* kw) { PbArgs args(l, kw); int hits=0; PyObject* (*call)(PyObject*,PyObject*,PyObject*); if (_K_0<int>(args)) {hits++; call = _W_T_0<int>; }if (_K_0<Real>(args)) {hits++; call = _W_T_0<Real>; }if (_K_0<Vec3>(args)) {hits++; call = _W_T_0<Vec3>; } if (hits == 1) return call(s,l,kw); if (hits == 0) pbSetError("addToGrid", "Can't deduce template parameters"); else pbSetError("addToGrid", "Argument matches multiple templates"); return 0 ; } static const Pb::Register _RP_addToGrid ("","addToGrid",_W_0);
+
+
+//! Kernel: get component (not shifted)
+/*KERNEL(idx) returns(Grid<Real> ret(parent))
+Grid<Real> GetComponent2(const Grid<Vec3>& grid, int dim) {
+ ret[idx] = grid[idx][dim];
+};
+
+PYTHON void testp(Grid<Vec3>& b) {
+ Grid<Real> d(b.getParent());
+ b(20,20,20) = Vec3(21,22,23);
+ {
+ cout <<"middle" << endl;
+ Grid<Real> a = GetComponent2(b,0);
+ cout << a(20,20,20) << endl;
+ cout <<"middle" << endl;
+ }
+ cout << "end" << endl;errMsg("f");
+}
+*/
+
+
+
+ struct ddtest : public KernelBase { ddtest(const Grid<Real>& v) : KernelBase(&v,0) ,v(v) ,sum(0) { run(); } inline void op(int 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, v,sum); } const Grid<Real>& v; double sum; };
+
+
+
+ struct detest : public KernelBase { detest(const Grid<Real>& v) : KernelBase(&v,0) ,v(v) ,sum(0) { run(); } inline void op(int 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, v,sum); } const Grid<Real>& v; double sum; };
+
+void checkGrids(Grid<int>& flags1, Grid<int>& flags2, Grid<Real>& phi1, Grid<Real>& phi2, Grid<Vec3>& vel1, Grid<Vec3>& vel2) {
+ FOR_IJK(flags1) {
+ assertMsg(flags1(i,j,k) == flags2(i,j,k), "flags mismatch");
+ assertMsg(norm(vel1(i,j,k)-vel2(i,j,k)) < 1e-1, "vel mismatch");
+ assertMsg( fabs(phi1(i,j,k)-phi2(i,j,k)) < 1e-4, "phi mismatch");
+ }
+} static PyObject* _W_1 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "checkGrids" ); PyObject *_retval = 0; { ArgLocker _lock; Grid<int>& flags1 = *_args.getPtr<Grid<int> >("flags1",0,&_lock); Grid<int>& flags2 = *_args.getPtr<Grid<int> >("flags2",1,&_lock); Grid<Real>& phi1 = *_args.getPtr<Grid<Real> >("phi1",2,&_lock); Grid<Real>& phi2 = *_args.getPtr<Grid<Real> >("phi2",3,&_lock); Grid<Vec3>& vel1 = *_args.getPtr<Grid<Vec3> >("vel1",4,&_lock); Grid<Vec3>& vel2 = *_args.getPtr<Grid<Vec3> >("vel2",5,&_lock); _retval = getPyNone(); checkGrids(flags1,flags2,phi1,phi2,vel1,vel2); _args.check(); } pbFinalizePlugin(parent,"checkGrids" ); return _retval; } catch(std::exception& e) { pbSetError("checkGrids",e.what()); return 0; } } static const Pb::Register _RP_checkGrids ("","checkGrids",_W_1);
+
+
+struct myvec {
+ myvec(int n) : x(n) { cout << "constructor" << endl; };
+ myvec(const myvec& a) : x(a.x) { cout << "copy constructor" << endl; }
+ myvec& operator=(const myvec& a) { x=a.x; cout << "copy operator" << endl; return *this;}
+ int& operator[](int idx) { return x[idx]; }
+
+ vector<int> x;
+};
+
+
+ struct testy : public KernelBase { testy(vector<int>& a) : KernelBase(a.size()) ,a(a) ,vec((size)) { run(); } inline void op(int idx, vector<int>& a ,myvec& vec) {
+ vec[idx] = a[idx];
+} inline operator myvec () { return vec; } inline myvec & getRet() { return vec; } inline vector<int>& getArg0() { return a; } typedef vector<int> type0; void run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, a,vec); } vector<int>& a; myvec vec; };
+
+void kernelTest() {
+ cout << "kernel test" << endl;
+ vector<int> a(10);
+ for (int i=0;i<10;i++) a[i]=i;
+
+ //testy xx(a);
+ myvec b = testy(a);
+ for (int i=0;i<10;i++) cout << b[i] << endl;
+ cout << "kernel end" << endl;
+} static PyObject* _W_2 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "kernelTest" ); PyObject *_retval = 0; { ArgLocker _lock; _retval = getPyNone(); kernelTest(); _args.check(); } pbFinalizePlugin(parent,"kernelTest" ); return _retval; } catch(std::exception& e) { pbSetError("kernelTest",e.what()); return 0; } } static const Pb::Register _RP_kernelTest ("","kernelTest",_W_2);
+
+void getCurl(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_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "getCurl" ); PyObject *_retval = 0; { ArgLocker _lock; 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" ); return _retval; } catch(std::exception& e) { pbSetError("getCurl",e.what()); return 0; } } static const Pb::Register _RP_getCurl ("","getCurl",_W_3);
+
+void setinflow(FlagGrid& flags, MACGrid& vel, LevelsetGrid& phi, Real h) {
+ FOR_IJK(vel) {
+ if (i<=2) {
+ if (j < h*flags.getSizeY()) {
+ vel(i,j,k).x = 1;
+ if (!flags.isObstacle(i,j,k)) {
+ flags(i,j,k) = 1;
+ phi(i,j,k) = -1;
+ }
+ } else {
+ vel(i,j,k).x = 0;
+ if (!flags.isObstacle(i,j,k)) {
+ flags(i,j,k) = 4;
+ phi(i,j,k) = 1;
+ }
+ }
+ }
+ else if (i>=flags.getSizeX()-2) {
+ vel(i,j,k).x = 1;
+ /*if (j < 30-12) {
+ vel(i,j,k).x = 1;
+ if (!flags.isObstacle(i,j,k)) {
+ flags(i,j,k) = 1;
+ phi(i,j,k) = -1;
+ }
+ } else {
+ vel(i,j,k).x = 0;
+ if (!flags.isObstacle(i,j,k)) {
+ flags(i,j,k) = 4;
+ phi(i,j,k) = 1;
+ }
+ }*/
+ }
+ }
+} static PyObject* _W_4 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "setinflow" ); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid& flags = *_args.getPtr<FlagGrid >("flags",0,&_lock); MACGrid& vel = *_args.getPtr<MACGrid >("vel",1,&_lock); LevelsetGrid& phi = *_args.getPtr<LevelsetGrid >("phi",2,&_lock); Real h = _args.get<Real >("h",3,&_lock); _retval = getPyNone(); setinflow(flags,vel,phi,h); _args.check(); } pbFinalizePlugin(parent,"setinflow" ); return _retval; } catch(std::exception& e) { pbSetError("setinflow",e.what()); return 0; } } static const Pb::Register _RP_setinflow ("","setinflow",_W_4);
+
+void testDiscardNth(BasicParticleSystem& parts, int skip=1) {
+ //knSetPdataConst<Real>(pd,value);
+ for(int i=0; i<parts.size(); ++i) {
+ if(i%(skip+1) == skip) { // keep
+ } else {
+ parts.setPos(i, Vec3(-100000) );
+ }
+ }
+} static PyObject* _W_5 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); pbPreparePlugin(parent, "testDiscardNth" ); PyObject *_retval = 0; { ArgLocker _lock; BasicParticleSystem& parts = *_args.getPtr<BasicParticleSystem >("parts",0,&_lock); int skip = _args.getOpt<int >("skip",1,1,&_lock); _retval = getPyNone(); testDiscardNth(parts,skip); _args.check(); } pbFinalizePlugin(parent,"testDiscardNth" ); return _retval; } catch(std::exception& e) { pbSetError("testDiscardNth",e.what()); return 0; } } static const Pb::Register _RP_testDiscardNth ("","testDiscardNth",_W_5);
+
+} //namespace
+
+
+
diff --git a/source/blender/python/manta_pp/timing.cpp b/source/blender/python/manta_pp/timing.cpp
new file mode 100644
index 00000000000..e421d7e689f
--- /dev/null
+++ b/source/blender/python/manta_pp/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
+ * GNU General Public License (GPL)
+ * http://www.gnu.org/licenses
+ *
+ * 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();
+}
+
+}
+
+
+
diff --git a/source/blender/python/manta_pp/timing.h b/source/blender/python/manta_pp/timing.h
new file mode 100644
index 00000000000..0aa0714523a
--- /dev/null
+++ b/source/blender/python/manta_pp/timing.h
@@ -0,0 +1,72 @@
+
+
+
+
+
+// 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
+ *
+ * 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); pbPreparePlugin(0, "Timings::Timings" ); { ArgLocker _lock; obj = new Timings(); obj->registerObject(_self, &_args); _args.check(); } pbFinalizePlugin(obj->getParent(),"Timings::Timings" ); 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)); pbPreparePlugin(pbo->getParent(), "Timings::display"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->display(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"Timings::display"); 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)); pbPreparePlugin(pbo->getParent(), "Timings::saveMean"); 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"); return _retval; } catch(std::exception& e) { pbSetError("Timings::saveMean",e.what()); return 0; } } public: PbArgs _args;}
+#define _C_Timings
+;
+
+}
+
+#endif
+
+
diff --git a/source/blender/python/manta_pp/timing.h.reg b/source/blender/python/manta_pp/timing.h.reg
new file mode 100644
index 00000000000..4a653bf381d
--- /dev/null
+++ b/source/blender/python/manta_pp/timing.h.reg
@@ -0,0 +1,6 @@
+#include "timing.h"
++Timings^ static const Pb::Register _R_$IDX$ ("Timings","Timings","PbClass"); template<> const char* Namify<Timings >::S = "Timings";
+>Timings^
++Timings^ static const Pb::Register _R_$IDX$ ("Timings","Timings",Timings::_W_0);
++Timings^ static const Pb::Register _R_$IDX$ ("Timings","display",Timings::_W_1);
++Timings^ static const Pb::Register _R_$IDX$ ("Timings","saveMean",Timings::_W_2);
diff --git a/source/blender/python/manta_pp/timing.h.reg.cpp b/source/blender/python/manta_pp/timing.h.reg.cpp
new file mode 100644
index 00000000000..f4151a3e9cd
--- /dev/null
+++ b/source/blender/python/manta_pp/timing.h.reg.cpp
@@ -0,0 +1,20 @@
+
+
+
+
+
+// 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_0 ("Timings","Timings","PbClass"); template<> const char* Namify<Timings >::S = "Timings";
+ static const Pb::Register _R_1 ("Timings","Timings",Timings::_W_0);
+ static const Pb::Register _R_2 ("Timings","display",Timings::_W_1);
+ static const Pb::Register _R_3 ("Timings","saveMean",Timings::_W_2);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/turbulencepart.cpp b/source/blender/python/manta_pp/turbulencepart.cpp
new file mode 100644
index 00000000000..796c1417fb1
--- /dev/null
+++ b/source/blender/python/manta_pp/turbulencepart.cpp
@@ -0,0 +1,154 @@
+
+
+
+
+
+// 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.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) { run(); } inline void op(int idx, TurbulenceParticleSystem& p, FlagGrid& flags, WaveletNoiseField& noise, Grid<Real>& kGrid, Real alpha, Real dt, int octaves, Real scale, Real invL0, Real kmin ) {
+ 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, p,flags,noise,kGrid,alpha,dt,octaves,scale,invL0,kmin); } 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
+
+
diff --git a/source/blender/python/manta_pp/turbulencepart.h b/source/blender/python/manta_pp/turbulencepart.h
new file mode 100644
index 00000000000..4ffb5f89446
--- /dev/null
+++ b/source/blender/python/manta_pp/turbulencepart.h
@@ -0,0 +1,64 @@
+
+
+
+
+
+// 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
+ *
+ * Turbulence particles
+ *
+ ******************************************************************************/
+
+#ifndef _TURBULENCEPART_H_
+#define _TURBULENCEPART_H_
+
+#include "particle.h"
+#include "noisefield.h"
+
+namespace Manta {
+class Shape;
+
+
+
+struct TurbulenceParticleData {
+ TurbulenceParticleData() : pos(_0),color(1.),tex0(_0),tex1(_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); pbPreparePlugin(0, "TurbulenceParticleSystem::TurbulenceParticleSystem" ); { 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" ); 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)); pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::resetTexCoords"); 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"); 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)); pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::seed"); 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"); 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); static PyObject* _W_3 (PyObject* _self, PyObject* _linargs, PyObject* _kwds) { try { PbArgs _args(_linargs, _kwds); TurbulenceParticleSystem* pbo = dynamic_cast<TurbulenceParticleSystem*>(Pb::objFromPy(_self)); pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::synthesize"); 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,&_lock); pbo->_args.copy(_args); _retval = getPyNone(); pbo->synthesize(flags,k,octaves,switchLength,L0,scale,inflowBias); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"TurbulenceParticleSystem::synthesize"); 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)); pbPreparePlugin(pbo->getParent(), "TurbulenceParticleSystem::deleteInObstacle"); 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"); 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
+
+
+#endif
+
diff --git a/source/blender/python/manta_pp/turbulencepart.h.reg b/source/blender/python/manta_pp/turbulencepart.h.reg
new file mode 100644
index 00000000000..f28cd70f4a3
--- /dev/null
+++ b/source/blender/python/manta_pp/turbulencepart.h.reg
@@ -0,0 +1,9 @@
+#include "turbulencepart.h"
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","TurbulenceParticleSystem","ParticleSystem<$BT$>"); template<> const char* Namify<TurbulenceParticleSystem >::S = "TurbulenceParticleSystem";
+>TurbulenceParticleSystem^
+@TurbulenceParticleSystem^^ParticleSystem^TurbulenceParticleData
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","TurbulenceParticleSystem",TurbulenceParticleSystem::_W_0);
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","resetTexCoords",TurbulenceParticleSystem::_W_1);
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","seed",TurbulenceParticleSystem::_W_2);
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","synthesize",TurbulenceParticleSystem::_W_3);
++TurbulenceParticleSystem^ static const Pb::Register _R_$IDX$ ("TurbulenceParticleSystem","deleteInObstacle",TurbulenceParticleSystem::_W_4);
diff --git a/source/blender/python/manta_pp/turbulencepart.h.reg.cpp b/source/blender/python/manta_pp/turbulencepart.h.reg.cpp
new file mode 100644
index 00000000000..04a1a422ea8
--- /dev/null
+++ b/source/blender/python/manta_pp/turbulencepart.h.reg.cpp
@@ -0,0 +1,34 @@
+
+
+
+
+
+// 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_0 ("ParticleSystem<TurbulenceParticleData>","ParticleSystem<TurbulenceParticleData>","ParticleBase"); template<> const char* Namify<ParticleSystem<TurbulenceParticleData> >::S = "ParticleSystem<TurbulenceParticleData>";
+ static const Pb::Register _R_1 ("ParticleSystem<TurbulenceParticleData>","ParticleSystem",ParticleSystem<TurbulenceParticleData>::_W_2);
+ static const Pb::Register _R_2 ("ParticleSystem<TurbulenceParticleData>","size",ParticleSystem<TurbulenceParticleData>::_W_3);
+ static const Pb::Register _R_3 ("ParticleSystem<TurbulenceParticleData>","setPos",ParticleSystem<TurbulenceParticleData>::_W_4);
+ static const Pb::Register _R_4 ("ParticleSystem<TurbulenceParticleData>","getPos",ParticleSystem<TurbulenceParticleData>::_W_5);
+ static const Pb::Register _R_5 ("ParticleSystem<TurbulenceParticleData>","getPosPdata",ParticleSystem<TurbulenceParticleData>::_W_6);
+ static const Pb::Register _R_6 ("ParticleSystem<TurbulenceParticleData>","setPosPdata",ParticleSystem<TurbulenceParticleData>::_W_7);
+ static const Pb::Register _R_7 ("ParticleSystem<TurbulenceParticleData>","clear",ParticleSystem<TurbulenceParticleData>::_W_8);
+ static const Pb::Register _R_8 ("ParticleSystem<TurbulenceParticleData>","advectInGrid",ParticleSystem<TurbulenceParticleData>::_W_9);
+ static const Pb::Register _R_9 ("ParticleSystem<TurbulenceParticleData>","projectOutside",ParticleSystem<TurbulenceParticleData>::_W_10);
+#endif
+#ifdef _C_TurbulenceParticleSystem
+ static const Pb::Register _R_10 ("TurbulenceParticleSystem","TurbulenceParticleSystem","ParticleSystem<TurbulenceParticleData>"); template<> const char* Namify<TurbulenceParticleSystem >::S = "TurbulenceParticleSystem";
+ static const Pb::Register _R_11 ("TurbulenceParticleSystem","TurbulenceParticleSystem",TurbulenceParticleSystem::_W_0);
+ static const Pb::Register _R_12 ("TurbulenceParticleSystem","resetTexCoords",TurbulenceParticleSystem::_W_1);
+ static const Pb::Register _R_13 ("TurbulenceParticleSystem","seed",TurbulenceParticleSystem::_W_2);
+ static const Pb::Register _R_14 ("TurbulenceParticleSystem","synthesize",TurbulenceParticleSystem::_W_3);
+ static const Pb::Register _R_15 ("TurbulenceParticleSystem","deleteInObstacle",TurbulenceParticleSystem::_W_4);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/util/integrator.h b/source/blender/python/manta_pp/util/integrator.h
new file mode 100644
index 00000000000..378a890c0ab
--- /dev/null
+++ b/source/blender/python/manta_pp/util/integrator.h
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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 + (_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
+
+#endif \ No newline at end of file
diff --git a/source/blender/python/manta_pp/util/interpol.h b/source/blender/python/manta_pp/util/interpol.h
new file mode 100644
index 00000000000..073df798ffa
--- /dev/null
+++ b/source/blender/python/manta_pp/util/interpol.h
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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, int idx) {
+ if (idx<0 || idx > 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
+ int idx = xi + Y * yi + 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
+ int idx = xi + Y * yi + 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
+ int idx = xi + Y * yi + 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*size.y+yi)*size.x+xi));
+ DEBUG_ONLY(checkIndexInterpol(size,(s_zi*size.y+s_yi)*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*size.y+yi)*size.x+xi));
+ DEBUG_ONLY(checkIndexInterpol(size,(s_zi*size.y+s_yi)*size.x+s_xi+X+Y+Z));
+
+ // process individual components
+ { // X
+ const int idx = (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 int idx = (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 int idx = (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
+
+#endif
diff --git a/source/blender/python/manta_pp/util/interpolHigh.h b/source/blender/python/manta_pp/util/interpolHigh.h
new file mode 100644
index 00000000000..6778e5f7d27
--- /dev/null
+++ b/source/blender/python/manta_pp/util/interpolHigh.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Helper functions for higher order interpolation
+ *
+ ******************************************************************************/
+
+#ifndef _INTERPOLHIGH_H
+#define _INTERPOLHIGH_H
+
+#include "vectorbase.h"
+
+namespace Manta {
+
+// copied from interpol.h
+#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 interpolCubic(const T* data, const Vec3i& size, const int Z, const Vec3& pos) {
+ BUILD_INDEX
+ int idx = xi + Y * yi + 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;
+}
+
+#undef BUILD_INDEX
+
+} //namespace
+
+#endif
+
+
diff --git a/source/blender/python/manta_pp/util/mcubes.h b/source/blender/python/manta_pp/util/mcubes.h
new file mode 100644
index 00000000000..39bd5970791
--- /dev/null
+++ b/source/blender/python/manta_pp/util/mcubes.h
@@ -0,0 +1,323 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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/source/blender/python/manta_pp/util/quaternion.h b/source/blender/python/manta_pp/util/quaternion.h
new file mode 100644
index 00000000000..1808bb582a6
--- /dev/null
+++ b/source/blender/python/manta_pp/util/quaternion.h
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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
+
+#endif
diff --git a/source/blender/python/manta_pp/util/randomstream.h b/source/blender/python/manta_pp/util/randomstream.h
new file mode 100644
index 00000000000..23380a4c10f
--- /dev/null
+++ b/source/blender/python/manta_pp/util/randomstream.h
@@ -0,0 +1,377 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Random numbers
+ *
+ * Based on GPL code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
+ * Richard J. Wagner v0.5 7 November 2000 rjwagner@writeme.com
+ *
+ ******************************************************************************/
+
+#ifndef _RANDOMSTREAM_H
+#define _RANDOMSTREAM_H
+
+namespace Manta {
+
+#include <iostream>
+#include <limits.h>
+#include <stdio.h>
+#include <time.h>
+#include <math.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;
+
+ register 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;
+ register int i = 1;
+ register uint32 j = 0;
+ register 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];
+ register uint32 *s = bigSeed;
+ register int i = N;
+ register 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.
+ register uint32 *s = state;
+ register uint32 *r = state;
+ register 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)
+ register uint32 *p = state;
+ register 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
+{
+ register uint32 *sa = saveArray;
+ register const uint32 *s = state;
+ register int i = N;
+ for( ; i--; *sa++ = *s++ ) {}
+ *sa = left;
+}
+
+
+inline void MTRand::load( uint32 *const loadArray )
+{
+ register uint32 *s = state;
+ register uint32 *la = loadArray;
+ register int i = N;
+ for( ; i--; *s++ = *la++ ) {}
+ left = *la;
+ pNext = &state[N-left];
+}
+
+
+inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )
+{
+ register const MTRand::uint32 *s = mtrand.state;
+ register int i = mtrand.N;
+ for( ; i--; os << *s++ << "\t" ) {}
+ return os << mtrand.left;
+}
+
+
+inline std::istream& operator>>( std::istream& is, MTRand& mtrand )
+{
+ register MTRand::uint32 *s = mtrand.state;
+ register 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
+
+#endif
diff --git a/source/blender/python/manta_pp/util/solvana.h b/source/blender/python/manta_pp/util/solvana.h
new file mode 100644
index 00000000000..c9c8167bceb
--- /dev/null
+++ b/source/blender/python/manta_pp/util/solvana.h
@@ -0,0 +1,176 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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/source/blender/python/manta_pp/util/vectorbase.cpp b/source/blender/python/manta_pp/util/vectorbase.cpp
new file mode 100644
index 00000000000..5f7dee46f59
--- /dev/null
+++ b/source/blender/python/manta_pp/util/vectorbase.cpp
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * Basic vector class
+ *
+ ******************************************************************************/
+
+#include "vectorbase.h"
+#include <limits>
+#include <math.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<> const Vector3D<int> Vector3D<int>::Invalid( -1, -1, -1 );
+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); }
+//template<> bool Vector3D<int>::isValid() const { return x!=-1 || y!=-1 || z!=-1; }
+
+
+
+
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/util/vectorbase.h b/source/blender/python/manta_pp/util/vectorbase.h
new file mode 100644
index 00000000000..6f24a299eb9
--- /dev/null
+++ b/source/blender/python/manta_pp/util/vectorbase.h
@@ -0,0 +1,585 @@
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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 <stdlib.h>
+#include <string>
+#include <cmath>
+#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 FP_REAL_MAX __FLT_MAX__
+# define VECTOR_EPSILON (1e-6f)
+# define _0 0.0f
+# define _1 1.0f
+#else
+ typedef double Real;
+# define FP_REAL_MAX __DBL_MAX__
+# define VECTOR_EPSILON (1e-10)
+# define _0 0.0
+# define _1 1.0
+#endif
+
+// windos, 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
+# 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 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;
+
+protected:
+
+};
+
+//************************************************************************
+// 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
+//************************************************************************
+
+//! 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
+template<class S>
+inline S norm ( const Vector3D<S>& v ) {
+ S l = v.x*v.x + v.y*v.y + v.z*v.z;
+ 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;
+}
+
+//! 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 );
+}
+
+//! 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
+
+
+#endif
diff --git a/source/blender/python/manta_pp/vortexpart.cpp b/source/blender/python/manta_pp/vortexpart.cpp
new file mode 100644
index 00000000000..32e2fd2053e
--- /dev/null
+++ b/source/blender/python/manta_pp/vortexpart.cpp
@@ -0,0 +1,109 @@
+
+
+
+
+
+// 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
+ *
+ * Vortex particles
+ *
+ ******************************************************************************/
+
+#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);
+ 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(vector<Node>& nodes, const vector<VortexParticleData>& vp, Real scale) : KernelBase(nodes.size()) ,nodes(nodes),vp(vp),scale(scale) ,u((size)) { run(); } inline void op(int idx, vector<Node>& nodes, const vector<VortexParticleData>& vp, Real scale ,vector<Vec3> & u) {
+ if (nodes[idx].flags & Mesh::NfFixed)
+ u[idx] = _0;
+ else
+ u[idx] = VortexKernel(nodes[idx].pos, vp, scale);
+} 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, nodes,vp,scale,u); } vector<Node>& nodes; const vector<VortexParticleData>& vp; Real scale; vector<Vec3> u; };
+
+
+ struct KnVpAdvectSelf : public KernelBase { KnVpAdvectSelf(vector<VortexParticleData>& vp, Real scale) : KernelBase(vp.size()) ,vp(vp),scale(scale) ,u((size)) { run(); } inline void op(int idx, vector<VortexParticleData>& vp, Real scale ,vector<Vec3> & u) {
+ if (vp[idx].flag & ParticleBase::PDELETE)
+ u[idx] = _0;
+ else
+ u[idx] = VortexKernel(vp[idx].pos, vp, scale);
+} 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 run() { const int _sz = size; for (int i=0; i < _sz; i++) op(i, vp,scale,u); } 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
+
+
diff --git a/source/blender/python/manta_pp/vortexpart.h b/source/blender/python/manta_pp/vortexpart.h
new file mode 100644
index 00000000000..47880678163
--- /dev/null
+++ b/source/blender/python/manta_pp/vortexpart.h
@@ -0,0 +1,56 @@
+
+
+
+
+
+// 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
+ *
+ * Vortex particles
+ *
+ ******************************************************************************/
+
+#ifndef _VORTEXPART_H
+#define _VORTEXPART_H
+
+#include "particle.h"
+
+namespace Manta {
+class Mesh;
+
+struct VortexParticleData {
+ VortexParticleData() : pos(_0),vorticity(_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); pbPreparePlugin(0, "VortexParticleSystem::VortexParticleSystem" ); { 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" ); 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)); pbPreparePlugin(pbo->getParent(), "VortexParticleSystem::advectSelf"); 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"); 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)); pbPreparePlugin(pbo->getParent(), "VortexParticleSystem::applyToMesh"); 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"); return _retval; } catch(std::exception& e) { pbSetError("VortexParticleSystem::applyToMesh",e.what()); return 0; } }
+ virtual ParticleBase* clone(); public: PbArgs _args;}
+#define _C_VortexParticleSystem
+;
+
+} // namespace
+
+
+#endif
+
diff --git a/source/blender/python/manta_pp/vortexpart.h.reg b/source/blender/python/manta_pp/vortexpart.h.reg
new file mode 100644
index 00000000000..8d36d048fbd
--- /dev/null
+++ b/source/blender/python/manta_pp/vortexpart.h.reg
@@ -0,0 +1,7 @@
+#include "vortexpart.h"
++VortexParticleSystem^ static const Pb::Register _R_$IDX$ ("VortexParticleSystem","VortexParticleSystem","ParticleSystem<$BT$>"); template<> const char* Namify<VortexParticleSystem >::S = "VortexParticleSystem";
+>VortexParticleSystem^
+@VortexParticleSystem^^ParticleSystem^VortexParticleData
++VortexParticleSystem^ static const Pb::Register _R_$IDX$ ("VortexParticleSystem","VortexParticleSystem",VortexParticleSystem::_W_0);
++VortexParticleSystem^ static const Pb::Register _R_$IDX$ ("VortexParticleSystem","advectSelf",VortexParticleSystem::_W_1);
++VortexParticleSystem^ static const Pb::Register _R_$IDX$ ("VortexParticleSystem","applyToMesh",VortexParticleSystem::_W_2);
diff --git a/source/blender/python/manta_pp/vortexpart.h.reg.cpp b/source/blender/python/manta_pp/vortexpart.h.reg.cpp
new file mode 100644
index 00000000000..99b1888f316
--- /dev/null
+++ b/source/blender/python/manta_pp/vortexpart.h.reg.cpp
@@ -0,0 +1,32 @@
+
+
+
+
+
+// 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_0 ("ParticleSystem<VortexParticleData>","ParticleSystem<VortexParticleData>","ParticleBase"); template<> const char* Namify<ParticleSystem<VortexParticleData> >::S = "ParticleSystem<VortexParticleData>";
+ static const Pb::Register _R_1 ("ParticleSystem<VortexParticleData>","ParticleSystem",ParticleSystem<VortexParticleData>::_W_2);
+ static const Pb::Register _R_2 ("ParticleSystem<VortexParticleData>","size",ParticleSystem<VortexParticleData>::_W_3);
+ static const Pb::Register _R_3 ("ParticleSystem<VortexParticleData>","setPos",ParticleSystem<VortexParticleData>::_W_4);
+ static const Pb::Register _R_4 ("ParticleSystem<VortexParticleData>","getPos",ParticleSystem<VortexParticleData>::_W_5);
+ static const Pb::Register _R_5 ("ParticleSystem<VortexParticleData>","getPosPdata",ParticleSystem<VortexParticleData>::_W_6);
+ static const Pb::Register _R_6 ("ParticleSystem<VortexParticleData>","setPosPdata",ParticleSystem<VortexParticleData>::_W_7);
+ static const Pb::Register _R_7 ("ParticleSystem<VortexParticleData>","clear",ParticleSystem<VortexParticleData>::_W_8);
+ static const Pb::Register _R_8 ("ParticleSystem<VortexParticleData>","advectInGrid",ParticleSystem<VortexParticleData>::_W_9);
+ static const Pb::Register _R_9 ("ParticleSystem<VortexParticleData>","projectOutside",ParticleSystem<VortexParticleData>::_W_10);
+#endif
+#ifdef _C_VortexParticleSystem
+ static const Pb::Register _R_10 ("VortexParticleSystem","VortexParticleSystem","ParticleSystem<VortexParticleData>"); template<> const char* Namify<VortexParticleSystem >::S = "VortexParticleSystem";
+ static const Pb::Register _R_11 ("VortexParticleSystem","VortexParticleSystem",VortexParticleSystem::_W_0);
+ static const Pb::Register _R_12 ("VortexParticleSystem","advectSelf",VortexParticleSystem::_W_1);
+ static const Pb::Register _R_13 ("VortexParticleSystem","applyToMesh",VortexParticleSystem::_W_2);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/python/manta_pp/vortexsheet.cpp b/source/blender/python/manta_pp/vortexsheet.cpp
new file mode 100644
index 00000000000..c58544f5f28
--- /dev/null
+++ b/source/blender/python/manta_pp/vortexsheet.cpp
@@ -0,0 +1,105 @@
+
+
+
+
+
+// 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
+ *
+ * Vortex sheets
+ *
+ ******************************************************************************/
+
+#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
+
+
diff --git a/source/blender/python/manta_pp/vortexsheet.h b/source/blender/python/manta_pp/vortexsheet.h
new file mode 100644
index 00000000000..b6656d56977
--- /dev/null
+++ b/source/blender/python/manta_pp/vortexsheet.h
@@ -0,0 +1,98 @@
+
+
+
+
+
+// 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
+ *
+ * Vortex sheets
+ *
+ ******************************************************************************/
+
+#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); pbPreparePlugin(0, "VortexSheetMesh::VortexSheetMesh" ); { 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" ); 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)); pbPreparePlugin(pbo->getParent(), "VortexSheetMesh::calcCirculation"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->calcCirculation(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"VortexSheetMesh::calcCirculation"); 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)); pbPreparePlugin(pbo->getParent(), "VortexSheetMesh::calcVorticity"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->calcVorticity(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"VortexSheetMesh::calcVorticity"); 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)); pbPreparePlugin(pbo->getParent(), "VortexSheetMesh::reinitTexCoords"); PyObject *_retval = 0; { ArgLocker _lock; pbo->_args.copy(_args); _retval = getPyNone(); pbo->reinitTexCoords(); pbo->_args.check(); } pbFinalizePlugin(pbo->getParent(),"VortexSheetMesh::reinitTexCoords"); 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
+
+#endif
+
diff --git a/source/blender/python/manta_pp/vortexsheet.h.reg b/source/blender/python/manta_pp/vortexsheet.h.reg
new file mode 100644
index 00000000000..d5ad6b64113
--- /dev/null
+++ b/source/blender/python/manta_pp/vortexsheet.h.reg
@@ -0,0 +1,7 @@
+#include "vortexsheet.h"
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","VortexSheetMesh","Mesh"); template<> const char* Namify<VortexSheetMesh >::S = "VortexSheetMesh";
+>VortexSheetMesh^
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","VortexSheetMesh",VortexSheetMesh::_W_0);
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","calcCirculation",VortexSheetMesh::_W_1);
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","calcVorticity",VortexSheetMesh::_W_2);
++VortexSheetMesh^ static const Pb::Register _R_$IDX$ ("VortexSheetMesh","reinitTexCoords",VortexSheetMesh::_W_3);
diff --git a/source/blender/python/manta_pp/vortexsheet.h.reg.cpp b/source/blender/python/manta_pp/vortexsheet.h.reg.cpp
new file mode 100644
index 00000000000..d8dcc775ed9
--- /dev/null
+++ b/source/blender/python/manta_pp/vortexsheet.h.reg.cpp
@@ -0,0 +1,21 @@
+
+
+
+
+
+// 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_0 ("VortexSheetMesh","VortexSheetMesh","Mesh"); template<> const char* Namify<VortexSheetMesh >::S = "VortexSheetMesh";
+ static const Pb::Register _R_1 ("VortexSheetMesh","VortexSheetMesh",VortexSheetMesh::_W_0);
+ static const Pb::Register _R_2 ("VortexSheetMesh","calcCirculation",VortexSheetMesh::_W_1);
+ static const Pb::Register _R_3 ("VortexSheetMesh","calcVorticity",VortexSheetMesh::_W_2);
+ static const Pb::Register _R_4 ("VortexSheetMesh","reinitTexCoords",VortexSheetMesh::_W_3);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index 36b9f8ae362..318b376d8c1 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -138,6 +138,10 @@ if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
endif()
+if(WITH_MOD_MANTA)
+ add_definitions(-DWITH_MANTA)
+endif()
+
if(WITH_FREESTYLE)
list(APPEND INC
../freestyle
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 25ee4f2ef21..4451264c02a 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -137,6 +137,7 @@ endif()
bf_intern_guardedalloc
bf_intern_memutil
bf_python_ext
+ bf_python_manta
bf_python_mathutils
bf_python_bmesh
bf_intern_utfconv
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 57e67a971d3..9f3ee8b3935 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -994,6 +994,19 @@ add_dependencies(blender makesdna)
setup_blender_sorted_libs()
+# -----------------------------------------------------------------------------
+# Mantaflow Force linking
+#PR removed -Wl, -force_load
+#SET(MANTA_LINK_LIBRARIES -rdynamic -Wl,-force_load bf_python_manta)
+if(APPLE)
+ SET(MANTA_LINK_LIBRARIES -force_load bf_python_manta )
+else()
+ SET(MANTA_LINK_LIBRARIES -Wl,--whole-archive bf_python_manta -Wl,--no-whole-archive )
+endif()
+target_link_libraries(blender ${MANTA_LINK_LIBRARIES})
+
+# -----------------------------------------------------------------------------
+# Setup link libs
target_link_libraries(blender ${BLENDER_SORTED_LIBS})
setup_liblinks(blender)