1
1

Compare commits

...

192 Commits

Author SHA1 Message Date
Roman Pogribnyi
3d397d22d7 Smoke: UI controls for manta buoyancy used 2015-05-17 21:22:08 +02:00
Roman Pogribnyi
16ace5e6f7 Smoke: manta export paths corrected 2015-05-17 20:46:04 +02:00
Roman Pogribnyi
03c7acf3a0 Smoke: Updated mantaflow sources 2015-04-13 22:17:59 +02:00
Roman Pogribnyi
79f7f4d562 after-merge errors fixed 2015-03-15 23:05:11 +01:00
Roman Pogribnyi
5c64aa2554 Merge branch 'master' into soc-2014-fluid 2015-03-15 19:57:06 +01:00
Roman Pogribnyi
2a1a6bc572 2D lowres smoke 2015-03-09 22:55:34 +01:00
Roman Pogribnyi
bf64cd1fd8 Forces passed to Mantaflow correctly, vortex working 2015-03-05 00:19:24 +01:00
Roman Pogribnyi
1799615629 Manta 2D smoke indexing fixed 2015-02-01 23:58:36 +01:00
Roman Pogribnyi
2d0f34ef76 Manta 2D Smoke display correct 2015-02-01 23:52:19 +01:00
Roman Pogribnyi
d607c2a598 manta scene file location, work on 2D smoke 2015-01-27 23:24:16 +01:00
Roman Pogribnyi
d72968e91d fields saved properly for export, unused code removed 2014-12-04 23:14:53 +01:00
Roman Pogribnyi
666cc76e42 completing flags passing, removing comments from scenarios 2014-11-17 10:53:10 +01:00
Roman Pogribnyi
a380ca2a63 passing obstacle flags to manta correctly 2014-11-15 15:05:23 +01:00
Roman Pogribnyi
1377d74cb5 high res smoke colors fixed 2014-11-14 14:41:43 +01:00
Roman Pogribnyi
43d7cbdea8 Boundary conditions + new feature 2014-11-11 23:42:18 +01:00
Roman Pogribnyi
26dca6df78 Buoyancy in Manta using heat from Blender 2014-11-09 15:39:17 +01:00
Roman Pogribnyi
6b11773770 error checks for Manta_API functions 2014-11-09 14:41:12 +01:00
Roman Pogribnyi
15ba8ec5af shrinking Fluid_3d class 2014-11-09 14:38:01 +01:00
Roman Pogribnyi
b63074492d low- and highres colored smoke 2014-11-06 00:31:09 +01:00
Roman Pogribnyi
b1acc10d8b not initializing density fields 2014-11-05 21:26:12 +01:00
Roman Pogribnyi
cbda5b801b SMOKE: mantaflow in Fluid_3d object, running wavelets 2014-11-05 20:53:08 +01:00
Roman Pogribnyi
2e6fbe23b8 SMOKE: wavelets included in setups 2014-11-04 17:45:03 +01:00
Roman Pogribnyi
645c283477 wturbulence for mantaflow 2014-11-02 14:21:17 +01:00
Roman Pogribnyi
f45d319d60 division between high-res and low-res manta operations 2014-11-02 14:20:54 +01:00
Roman Pogribnyi
4256c72ae3 working with manta compiler flag 2014-10-30 16:36:06 +01:00
Roman Pogribnyi
d410d6622a lowres density pointers corrected 2014-10-30 11:48:07 +01:00
Roman Pogribnyi
c181d0b9be lowres: computing forces only once 2014-10-27 13:38:45 +01:00
Roman Pogribnyi
c92be53d24 Not using disk setup file anymore 2014-10-27 09:56:29 +01:00
Roman Pogribnyi
cd5898aecb low-res: only manta solver, with manta flag simulation 2014-10-27 09:16:32 +01:00
Roman Pogribnyi
8d40c8de5a Defining Interfaces for Manta_API 2014-10-26 21:59:40 +01:00
Roman Pogribnyi
b4ef7ed987 GetGridPOinter form mantaflow working 2014-10-26 21:51:41 +01:00
Roman Pogribnyi
4ffc4fb0bc UI syntax 2014-10-26 21:50:31 +01:00
Roman Pogribnyi
e62f96480a unused manta UI disabled 2014-10-25 14:54:54 +02:00
Roman Pogribnyi
71493088c1 deleting manta solvers and fields correctly 2014-10-25 14:10:15 +02:00
Roman Pogribnyi
5d3ae295d8 compiler flags for osx and linux 2014-10-25 12:26:59 +02:00
Roman Pogribnyi
2696d2bb8b mantaflow stable on osx 2014-10-24 17:45:28 +02:00
Roman Pogribnyi
9b54025191 Manta python module imported correctly 2014-10-24 12:33:19 +02:00
ee54a4eaee Fix compile 2014-10-23 18:41:11 +02:00
0d41f63eb2 Revert changes.
Still one linking error left.
2014-10-23 18:04:28 +02:00
f43088623c Revert name changes to be conform with mana_full 2014-10-23 17:17:01 +02:00
33c5699a41 Fix compile error on Linux 2014-10-23 16:55:49 +02:00
f2c5ff385d Fix merge error
Streamline Python function name
2014-10-23 16:46:28 +02:00
9c113a870a Fix merge error (still some left)
Fix some path issues
2014-10-23 16:36:01 +02:00
2cc063318c Fix CMake (missing path for zlib) 2014-10-23 15:36:05 +02:00
8662cddce1 Fix (one) compile error on MSVC 2013
Fix merge error
2014-10-23 15:24:24 +02:00
9ff1ebed52 Merge remote-tracking branch 'origin/master' into soc-2014-fluid
Conflicts:
	.gitignore
	intern/cycles/CMakeLists.txt
	source/blender/blenkernel/intern/smoke.c
	source/blender/python/intern/bpy_interface.c
	source/creator/CMakeLists.txt
2014-10-23 15:12:28 +02:00
Roman Pogribnyi
a2ed11c6ee readGridFromMemory correct dimensionality 2014-10-23 11:59:50 +02:00
Roman Pogribnyi
77fcd6c400 unnecessary calls to Mantaflow removed 2014-10-22 20:47:41 +02:00
Roman Pogribnyi
9cc9c7ec16 high-res: inflow data passed in-memory, forces working 2014-10-21 23:09:04 +02:00
Roman Pogribnyi
2b3b73fbb0 low-res: passing obstacles in-memory 2014-10-18 15:52:46 +02:00
Roman Pogribnyi
e6a37c3f24 low res: errors in grid construction fixed, methods for passing obstacles to Mantaflow added 2014-10-18 15:15:45 +02:00
Roman Pogribnyi
8b9abeb8e0 methods for adding texture values to grids, working for Real type 2014-10-17 17:37:53 +02:00
Roman Pogribnyi
86aeeb16f8 in-memory passing of force fields 2014-10-16 22:05:00 +02:00
Roman Pogribnyi
453a284e97 generating grid name from type 2014-10-16 21:42:37 +02:00
Roman Pogribnyi
2fcda12a14 passing void pointers for different types of grids 2014-10-16 21:33:35 +02:00
Roman Pogribnyi
b3413a07b4 passing inflow adaptive grids without disk files 2014-10-15 19:51:35 +02:00
Roman Pogribnyi
193461e3da Manta_API as singletone 2014-10-11 20:21:40 +02:00
Roman Pogribnyi
065e1a196c debug output, smoke BC 2014-10-11 19:39:03 +02:00
Roman Pogribnyi
c7c360c573 loading influence fields form file 2014-10-11 19:38:08 +02:00
Roman Pogribnyi
239260d45b returning to non-static methods 2014-10-11 19:35:53 +02:00
Roman Pogribnyi
1ad9eebd51 more vars from sds, flow density added to manta 2014-09-27 14:48:56 +02:00
Roman Pogribnyi
db26bdd36f writing correct density emitter to file 2014-09-27 13:53:41 +02:00
Roman Pogribnyi
b79bcc8121 replacing step function 2014-09-27 09:38:38 +02:00
Roman Pogribnyi
f91b07d655 loading flow data on first sim frame 2014-09-22 14:46:14 +02:00
Roman Pogribnyi
8e32d79158 scenario changed according to simpleplume 2014-09-22 13:35:42 +02:00
Roman Pogribnyi
8f14ff3905 per-step sim without writing to disk, reducing number of arguments to manta 2014-09-21 16:37:49 +02:00
Roman Pogribnyi
309e1bcc2d low-res smoke scenario running, unused files removed 2014-09-21 14:51:48 +02:00
Roman Pogribnyi
065676a6f8 updated mantaflow version 2014-09-21 14:43:44 +02:00
Roman Pogribnyi
00157066bf reverting to old smoke style, simpleplume scenario for debug 2014-09-21 14:43:00 +02:00
Roman Pogribnyi
527920ecf6 using bake buton, reading more settings 2014-09-20 16:48:46 +02:00
Roman Pogribnyi
199b6cdc1e timestep config corrected 2014-08-31 23:03:26 +02:00
Roman Pogribnyi
0fce063fd0 Display and render of highres smoke fixed 2014-08-25 15:28:12 +02:00
Roman Pogribnyi
9c7f7c6573 more parameters for smoke scenario, writing out emitter fields 2014-08-25 14:43:17 +02:00
Roman Pogribnyi
b3cc023c08 smoke scenarion working 2014-08-19 11:03:29 +02:00
Roman Pogribnyi
86989150b5 started scenarios implemetation; added file for smoke; back to setup file generation 2014-08-18 20:48:33 +02:00
Roman Pogribnyi
c9a3db6c42 reverting to Bake button 2014-08-18 16:49:01 +02:00
Roman Pogribnyi
ca26093a2c functions for scenarios parsing added 2014-08-18 16:01:37 +02:00
Roman Pogribnyi
01ec151a07 commented parts and debug msgs removed in rest of files 2014-08-18 15:22:59 +02:00
Roman Pogribnyi
0e200e9d31 manta.cpp commented parts removed 2014-08-18 15:08:39 +02:00
Roman Pogribnyi
dca46055ee releasing python after sim step 2014-08-18 14:53:03 +02:00
Roman Pogribnyi
2b9c2bc1d4 debug messages added 2014-08-18 11:52:26 +02:00
Roman Pogribnyi
5f39d58e6d setup script passed directly; file still created fir debug 2014-08-18 09:25:54 +02:00
Roman Pogribnyi
a651697d78 frame counting for simulation correct 2014-08-17 22:26:26 +02:00
Roman Pogribnyi
c9571f9a3e Run sim from timeline, without Bake button 2014-08-17 15:55:00 +02:00
Roman Pogribnyi
775b93767f RNA update operations corrected 2014-08-16 12:03:17 +02:00
Roman Pogribnyi
f105ea7b5e timestep decreased 2014-08-15 22:25:22 +02:00
Roman Pogribnyi
269dbda090 old density read-style 2014-08-15 22:18:52 +02:00
Roman Pogribnyi
0607338884 repositioned domain handling; quick smoke working 2014-08-15 21:48:15 +02:00
Roman Pogribnyi
3bd5139761 faster SDF, displaying smoke 2014-08-15 20:17:23 +02:00
Roman Pogribnyi
dca8568fff added comments 2014-08-14 23:14:49 +02:00
Roman Pogribnyi
4b7cc3923e removed commented parts 2014-08-14 23:11:12 +02:00
Roman Pogribnyi
dcdb8a658c inflow without noise; passing rotated geometry to amantaflow correct 2014-08-14 23:04:56 +02:00
Roman Pogribnyi
6642bd6ab4 wavelets source positioning correct 2014-08-13 22:12:02 +02:00
Roman Pogribnyi
dc529debbd resizeable domain added. Working for non-rotated objects 2014-08-13 20:57:12 +02:00
Roman Pogribnyi
9575a37b20 loading and displaying wavelets smoke 2014-08-13 16:06:04 +02:00
Roman Pogribnyi
00c9e3b4cf rotating domain to get manta axes 2014-08-12 22:43:39 +02:00
Roman Pogribnyi
2f96dbd3fc invoking BKE_cache_write when read from cached files successful; handling wavelet 2014-08-12 22:42:23 +02:00
Roman Pogribnyi
201555edca updating highres fluid_3d; writing smoke cache to BKE_pointcache 2014-08-12 00:55:35 +02:00
Roman Pogribnyi
74136a6d06 re-runs with wavelets work 2014-08-11 22:16:15 +02:00
Roman Pogribnyi
8537dccb30 runtime error in abscent FLUID_3D obj seems corrected 2014-08-11 21:48:16 +02:00
Roman Pogribnyi
e5b7630809 more density in emitter, unused function declaration removed 2014-08-10 18:05:10 +02:00
Roman Pogribnyi
edc3b4b687 force fields direction correct 2014-08-09 13:00:48 +02:00
Roman Pogribnyi
818d6ae380 more fluid_3d pointers handling 2014-08-08 23:46:11 +02:00
Roman Pogribnyi
868980d7f2 FLUID3D pointers handling 2014-08-08 22:25:33 +02:00
Roman Pogribnyi
ba0d7cb56d Buoyancy factor corrected 2014-08-08 17:55:36 +02:00
Roman Pogribnyi
0e173445c7 manta running speed increased. Buoyancy factor added 2014-08-08 17:55:14 +02:00
Roman Pogribnyi
861bfc9441 correct number of sim frames 2014-08-08 16:51:22 +02:00
Roman Pogribnyi
e3adec65f7 Error with force_grid_size fixed. Direction still incorrect 2014-08-08 14:16:10 +02:00
Roman Pogribnyi
ec9c908018 forces included in manta simulation on per-basis step 2014-08-08 00:14:35 +02:00
Roman Pogribnyi
306ef174cb updating force_fields on per-step basis 2014-08-07 23:50:58 +02:00
Roman Pogribnyi
5a54c9c6b7 updating force field on smoke_process 2014-08-07 20:34:21 +02:00
Roman Pogribnyi
ff20f36680 exporting wind force 2014-08-07 20:12:38 +02:00
Roman Pogribnyi
9156dcac7d addForceField method in mantaflow added 2014-08-07 19:58:15 +02:00
Roman Pogribnyi
fa4dec8e52 Linux running error fixed. Replay sim error fixed 2014-08-05 19:34:15 +02:00
Roman Pogribnyi
1f22e9d68c passing correctly rotated geometry to manta 2014-08-05 19:20:29 +02:00
Roman Pogribnyi
6a22addd61 returning to densityInflowMesh 2014-08-05 14:11:06 +02:00
Roman Pogribnyi
5c6ee2794d extracting force_fields 2014-08-04 12:08:37 +02:00
Roman Pogribnyi
4de2c21a40 closing file correctly 2014-08-03 17:45:54 +02:00
Roman Pogribnyi
73186af86e renaming of processed density field files 2014-08-02 13:04:30 +02:00
Roman Pogribnyi
2e06c6dbe7 progress textfield started, stopButton correct 2014-08-02 13:03:29 +02:00
Roman Pogribnyi
e7dbab06f4 unused file deleted 2014-08-01 19:36:27 +02:00
Roman Pogribnyi
0f8dabc1d7 imorting mantaflow correctly in Unix 2014-08-01 19:33:39 +02:00
Roman Pogribnyi
c6ca55e32e stop sim button 2014-07-31 23:13:21 +02:00
Roman Pogribnyi
79d6c89eaf frame_num field added, manta_sim in separate thread 2014-07-31 19:54:09 +02:00
Roman Pogribnyi
ce20c8d876 step, stop sim manta operations added 2014-07-31 19:52:50 +02:00
Roman Pogribnyi
473255d2f7 method for frame_step in separate thread added 2014-07-31 13:13:35 +02:00
Roman Pogribnyi
c8138097f7 per-step simulation added 2014-07-31 00:12:24 +02:00
Roman Pogribnyi
411ee40384 single-threaded re-runs work ok 2014-07-30 18:24:02 +02:00
Roman Pogribnyi
3122ee62d1 back to single-threaded method to debug manta re-run errors 2014-07-30 17:29:24 +02:00
Roman Pogribnyi
5f19242c58 new flags for manta module 2014-07-28 21:16:58 +02:00
Roman Pogribnyi
ada6ead6cc manta readfile to separate function 2014-07-28 12:09:00 +02:00
Roman Pogribnyi
e3aecd084e using user-defined frame bounds 2014-07-25 20:35:00 +02:00
Roman Pogribnyi
3643bf3be0 added start-end frame fields in UI 2014-07-25 19:40:31 +02:00
Roman Pogribnyi
06f05294cb function bodies moved to cpp file, some sim settings tweaked 2014-07-25 16:53:24 +02:00
Roman Pogribnyi
762a4b57a8 manta tun is separate thread 2014-07-24 14:54:32 +02:00
Roman Pogribnyi
15a2f381b0 class registration improved 2014-07-23 20:06:56 +02:00
Roman Pogribnyi
5e92c2770a debug output removed 2014-07-23 20:01:30 +02:00
Roman Pogribnyi
0f64929d79 added debug messages 2014-07-22 16:44:57 +02:00
Roman Pogribnyi
bab35daf74 unused files removed 2014-07-22 15:20:02 +02:00
Roman Pogribnyi
5bd23adb62 division on manta_pp and manta_full to switch between full module and pp files 2014-07-22 15:18:47 +02:00
Roman Pogribnyi
7752cfb1d8 cleaned cmakelists file 2014-07-21 16:48:52 +02:00
Roman Pogribnyi
fe44c97b37 unused plugin files removed 2014-07-21 16:47:34 +02:00
Roman Pogribnyi
8f9b4a3566 removing source duplicates 2014-07-17 15:36:20 +02:00
Roman Pogribnyi
ea0e959843 compiling & linking; unused paths deleted; compile flags for manta removed 2014-07-17 15:12:52 +02:00
Roman Pogribnyi
91921bb051 depends added, unused list commands removed 2014-07-17 13:51:43 +02:00
Roman Pogribnyi
c6e418c690 non-existing files generated and preprocessed 2014-07-17 13:20:29 +02:00
Roman Pogribnyi
1c2f537505 paths for repositioned manta_pp folder correct 2014-07-17 10:00:36 +02:00
Roman Pogribnyi
df1c4bb710 removing repository info 2014-07-17 10:00:36 +02:00
Roman Pogribnyi
eb64dca859 fixed prep-not-found issue,files compiling 2014-07-17 10:00:35 +02:00
2fd69c5185 Fix generating temporary files with prep binary, also comment out include of hgnfo header for now.
- I just uncommented failing code
- dunno whats up with hginfo, guess thats from external source versioncontrol of manta (?)
- pls disable openmp, due this branch was not merged lately and misses omp cmake fixes
I checked all is compiling fine now
2014-07-16 01:47:10 +02:00
Roman Pogribnyi
8a990a8318 correct prep binary location, debug messages instead of prep step 2014-07-15 16:24:32 +02:00
Roman Pogribnyi
25ef55b304 library creation for Win systems 2014-07-14 13:00:42 +02:00
Roman Pogribnyi
a70e4394ac removed pp files, preproessing during compiling step 2014-07-14 12:57:43 +02:00
Roman Pogribnyi
2071f5901a setting for debugging the linking issue 2014-07-12 16:00:50 +02:00
Roman Pogribnyi
41a28c2106 Compiling intermediate files for linking c++ code from bpy_interface.c 2014-07-10 23:02:13 +02:00
Roman Pogribnyi
8c3aedcec5 Big commit. Manta included in Blender Python. NOT ALL modules imported 2014-07-08 21:31:15 +02:00
Roman Pogribnyi
f80924027f importing manta module to interpreter 2014-07-02 20:13:12 +02:00
Roman Pogribnyi
37613a8cba *FAULTY* code, big commit: manta files, Cmake and Scons integration. Started work on full-cycle fluids 2014-07-02 11:50:03 +02:00
Roman Pogribnyi
f47b7784cf settings for SDF tweaked 2014-06-25 13:05:40 +02:00
Roman Pogribnyi
aa59cb6615 Running Manta in separate thread 2014-06-21 10:26:36 +02:00
Roman Pogribnyi
559ae8567c vorticity, SDF grids added 2014-06-21 10:25:13 +02:00
Roman Pogribnyi
efa2f69473 method for transforming meshes back from [-1,1] coords; sdf fields for obstacles and inflow meshes added 2014-06-19 15:05:05 +02:00
Roman Pogribnyi
7548135aec Manta vars initialization, support for inflow objs in setup file, *.obj export for bounding box[ -1,1] 2014-06-16 23:11:58 +02:00
Roman Pogribnyi
91c5025ce8 repositioning handled 2014-06-14 01:37:53 +02:00
Roman Pogribnyi
c781f59974 resizing meshes accordingly, tweaks in SDF method call 2014-06-14 00:40:05 +02:00
Roman Pogribnyi
7ae6959df9 Better handling of obj files when writing there 2014-06-13 22:07:20 +02:00
Roman Pogribnyi
7e0aa75de9 Setup file handles collision objs correctly 2014-06-13 22:05:29 +02:00
Roman Pogribnyi
b5b81bea79 correct file naming 2014-06-13 19:45:57 +02:00
Roman Pogribnyi
42567648a7 exporting Collision and flow objects as .obj files 2014-06-13 19:45:20 +02:00
Roman Pogribnyi
c249d3dad1 Noise settings UI 2014-06-10 23:52:45 +02:00
Roman Pogribnyi
c0ecba8002 UI for UVS count 2014-06-10 22:59:58 +02:00
Roman Pogribnyi
b37b145a95 indentation method added, minor fixes 2014-06-10 22:19:37 +02:00
Roman Pogribnyi
6a1ffeefd8 indents added; correct order of wavelets restored 2014-06-08 13:16:35 +02:00
Roman Pogribnyi
98d62932e5 setup file is correct 2014-06-07 17:59:10 +02:00
Roman Pogribnyi
8fddd571a1 flags, mock sources and obstacles. handling of octaves 2014-06-07 16:55:59 +02:00
Roman Pogribnyi
f6a5020d09 wavelet vars added 2014-06-07 16:38:52 +02:00
Roman Pogribnyi
0d979ce138 noise accounts for indentation 2014-06-07 16:16:30 +02:00
Roman Pogribnyi
44b4cf699d noise field name var 2014-06-06 23:42:23 +02:00
Roman Pogribnyi
9ed7be50aa Separate Solver creation function; 2D solver option implemented: UI + functionality 2014-06-06 23:39:00 +02:00
Roman Pogribnyi
1eae4069f7 Pressure function separated; Bundary Conditions set correctly 2014-06-05 18:47:37 +02:00
Roman Pogribnyi
a36bb2ae85 unused comments removed 2014-06-03 23:18:03 +02:00
Roman Pogribnyi
7177c3f129 separate function for semiLagrange advecttion. Using stringstream for script generation 2014-06-03 23:16:30 +02:00
Roman Pogribnyi
33e9a9e0ce Separate function for noise generation. Pressure syntax correct 2014-06-02 15:41:19 +02:00
Roman Pogribnyi
bcb5c61dc3 support for Domain Border Collisions added 2014-05-31 17:29:35 +02:00
Roman Pogribnyi
ac78fde848 operator to generate setup file added 2014-05-30 14:03:33 +02:00
Roman Pogribnyi
a009fb637b function to generate setup file added 2014-05-30 13:58:45 +02:00
Roman Pogribnyi
e7e5ef2c04 use_manta property added to smoke DNA 2014-05-30 13:45:43 +02:00
Roman Pogribnyi
2cf121ca35 Mantaflow UI added: tab and file generation button 2014-05-30 13:40:24 +02:00
Roman Pogribnyi
9ae7bd0cdb added manta.h to smoke cmake config 2014-05-30 13:17:32 +02:00
Roman Pogribnyi
60f32a6389 CMakeLists warnings restored 2014-05-30 13:15:25 +02:00
Roman Pogribnyi
e726908fb4 comments style fixed 2014-05-25 22:21:03 +02:00
Roman Pogribnyi
66f21314f9 added Manta.h for mantaflow integrtion; reading smoke simulation files 2014-05-25 00:44:12 +02:00
337 changed files with 64845 additions and 454 deletions

9
.gitignore vendored
View File

@@ -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

View File

@@ -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)
@@ -2482,6 +2483,38 @@ if(WITH_PYTHON_MODULE)
add_definitions(-DPy_ENABLE_SHARED)
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
@@ -2489,9 +2522,9 @@ 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)

View File

@@ -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

View File

@@ -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

View File

@@ -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', ''),

View File

@@ -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)

1
extern/SConscript vendored
View File

@@ -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'])

View File

@@ -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 {

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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

View File

File diff suppressed because it is too large Load Diff

View File

@@ -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;

View File

@@ -0,0 +1,662 @@
#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::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 "";
}
cout << "getting grid pointer " << gridName<< " , " << solverName <<endl;
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];
cout << 'updating pointers'<<endl;
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{
cout << '3D'<<endl;
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"));
}
}

136
intern/smoke/intern/MANTA.h Normal file
View File

@@ -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 */

View File

@@ -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

View File

@@ -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;

View File

@@ -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 = $TIMESTEP$\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 = $ALPHA$, vel=vel, gravity=gravity, flags=flags, heat = heat_low, heatCoeff = $BETA$*10)\n\
else:\n\
gravity=vec3(0,0,-0.01 * $ALPHA$) if solver_dim==3 else vec3(0,-0.01* $ALPHA$,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\
";

View File

@@ -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;
}

View File

@@ -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
manta_filepath = os.path.dirname(context.smoke.domain_settings.manta_filepath)
silent_remove(os.path.join(manta_filepath, "manta_coll.obj"))
silent_remove(os.path.join(manta_filepath, "manta_flow.obj"))
#exporting here
if coll_objs:
old_data = transform_objgroup(coll_objs, domain)
bpy.ops.export_scene.obj(filepath = os.path.join(manta_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 = os.path.join(manta_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__)

View File

@@ -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()

View File

@@ -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')

View File

@@ -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));

View File

@@ -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);
@@ -206,7 +210,7 @@ void smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[
/* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */
BLI_lock_thread(LOCK_FFTW);
sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors);
sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors, sds);
BLI_unlock_thread(LOCK_FFTW);
@@ -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, BKE_tempdir_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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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 */

View File

@@ -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()

View File

@@ -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'

View File

@@ -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)

View File

@@ -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)

View File

@@ -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')

View File

@@ -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()

View File

@@ -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 */

View File

@@ -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}' ")

View File

@@ -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>.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
Detailed instructions on how to compile and run mantaflow can be found at:
http://mantaflow.ethz.ch/quickstart.html

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -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 */

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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));

View File

@@ -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}
};

File diff suppressed because it is too large Load Diff

View File

@@ -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 */
};

View File

@@ -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;
}

View File

@@ -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));

File diff suppressed because it is too large Load Diff

View File

@@ -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
};

View File

@@ -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;
}

View File

@@ -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 */

File diff suppressed because it is too large Load Diff

View File

@@ -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 */

View File

@@ -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 */

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

View File

@@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

View File

@@ -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()

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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++;
}
}
}
*/

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

Some files were not shown because too many files have changed in this diff Show More