Compare commits

..

255 Commits

Author SHA1 Message Date
David Williams
c986c9f0b1 Added note that development of PolyVox has now stopped. 2016-11-24 22:47:40 +00:00
David Williams
9a71004b1e Added ability to check whether previousVoxel has been set. 2016-05-21 08:34:13 +01:00
David Williams
f4c4bf984c Updated install instructions regarding different Python versions. 2016-02-07 10:29:04 +00:00
David Williams
fe2c29e013 Compile fix. 2016-02-07 10:00:07 +00:00
David Williams
98cce0ea26 Documentation fixes. 2016-02-07 00:19:18 +00:00
David Williams
c57cb96e80 Replaced LargeVolume reference with PagedVolume. 2016-02-07 00:13:05 +00:00
David Williams
817c799fcf Updated tutorial 1 with latest code from BasicExample. 2016-02-07 00:06:29 +00:00
David Williams
09c3c2e12f Minor changes to error handling documentation. 2016-02-06 09:38:46 +00:00
David Williams
dcbc3bd995 Minor changes to threading documentation. 2016-02-06 09:25:52 +00:00
David Williams
92c900b774 Minor updates to level-of-detail documentation. 2016-02-06 09:15:35 +00:00
David Williams
4f8ae5acea Minor tweaks to texture mapping documentation. 2016-01-31 17:36:09 +00:00
David Williams
615c1dc00a Tweaks to lighting documentation. 2016-01-31 10:32:27 +00:00
David Williams
3caa86a462 Minor update to 'Principles of PolyVox' 2016-01-31 10:23:46 +00:00
David Williams
b5e8b63810 Minor documentation tweaks. 2016-01-31 09:18:20 +00:00
David Williams
5103563365 Updating documentation. 2016-01-30 23:23:42 +00:00
David Williams
e0b00fc5ac Updated prerequisites section of PolyVox docs. 2016-01-28 23:00:16 +00:00
David Williams
92981f3599 Minor doc update. 2016-01-28 22:24:55 +00:00
David Williams
21e6b435a1 Linux compile fix. 2016-01-25 23:54:34 +01:00
David Williams
5644f837ca Fixed broken include paths causing compile errors on Linux. 2016-01-24 13:15:51 +00:00
David Williams
8d9fffd4c6 Minimal set of changes to get Python bindings building since the last big refactor made PolyVox header only. 2016-01-21 22:49:20 +00:00
David Williams
156bcef9c0 Added files which were accidently removed from repository. 2016-01-19 23:16:02 +00:00
David Williams
0fe41fe28c Documentation changes. 2016-01-11 22:54:27 +00:00
David Williams
e433a697cb Removed out-of-date PagedVolume documentation and added a little bit in it's place. 2016-01-09 09:47:20 +00:00
David Williams
3d01a8412e Documentation. 2016-01-03 23:12:28 +00:00
David Williams
abfe63a525 Moved some files into 'Impl' folder 2016-01-03 22:50:10 +00:00
David Williams
85b1bbb641 Documentation. 2016-01-03 22:45:55 +00:00
David Williams
eef0bebacf Various documentation enhancements. 2016-01-03 22:31:24 +00:00
David Williams
4d2a27ea8e Removed old Thermite reference! 2016-01-03 22:21:04 +00:00
David Williams
6a12a3dc7f Moved some code to .inl 2016-01-03 22:20:14 +00:00
David Williams
f4ebd4c6a9 Removed unnecessary headers. 2016-01-03 22:14:33 +00:00
David Williams
75a2831ae7 Documentation tweaks. 2016-01-03 18:04:07 +00:00
David Williams
c0b72b6a55 Tidying up comments. 2016-01-03 17:49:59 +00:00
David Williams
1444f187a6 More tidying up, moving private code out of main header. 2016-01-03 09:40:52 +00:00
David Williams
8678d741b3 Rearranging cubic extractor code. 2016-01-02 17:38:23 +00:00
David Williams
64c4c8ce86 Moving around some Marching Cubes code so that only the public stuff is in the header.
Tidying up some documentation.
2016-01-02 13:06:43 +00:00
David Williams
d544de6dd1 Removed deprecated functions. 2015-12-26 23:41:49 +00:00
David Williams
e89a55d154 Applied default Visual Studio formatting to most files. This is a quick fix for the tabs vs spaces issue that messes up the formatting in any editor (esp. Linux) which handles tabs/spaces differently to Visual Studio. Some parts of the formatting look a bit worse but overall it should be better (or at least more consistent).
I didn't apply the changes to a few macro-heavy files as Visual Studio removes all indentation from macros, whereas the indentation can be handy to see nesting.
2015-12-26 23:11:27 +00:00
David Williams
b3ca051878 Changed 'embedded' licenses from zlib to MIT. 2015-12-26 21:45:41 +00:00
David Williams
9a8e816485 Replaced uint32_t with size_t. 2015-12-20 21:59:27 +00:00
David Williams
1e9fdf074a Removed the old LargeVolume and SimpleVolume classes, which are now replaced by PagedVolume. 2015-12-20 21:22:29 +00:00
David Williams
403189f357 Removed PolyVoxForwardDeclarations.h. It was a source of confusion because the forward declarations often got out of sync with the real definitions, resulting in confusing template error messages. Furthermore, it does not appear to have actually hurt compile times so I guess it wasn't that useful (or wasn't being used to it's fullest potential). Overall I think PolyVox is not large enough to really benefit from this. 2015-12-20 21:19:20 +00:00
David Williams
354b6aa9d0 When PolyVox files include other PolyVox files the 'PolyVox' part of the path is not needed. This is only needed when examples, tests, and external applications include PolyVox. 2015-12-20 20:56:37 +00:00
David Williams
4fdecf42eb Removing unused code, tidying up. 2015-12-19 15:29:56 +00:00
David Williams
74dfaa293f Fixed usage of region which was too large for the cubic surface extractor. 2015-12-19 15:26:20 +00:00
David Williams
9e600c0bcb Refactoring CubicSurfaceExtractor to free functions rather than just wrapping a class. 2015-12-17 22:57:41 +00:00
David Williams
43bb832c46 Refactoring CubicSurfaceExtractor to free functions rather than just wrapping a class. 2015-12-08 23:50:41 +00:00
David Williams
9617197893 Refactoring CubicSurfaceExtractor to free functions rather than just wrapping a class. 2015-12-08 23:29:38 +00:00
David Williams
65a973f94e Started refactoring CubicSurfaceExtractor to free functions rather than just wrapping a class. 2015-12-07 23:45:24 +00:00
David Williams
28a3d78354 Removed old deprecated code. 2015-11-30 07:50:32 +00:00
David Williams
ed94fc6f25 Removed old/unused code. 2015-11-30 07:47:59 +00:00
David Williams
7fc9990b79 Fixed warning. 2015-11-29 22:50:09 +00:00
David Williams
20ff44c814 Changed license in readme. 2015-11-29 22:12:01 +00:00
David Williams
280c2fdeaa Changed license from zlib to MIT. 2015-11-29 22:08:30 +00:00
David Williams
6d2dcc7d02 Fixing case of file extension (step 2 of 2) 2015-11-29 22:06:57 +00:00
David Williams
67a9d90c0b Fixing case of file extension (step 1 of 2) 2015-11-29 22:06:23 +00:00
Matt Williams
735b0ab6b1 Fix compile on Linux 2015-06-22 12:06:39 +01:00
David Williams
920c78f4d1 Added sobel gradient back in. 2015-06-16 00:00:32 +02:00
David Williams
f8e1bb8452 Fix for broken normals in marching cubes code. 2015-06-14 13:59:51 +02:00
David Williams
14cac713bd Added comment. 2015-06-01 14:30:38 +02:00
David Williams
ff567aa9f8 Added performance notes. 2015-05-29 23:09:51 +02:00
David Williams
5aa631da8f Merge branch 'feature/extractor-optimizations' into develop 2015-05-29 22:39:57 +02:00
David Williams
8c35399fc6 Comments and renaming variables. 2015-05-29 20:34:03 +02:00
David Williams
a0c32e22b7 Added comment. 2015-05-29 17:41:40 +02:00
David Williams
96e747d0c3 Revert "Split the code which generates vertices and indices for a single cell into a separate function."
This reverts commit 2fa291d16f13adf039dc4fa636bfccde52377989.
2015-05-29 17:28:07 +02:00
David Williams
942bb37981 Revert "Passing sampled voxel."
This reverts commit ebab89b9adac576b0d20fd8cbacf0154e7e74fe4.
2015-05-29 17:28:01 +02:00
David Williams
ebab89b9ad Passing sampled voxel. 2015-05-28 23:42:50 +02:00
David Williams
2fa291d16f Split the code which generates vertices and indices for a single cell into a separate function. 2015-05-28 23:26:50 +02:00
David Williams
f32bb1d1ed Reduced array accesses. 2015-05-28 23:02:14 +02:00
David Williams
92db006250 Fixed compile warnings. 2015-05-28 22:40:25 +02:00
David Williams
01963bd462 Added comment about performance. 2015-05-28 22:37:05 +02:00
David Williams
68bdd9ca99 Tidying up. 2015-05-28 21:51:57 +02:00
David Williams
ac7bec0c45 Eliminated unused variables. 2015-05-28 21:46:50 +02:00
David Williams
6493e88d4c Removed unnecessary condition. 2015-05-27 22:58:46 +02:00
David Williams
edd1af14ca Removed unnecessary setting of sampler position. 2015-05-27 22:57:48 +02:00
David Williams
ccedb0e294 Replaced separate arrays with arrays of vectors. 2015-05-27 22:55:36 +02:00
David Williams
baf5cf2cab Removed unneeded memsets. 2015-05-27 07:25:04 +02:00
David Williams
48a6929a7a Tidying up. 2015-05-26 21:24:38 +02:00
David Williams
04c4e49aa1 Fully eliminated MarchingCubesSurfaceExtractor class. It's now only a standalone function called 'extractMarchingCubesMesh'. 2015-05-25 21:23:27 +02:00
David Williams
37db0bac52 Moved gradient calculation outside of class. 2015-05-25 21:16:29 +02:00
David Williams
e4ef845045 Removed sobel gradient calculation code.
Removed m_controller member.
2015-05-25 21:00:50 +02:00
David Williams
b3ce982ef3 Removed some member variables. 2015-05-25 20:51:42 +02:00
David Williams
d353685ce9 Restructuring code... 2015-05-25 20:42:40 +02:00
David Williams
1d51ee8d0a Revert "Rather ugly split of some code into a separate function, to keep the main loop as small and simple as possible. To be tidied up shortly."
This reverts commit 13be35aac906ee34448c3160372db4dcb031022f.
2015-05-25 20:35:55 +02:00
David Williams
c384fbfea8 Revert "Eliminated member variable."
This reverts commit 96ec47a972fea2cd6efcaddd276728f8062d8f7b.
2015-05-25 20:35:47 +02:00
David Williams
96ec47a972 Eliminated member variable. 2015-05-25 17:45:40 +02:00
David Williams
13be35aac9 Rather ugly split of some code into a separate function, to keep the main loop as small and simple as possible. To be tidied up shortly. 2015-05-25 17:37:30 +02:00
David Williams
e0ce93acb1 Added comments. 2015-05-25 16:45:52 +02:00
David Williams
b353cd1ce8 Removed unneeded conditions. 2015-05-25 16:39:30 +02:00
David Williams
ecc06ba986 Changed the way samplers are used for a minor speed improvement. 2015-05-25 12:05:15 +02:00
David Williams
f4941fb73c Minor tweaks. 2015-05-24 23:58:51 +02:00
David Williams
c8124097e3 Using a bit less memory. 2015-05-24 23:32:52 +02:00
David Williams
efb9844fe2 Merge branch 'develop' into feature/extractor-optimizations 2015-05-24 21:17:19 +02:00
David Williams
a34eda6250 Simple optimization. 2015-05-24 21:17:09 +02:00
David Williams
69349d95cd Tidying up. 2015-05-24 21:01:01 +02:00
David Williams
eb3727de30 Vastly simplified logic... hard to believe I made it so complicated :-) 2015-05-24 20:41:46 +02:00
David Williams
32df8be8da Tweaked conditions and comments. 2015-05-24 07:59:03 +02:00
David Williams
4e9b0e374b Moved code into outer loops. 2015-05-24 00:02:27 +02:00
David Williams
8e9e122c03 Merge branch 'develop' into feature/extractor-optimizations 2015-05-23 21:22:58 +02:00
David Williams
304e3d8f7a Faster tests when moving sampler. 2015-05-23 21:22:29 +02:00
David Williams
cee15a145f Avoid setting the sampler position every iteration. 2015-05-23 17:45:16 +02:00
David Williams
5b84c5a9a5 Removed unneeded call to setPosition(). 2015-05-23 17:23:59 +02:00
David Williams
762c9a5090 Switched 3D array back to two 2D arrays to reduce memory usage. 2015-05-22 16:48:42 +02:00
David Williams
50cf939e8a Reorganizing code. 2015-05-22 16:15:53 +02:00
David Williams
50a8bebfa9 Removed unneeded logic. 2015-05-21 23:31:19 +02:00
David Williams
711c262004 Skip outputting some indices. 2015-05-21 23:17:49 +02:00
David Williams
2a7eb51653 Refactoring multiple loops into one big loop. 2015-05-21 23:12:38 +02:00
David Williams
b19de819e2 Fixed compile error due to logging code changing scope. 2015-05-21 10:29:39 +02:00
David Williams
797689acea Trying to re-apply some previous optimizations to get old speed back. 2015-05-20 23:45:22 +02:00
David Williams
f178dc084b Updated unit tests. It seems we had a bug which was causing an excessive number of vertices to be generated. Not sure exactly what was wrong by the refactoring has fixed this. However, it still needs testing in Cubiquity to verify. 2015-05-19 23:14:31 +02:00
David Williams
9a68582530 Added bounds checks 2015-05-17 11:47:52 +02:00
David Williams
ccb76bc6d7 More work refactoring code. Examples appear to work now but tests still fail. 2015-05-17 09:52:13 +02:00
David Williams
a39b7f6a9f More refactoring. 2015-05-16 20:48:15 +02:00
David Williams
1a1ae75766 More refactoring. 2015-05-16 15:36:39 +02:00
David Williams
0e8c90c6ee More refactoring... 2015-05-16 09:00:04 +02:00
David Williams
227b11a764 Cleared array. 2015-05-15 10:03:29 +02:00
David Williams
b4267b11f5 More refactoring code. 2015-05-15 09:57:32 +02:00
David Williams
71adc7292c Restructuring code. 2015-05-14 22:10:37 +02:00
David Williams
89508f8b2b Restructuring code. 2015-05-14 11:48:28 +02:00
David Williams
f53efa1d64 Restructuring code. 2015-05-14 11:41:16 +02:00
David Williams
e912950317 Restructuring code... 2015-05-14 11:35:04 +02:00
David Williams
49683b4b48 Fixed compile error due to logging code changing scope. 2015-05-14 11:27:19 +02:00
David Williams
54f235e09a Restructuring computeBitmask code. 2015-05-14 11:14:39 +02:00
David Williams
5974a1de9b Restructuring loops... 2015-05-14 10:52:07 +02:00
David Williams
13fc8c5ba9 Removed unneeded variable. 2015-05-14 07:42:04 +02:00
David Williams
c4ce66dec5 Replaced 2D pPreviousBitmask and pCurrentBitmask with 3D pBitmask. 2015-05-14 07:15:36 +02:00
David Williams
2b22213bec Replaced 2D arrays with single 3D array when tracking existing vertices. 2015-05-13 23:05:58 +02:00
David Williams
5ce0d9c3e0 Cutting down and simplifying Marching Cubes code (also now slower...). 2015-05-10 19:43:09 +02:00
David Williams
3937dc3c61 Applying test to a larger region so we can more easily benchmark the performance (otherwise the VS profiler can fail if the test runs too quickly). 2015-05-10 11:40:58 +02:00
David Williams
16fca2529b Moved Config.h out of the 'Impl' folder. It should probably be considered part of the public API as users may want to adjust it for their purposes. 2015-05-09 08:58:14 +02:00
David Williams
65b0d1c3c5 Moved parts of the logging code into the public API (so users can redirect logs). 2015-05-09 08:52:30 +02:00
David Williams
040dc37057 Changed header guards. 2015-05-08 21:19:39 +02:00
David Williams
c2bb64d055 Renamed Logging.h to LoggingImpl.h
Added missing files to CMakeLists.txt
2015-05-08 21:18:10 +02:00
David Williams
09253a7bcc Removed a few uses of '#ifdef SWIG', mainly from areas where they would no longer work. e.g where the code has been templatized since the #ifdef was added so we can see that the SWIG version of the code is out of date and won't build anyway. 2015-05-08 21:08:43 +02:00
David Williams
3c31643e4f Exceptions are now part of the PolyVox public API (client code may need to catch them) but the utility macros we use to throw them are still private implementation details. 2015-05-08 16:15:11 +02:00
David Williams
4887fc2701 For work splitting error handling code into separate files for asserts vs. exceptions. 2015-05-08 15:59:17 +02:00
David Williams
a61d4556c1 Moved assertion code to separate file. 2015-05-08 15:31:17 +02:00
David Williams
e9bde59fbc Moved more code into PlatformDefinitions.h 2015-05-08 15:20:29 +02:00
David Williams
64fa004102 Comments and tidying of PlatformDefinitions.h 2015-05-08 15:16:26 +02:00
David Williams
ed64106237 More removing of API import/export macros. 2015-05-08 15:09:44 +02:00
David Williams
d8a422955d Now that PolyVox is header only we have no further use for the POLYVOX_API/LOCAL/SHARED macros which wrap API import/export. 2015-05-08 15:04:17 +02:00
David Williams
b36548ff20 Missed a couple of files during header renaming process. 2015-05-08 15:02:48 +02:00
David Williams
2a8e0a5f7b Renamed 'Typedef.h' to 'PlatformDefinitions.h'. 2015-05-08 14:57:12 +02:00
David Williams
64c30044b0 Moving some macros. 2015-05-08 14:50:10 +02:00
David Williams
f16a247934 Changed implementation of logging macros.
We have observed some strange performance-related behavior as described here: https://stackoverflow.com/questions/29652787/adding-stringstream-cout-hurts-performance-even-when-the-code-is-never-called

This set of changes addresses this problem. The old macros would simply expand the logging code in place, whereas we now have logging functions and the macros call these. Overall I believe it is tidier.
2015-05-07 22:58:00 +02:00
David Williams
4dadbbffd1 Added comment about performance for the future. 2015-04-26 09:25:57 +02:00
David Williams
1d925a59a1 Fixed crash. 2015-04-16 16:47:12 +02:00
David Williams
9947425169 Fix for code which determines which old chunk to delete. 2015-04-15 16:58:24 +02:00
David Williams
cd752b4459 Merge branch 'feature/custom-chunk-hash-table' into develop 2015-04-14 23:43:41 +02:00
David Williams
6ff7b46e26 Merge branch 'develop' into feature/custom-chunk-hash-table 2015-04-14 23:30:29 +02:00
Matt Williams
32c30471a6 Make m_uChunkSideLengthMinusOne const 2015-04-14 15:01:10 +01:00
David Williams
12fdeb8e52 Removed old chunk map.
Removed flush(Region) function as it's a bit trickier to implement with the new hash table, and it's not clear that we need it.
2015-04-13 23:51:18 +02:00
David Williams
1e0e8a8c16 Fixed calculation of volume size in bytes. 2015-04-13 23:48:33 +02:00
David Williams
f7c1962773 Removed commented-out code. 2015-04-13 23:32:23 +02:00
David Williams
143c9fd08d Made test 10x longer. 2015-04-13 21:34:59 +02:00
David Williams
37c35a08db Added code to ensure the number of chunks doesn't go over our target limit. 2015-04-13 21:30:59 +02:00
David Williams
8757f1e53e Removed unneeded assert. 2015-04-13 21:17:19 +02:00
David Williams
5dd46c4bcf Merge branch 'develop' into feature/custom-chunk-hash-table 2015-04-13 21:07:48 +02:00
David Williams
64be18cd14 Tidied up loop for inserting chunk into array. 2015-04-12 20:55:49 +02:00
David Williams
af70096fcc Tidying and adding comments. 2015-04-12 16:46:43 +02:00
David Williams
99390580dd Replaced number with constant. 2015-04-12 10:35:12 +02:00
David Williams
c4cccf9043 Replaced double for loop with cleaner do-while loop. 2015-04-12 09:55:30 +02:00
David Williams
f35581506c Minor optimization - only creating vector if we are going to use it. 2015-04-12 09:42:15 +02:00
David Williams
54903150e9 Merge branch 'develop' into feature/custom-chunk-hash-table 2015-04-12 09:19:14 +02:00
David Williams
c562341db0 Added a second PagedVolume to the tests with much higher allowed memory usage. This makes more sense when testing random access, as low permitted memory usage causes disk IO to become the bottleneck. 2015-04-10 16:56:19 +02:00
David Williams
b90f0d4e15 Made the FilePager a little more robust regarding filename conflicts. 2015-04-10 16:47:50 +02:00
David Williams
8bd013f28e Added RawVolume version of test as well. 2015-04-10 16:14:29 +02:00
David Williams
887ecc1aaa Adding test to measure voxel access times when sampling the volume randomly. 2015-04-10 16:09:35 +02:00
David Williams
a2fe1944af Initial work on replacing std::unordered_map with a specialized hash table for looking up chunks based on their 3D position. 2015-04-09 23:44:25 +02:00
David Williams
27a59f34bc Merge branch 'feature/morton-encoding' into develop 2015-04-05 17:44:27 +02:00
David Williams
4c24d61408 Added another function for backwards compatibility. 2015-04-05 12:03:12 +02:00
David Williams
c887d1444f Added utility function for people who already have data in linear order, to convert it to Morton order. 2015-04-05 10:14:25 +02:00
David Williams
d521b08cf9 Added comment. 2015-04-04 09:57:31 +02:00
David Williams
dec06bcfe4 Added caching of variable. 2015-04-04 09:49:12 +02:00
David Williams
77db90ac30 Removed unneeded variable. 2015-04-04 09:42:46 +02:00
David Williams
0d36c416f2 Tidied up macros. 2015-04-04 09:18:51 +02:00
David Williams
3ca0222b19 Applied simplified test when going in the negative direction as well. 2015-04-04 00:08:20 +02:00
David Williams
d1bcaec2c5 This commit knocks about 30% off the run time of the sampler tests by using a more efficient check for whether we are near the edge of the chunk. 2015-04-02 23:11:19 +02:00
David Williams
d41a7d2747 Removed redundant samplers. 2015-04-02 21:35:50 +02:00
David Williams
135aa96bdf Further fixes for move...() functions. 2015-04-01 23:34:57 +02:00
David Williams
056cae39b5 Fixed sampler move...() functions to work with Morton ordering. 2015-04-01 22:57:22 +02:00
David Williams
b518978cd6 Enlarged lookup tables to 256 elements. 2015-04-01 22:34:42 +02:00
David Williams
65f39e7b57 Made the values signed ints, as otherwise the casting was doing something strange on 64-bit systems. 2015-04-01 16:29:19 +02:00
David Williams
5d220c5d57 Added extra lookup tables to avoid the need to multiply y/z deltas by 2/4 each time. 2015-03-31 23:58:01 +02:00
David Williams
60612c5583 Implemented use of delta for the rest of the peek functions. 2015-03-31 19:55:22 +02:00
David Williams
afd0650230 Implemented peeking in positive x and negative x directions using Matt's delta lookup table. 2015-03-31 16:33:56 +02:00
David Williams
120b8e84cc Added position in chunk and pointer to current chunk data to sampler. 2015-03-30 23:33:51 +02:00
David Williams
d34c1d227c Merge branch 'develop' into feature/morton-encoding 2015-03-30 15:38:34 +02:00
David Williams
5847219331 Fixed bug with chunk timestamp not being updated. 2015-03-30 15:36:28 +02:00
David Williams
b415e5c5f3 calculateAmbientOcclusion() now works with both RawVolume and PagedVolume. 2015-03-30 11:44:25 +02:00
David Williams
d000616d3e Revert "Ambient occlusion test now uses RawVolume, as it need a fixed size volume to create a temporary array."
This reverts commit 396d1cfc599e6837cf38bc1a95e680e9721ea844.
2015-03-30 11:24:48 +02:00
David Williams
413bb95b1a Passing parameter as const ref. 2015-03-30 11:01:08 +02:00
David Williams
7f96005985 Commented out optimized path in sampler as it doesn't work now that we are using Morton ordering for the data in chunks. However, we can probably reinstate such a fast path if we give some thought as to how it should be done. 2015-03-29 09:58:28 +02:00
David Williams
d3b2dab1ac Switched to using lookup tables for Morton encoding. 2015-03-29 00:17:27 +01:00
David Williams
d99ed5e624 Implemented morton encoding using standard bit-twidling approach. 2015-03-28 09:46:05 +01:00
David Williams
1c17a7147b Made test do 10 times more iterations. 2015-03-28 08:42:06 +01:00
David Williams
9256f3deb5 Fixed compile warning. 2015-03-27 21:23:31 +01:00
David Williams
322bedc009 Improved test for PagedVolume::Chunk performance. 2015-03-26 23:45:01 +01:00
David Williams
1d24b189ca Refactoed test code. 2015-03-25 17:12:11 +01:00
David Williams
931c6cd3ec Added tests for chunk performance. 2015-03-25 16:40:05 +01:00
David Williams
6516c00e62 Merge branch 'feature/optimize-paged-volume' into develop 2015-03-21 16:30:07 +01:00
David Williams
3facd4df41 Removed commented out code. 2015-03-21 16:27:43 +01:00
David Williams
d6c708f869 Merge branch 'develop' into feature/optimize-paged-volume 2015-03-21 16:24:46 +01:00
David Williams
b027cf1a0c Moved common code into function. 2015-03-21 16:22:23 +01:00
David Williams
778238d11d Moved the test for whether we are accessing the same voxel as last time. 2015-03-21 14:57:48 +01:00
David Williams
d477bec540 Revert "Replaced Vector3D with integer as key to map."
This reverts commit e82d6beca1a5cf7e81c546e6dd0243f54ff5d3e6.
2015-03-21 14:41:15 +01:00
David Williams
672c375a7a Revert "Work on using a bitfield to set up chunk key."
This reverts commit 8bd8f8ba7a91de21fd56d4350f3bf8403a84c4b3.
2015-03-21 14:41:10 +01:00
David Williams
5fc0317260 Revert "Added typedef for chunk key type."
This reverts commit 6419c5827bc99d91dd5e96acd17bd507a30dc106.
2015-03-21 14:41:04 +01:00
David Williams
92eaaae765 Revert "Decided to always use a 64-bit chunk key, rather than trying to make it configurable."
This reverts commit 69f6f4ac3713e7a9eee804773a516cc5c3412183.
2015-03-21 14:40:57 +01:00
David Williams
ceeb8f70ce Revert "Going back to building key by shifting instead of using bitfield."
This reverts commit 0d638f98370907b5ffed6b3460e320f4f9b2cf52.
2015-03-21 14:40:49 +01:00
David Williams
0c619ebec7 Revert "Added typedef for ChunkKey."
This reverts commit 905ec27f47a3e2dc1cba3a3a384b2c7532dab03d.
2015-03-21 14:40:30 +01:00
David Williams
f574563672 Revert "New, safer method of packing which makes careful use of casting to avoid problems with e.g. signed integer sign extension."
This reverts commit fd451be2dd7b65671274791105e76bd6a31a0f79.
2015-03-21 14:40:11 +01:00
David Williams
fd451be2dd New, safer method of packing which makes careful use of casting to avoid problems with e.g. signed integer sign extension. 2015-03-21 08:48:45 +01:00
David Williams
905ec27f47 Added typedef for ChunkKey. 2015-03-21 08:12:02 +01:00
David Williams
0d638f9837 Going back to building key by shifting instead of using bitfield. 2015-03-21 08:05:58 +01:00
David Williams
0e995b5140 Fixed some compiler warnings. 2015-03-21 07:40:32 +01:00
David Williams
69f6f4ac37 Decided to always use a 64-bit chunk key, rather than trying to make it configurable. 2015-03-20 23:09:38 +01:00
David Williams
6419c5827b Added typedef for chunk key type. 2015-03-20 16:59:25 +01:00
David Williams
8bd8f8ba7a Work on using a bitfield to set up chunk key. 2015-03-20 15:48:46 +01:00
David Williams
cd48c6f611 Made method const. 2015-03-19 23:08:35 +01:00
David Williams
e82d6beca1 Replaced Vector3D with integer as key to map.
Chunks of voxel data are stored in a map, and it is quite common to need to search the map for a particular chunk. The key type used to be a Vector3D (i.e. the position of the chunk in 3D space) which makes conceptual sense but is relatively slow. Using a Vector3D as a key seems to have overhead, probably in terms of copying and performing comparisons. It seems to be significantly faster to use an integer as a key, so we now take the 3D position and pack it into a single integer by bitshifting.

Naturally this reduces the range of positions we can store - a 32-bit int can only encode 3 x 10-bit values, which means our volume can only be 1024 chunks in each direction (with a chunk often being 32x32x32 voxels). This should still be large enough for most uses, but an upcoming change will allow 64-bit keys to be used (at least on 64-bit builds) which then allows 21 bits of precision  per component. This is so large that it's almost infinite for any practical purposes.
2015-03-15 09:32:42 +01:00
David Williams
d305038c27 Replaced loop with fill. 2015-03-11 23:47:32 +01:00
David Williams
741234e4a5 Small speed improvement by storing variables separately (rather than in Vector3D) to void construction/comparison overhead. 2015-03-09 23:52:56 +01:00
David Williams
99d0a226c8 Tidying up. 2015-03-08 23:48:55 +01:00
David Williams
72abcd8e9c Chunks are now stored with unique_ptr rather than shared_ptr. 2015-03-08 23:30:12 +01:00
Matt Williams
639eb6620f Add 'this' pointer disambiguation.
I guess this didn't fail on MSVC due to the different name lookup rules
the use.

Fixes issue 56.
2015-03-08 12:51:00 +00:00
David Williams
c98ad8c948 Merge branch 'feature/remove-wrap-modes' into develop 2015-03-07 21:19:21 +01:00
David Williams
43c203a2c9 Removed declaration of function for which we already removed the definition. 2015-03-07 17:42:31 +01:00
David Williams
aaa6b1dc15 A PagedVolume must now always be provided with a Pager when it is constructed. 2015-03-07 17:01:07 +01:00
David Williams
5a5b2b3875 Spotted an optimization for computing the voxel position. 2015-03-06 23:03:38 +01:00
David Williams
2c0d9cb9e7 Moved contents of initialize() into constructor. 2015-03-05 23:51:16 +01:00
David Williams
c804190d84 Removed the ability to set the target memory usage after construction, and this is now just done through the constructor. I don't think the functionality was useful, and this simplifies more logic. 2015-03-05 23:42:50 +01:00
David Williams
89550fcd44 Fixed warnings. 2015-03-05 00:04:22 +01:00
David Williams
61bffc9783 Removed some not useful functions. 2015-03-04 23:31:24 +01:00
David Williams
1213a4047a Fully stripped out references to wrap modes. 2015-03-04 23:13:37 +01:00
David Williams
bd6efe8c3c Stuff related to valid regions is being moved from BaseVolum to RawVolume, as PagedVolume is now infinite. 2015-03-04 22:42:14 +01:00
David Williams
d3618ca688 Removed tracking of whether the PagedVolume::Sampler is currently valid. 2015-03-01 23:32:22 +01:00
David Williams
396d1cfc59 Ambient occlusion test now uses RawVolume, as it need a fixed size volume to create a temporary array. 2015-03-01 09:51:45 +01:00
David Williams
e7f41b7e0f More fixing/tidying of test, related to removing volume size limit. 2015-03-01 08:14:30 +01:00
David Williams
bfc7dfdc1b Removed the ability to specify a region in the PagedVolume's constructor, and updated the tests and examples where required. 2015-02-28 23:31:23 +01:00
David Williams
7e03c3e05b Compile fixes and tweaks for tests. 2015-02-28 13:43:17 +01:00
Matt Williams
09c15173f9 Simplify -std=c++0x flag logic
This could be improved in CMake 3.1 by using CXX_STANDARD and
CXX_STANDARD_REQUIRED (see http://stackoverflow.com/a/20165220/96704)
2015-02-28 10:55:01 +00:00
Matt Williams
41d5ea6178 Move FindQt5Test logic inside tests directory 2015-02-28 10:40:05 +00:00
Matt Williams
d9dae773dc Simplify the BUILD_EXAMPLES logic 2015-02-28 10:24:32 +00:00
Matt Williams
32b07659a8 Move all the examples' CMake logic into the examples directory 2015-02-28 10:19:17 +00:00
Matt Williams
969310f327 Make sure we're notifiying if the docs are available 2015-02-28 10:17:56 +00:00
Matt Williams
65f966555d Move Doxygen stuff into include directory where it is actually used 2015-02-28 10:06:56 +00:00
Matt Williams
cb1cd58288 Remove all mention of LIBRARY_TYPE as PolyVox is now header-only 2015-02-28 09:56:12 +00:00
David Williams
f262c0e8f5 Revert "Removing tests which depend on wrap modes, in preparation for removing the wrap modes themselves."
This reverts commit 917d3b8c953c7fa6ceb3ab232dab54b78d57751c.
2015-02-28 09:59:28 +01:00
David Williams
416ae8eb7f Revert "Removed 'AllInternal' part of function name as it is now redundant."
This reverts commit 42e8b2cf4478b40663437df724a2cd292255671f.
2015-02-28 09:59:11 +01:00
David Williams
1853a0fc4e Revert "More work on removing wrap modes."
This reverts commit 6817899e6a9f18d708597f6cdabfffed7d4f671f.
2015-02-28 09:58:41 +01:00
David Williams
6817899e6a More work on removing wrap modes. 2015-02-27 15:12:11 +01:00
David Williams
3ace735619 Work on removing wrap modes. 2015-02-27 13:48:31 +01:00
David Williams
64d010527b Removed old getVoxelAt()/setVoxelAt() functions. they've been flagged as deprecated for a while now, and are replaced by just getVoxel()/setVoxel(). 2015-02-27 11:07:15 +01:00
David Williams
42e8b2cf44 Removed 'AllInternal' part of function name as it is now redundant. 2015-02-26 22:15:19 +01:00
David Williams
917d3b8c95 Removing tests which depend on wrap modes, in preparation for removing the wrap modes themselves. 2015-02-26 17:07:00 +01:00
145 changed files with 6551 additions and 9380 deletions

View File

@ -1,24 +1,26 @@
# Copyright (c) 2007-2012 Matt Williams ################################################################################
# Copyright (c) 2007-2012 David Williams # The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # 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.
################################################################################
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.6) CMAKE_MINIMUM_REQUIRED(VERSION 2.8.6)
@ -33,43 +35,19 @@ MARK_AS_ADVANCED(FORCE POLYVOX_VERSION)
SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON)
include(FeatureSummary) include(FeatureSummary)
FIND_PACKAGE(Doxygen) IF(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") #Maybe "OR MINGW"
OPTION(ENABLE_EXAMPLES "Should the examples be built" ON)
SET(LIBRARY_TYPE "DYNAMIC" CACHE STRING "Should the library be STATIC or DYNAMIC")
SET_PROPERTY(CACHE LIBRARY_TYPE PROPERTY STRINGS DYNAMIC STATIC)
IF(WIN32)
SET(LIBRARY_TYPE "STATIC")
ENDIF()
# Qt is required for building the tests, the example and optionally for bundling the documentation
find_package(Qt5Test 5.2)
find_package(Qt5OpenGL 5.2)
set_package_properties(Doxygen PROPERTIES URL http://www.doxygen.org DESCRIPTION "API documentation generator" TYPE OPTIONAL PURPOSE "Building the API documentation")
set_package_properties(Qt5Test PROPERTIES DESCRIPTION "C++ framework" URL http://qt-project.org)
set_package_properties(Qt5Test PROPERTIES TYPE OPTIONAL PURPOSE "Building the tests")
set_package_properties(Qt5OpenGL PROPERTIES DESCRIPTION "C++ framework" URL http://qt-project.org)
set_package_properties(Qt5OpenGL PROPERTIES TYPE RECOMMENDED PURPOSE "Building the examples")
IF(CMAKE_COMPILER_IS_GNUCXX) #Maybe "OR MINGW"
ADD_DEFINITIONS(-std=c++0x) #Enable C++0x mode ADD_DEFINITIONS(-std=c++0x) #Enable C++0x mode
ENDIF() ENDIF()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
ADD_DEFINITIONS(-std=c++0x) #Enable C++0x mode IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
endif() ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
ENDIF()
ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(include)
OPTION(ENABLE_EXAMPLES "Should the examples be built" ON) OPTION(ENABLE_EXAMPLES "Should the examples be built" ON)
IF(ENABLE_EXAMPLES AND Qt5OpenGL_FOUND) IF(ENABLE_EXAMPLES)
ADD_SUBDIRECTORY(examples/Basic) ADD_SUBDIRECTORY(examples)
ADD_SUBDIRECTORY(examples/Paging)
ADD_SUBDIRECTORY(examples/OpenGL)
ADD_SUBDIRECTORY(examples/SmoothLOD)
ADD_SUBDIRECTORY(examples/DecodeOnGPU)
ADD_SUBDIRECTORY(examples/Python)
SET(BUILD_EXAMPLES ON)
ELSE() ELSE()
SET(BUILD_EXAMPLES OFF) SET(BUILD_EXAMPLES OFF)
ENDIF() ENDIF()
@ -77,22 +55,14 @@ ENDIF()
INCLUDE(Packaging.cmake) INCLUDE(Packaging.cmake)
OPTION(ENABLE_TESTS "Should the tests be built" ON) OPTION(ENABLE_TESTS "Should the tests be built" ON)
IF(ENABLE_TESTS AND Qt5Test_FOUND) IF(ENABLE_TESTS)
INCLUDE(CTest) INCLUDE(CTest)
MARK_AS_ADVANCED(FORCE BUILD_TESTING) MARK_AS_ADVANCED(FORCE BUILD_TESTING)
ADD_SUBDIRECTORY(tests) ADD_SUBDIRECTORY(tests)
SET(BUILD_TESTS ON)
ELSE() ELSE()
SET(BUILD_TESTS OFF) SET(BUILD_TESTS OFF)
ENDIF() ENDIF()
#Check if we will building _and_ bundling the docs
IF(DOXYGEN_FOUND AND QT_QCOLLECTIONGENERATOR_EXECUTABLE)
SET(BUILD_AND_BUNDLE_DOCS ON)
ELSE()
SET(BUILD_AND_BUNDLE_DOCS OFF)
ENDIF()
ADD_SUBDIRECTORY(documentation) ADD_SUBDIRECTORY(documentation)
ADD_SUBDIRECTORY(bindings) ADD_SUBDIRECTORY(bindings)
@ -100,8 +70,7 @@ ADD_SUBDIRECTORY(bindings)
add_feature_info("Examples" BUILD_EXAMPLES "Examples of PolyVox usage") add_feature_info("Examples" BUILD_EXAMPLES "Examples of PolyVox usage")
add_feature_info("Tests" BUILD_TESTS "Unit tests") add_feature_info("Tests" BUILD_TESTS "Unit tests")
add_feature_info("Bindings" BUILD_BINDINGS "SWIG bindings") add_feature_info("Bindings" BUILD_BINDINGS "SWIG bindings")
add_feature_info("API docs" DOXYGEN_FOUND "HTML documentation of the API") add_feature_info("API docs" BUILD_DOCS "HTML documentation of the API")
add_feature_info("Qt Help" BUILD_AND_BUNDLE_DOCS "API docs in Qt Help format")
add_feature_info("Manual" BUILD_MANUAL "HTML user's manual") add_feature_info("Manual" BUILD_MANUAL "HTML user's manual")
feature_summary(WHAT ALL) feature_summary(WHAT ALL)
@ -110,11 +79,9 @@ feature_summary(WHAT ALL)
MESSAGE(STATUS "") MESSAGE(STATUS "")
MESSAGE(STATUS "Summary") MESSAGE(STATUS "Summary")
MESSAGE(STATUS "-------") MESSAGE(STATUS "-------")
MESSAGE(STATUS "Library type: " ${LIBRARY_TYPE})
MESSAGE(STATUS "Build examples: " ${BUILD_EXAMPLES}) MESSAGE(STATUS "Build examples: " ${BUILD_EXAMPLES})
MESSAGE(STATUS "Build tests: " ${BUILD_TESTS}) MESSAGE(STATUS "Build tests: " ${BUILD_TESTS})
MESSAGE(STATUS "Build bindings: " ${BUILD_BINDINGS}) MESSAGE(STATUS "Build bindings: " ${BUILD_BINDINGS})
MESSAGE(STATUS "API Docs available: " ${DOXYGEN_FOUND}) MESSAGE(STATUS "API Docs available: " ${BUILD_DOCS})
MESSAGE(STATUS " - Qt Help bundling: " ${BUILD_AND_BUNDLE_DOCS})
MESSAGE(STATUS "Build manual: " ${BUILD_MANUAL}) MESSAGE(STATUS "Build manual: " ${BUILD_MANUAL})
MESSAGE(STATUS "") MESSAGE(STATUS "")

View File

@ -1,23 +1,26 @@
# Copyright (c) 2010-2012 Matt Williams ################################################################################
# The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # 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.
################################################################################
set(CTEST_PROJECT_NAME "PolyVox") set(CTEST_PROJECT_NAME "PolyVox")
set(CTEST_NIGHTLY_START_TIME "00:00:00 GMT") set(CTEST_NIGHTLY_START_TIME "00:00:00 GMT")

View File

@ -2,21 +2,31 @@
Building PolyVox Building PolyVox
**************** ****************
.. warning ::
Before reading this information, be aware that *you may not actually need to build PolyVox in order to use it*. PolyVox is a header-only library and in many cases it is sufficient to simply copy the ``include/PolyVox`` folder into your source tree. This folder contains all the PolyVox header files, and you can probably then include them directly with ``#include "PolyVox/SomeHeaderHere.h"`` without even needing to change your compiler search paths.
That said, you *will* need to read the instructions below if you want to build the examples, tests, bindings or documentation which may be helpful in getting you started with PolyVox.
Requirements Requirements
============ ============
To build PolyVox you need: To build PolyVox you need:
* `CMake <http://cmake.org>`_ 2.8.3 or greater * `CMake <http://cmake.org>`_ (tested on version 2.8.12.2, later versions should also work)
* A C++ compiler with support for some C++0x features (GCC 4.3 or VC 2010 seem to work) * A C++ compiler with support for some C++11 features (tested on GCC 4.8 and VC 2013)
With the following optional packages: With the following optional packages:
* `Qt <http://qt.nokia.com>`_ for building the tests and the example applications * `Qt version 5.2 of later <https://www.qt.io/>`_ for building the tests and the example applications
* ``qcollectiongenerator`` which comes with Qt Assistant is used for bundling the docs for installation * ``qcollectiongenerator`` which comes with Qt Assistant is used for bundling the docs for installation
* `Doxygen <http://doxygen.org>`_ for building the documentation. Version 1.5.7 is needed to build the Qt Assistant docs. 1.7.0 or greater is recommended * `Doxygen <http://doxygen.org>`_ for building the documentation. Version 1.5.7 is needed to build the Qt Assistant docs. 1.7.0 or greater is recommended
* `Python <http://python.org>`_, `Sphinx <http://sphinx.pocoo.org>`_ and `PyParsing <http://pyparsing.wikispaces.com/>`_ for generating the PolyVox manual in HTML * `Python <http://python.org>`_, `Sphinx <http://sphinx.pocoo.org>`_ and `PyParsing <http://pyparsing.wikispaces.com/>`_ for generating the PolyVox manual in HTML
* Version 2 required - see note below.
* `Python development libraries <http://python.org>`_, `SWIG <http://swig.org/>`_ for generating the Python bindings * `Python development libraries <http://python.org>`_, `SWIG <http://swig.org/>`_ for generating the Python bindings
* Version 3 required - see note below.
.. note ::
Currently we use different versions of Python for generating the documentation (version 2) vs. building the bindings (version 3). However, it is unlikely that you as a user will want to build the documentation as it is available online, or you can view the source *.rst files directly. But if you do want to build both the documentation and the bindings yourself then you will need both versions of Python installed.
Linux Linux
===== =====
@ -51,9 +61,6 @@ The other available settings for PolyVox are:
``ENABLE_BINDINGS`` (``ON`` or ``OFF``) ``ENABLE_BINDINGS`` (``ON`` or ``OFF``)
Should the Python bindings to PolyVox be built. This requires the Python development libraries and SWIG to be installed. Defaults to ``ON``. Should the Python bindings to PolyVox be built. This requires the Python development libraries and SWIG to be installed. Defaults to ``ON``.
``LIBRARY_TYPE`` (``DYNAMIC`` or ``STATIC``)
Choose whether static (``.a``) or dynamic libraries (``.so``) should be built. On Linux ``DYNAMIC`` is the default and on Windows ``STATIC`` is the default.
``CMAKE_BUILD_TYPE`` (``Debug``, ``Release``, ``RelWithDebInfo`` or ``MinSizeRel``) ``CMAKE_BUILD_TYPE`` (``Debug``, ``Release``, ``RelWithDebInfo`` or ``MinSizeRel``)
String option to set the type of build. This will automatically set some compilation flags such as the optimisation level or define ``NDEBUG``. String option to set the type of build. This will automatically set some compilation flags such as the optimisation level or define ``NDEBUG``.
@ -114,14 +121,14 @@ If you do not have Python and Sphinx installed and do not want to install them t
Windows Windows
======= =======
For information about the dependencies, CMake configuration variables and buildable targets look at the Linux build information in the section above. The earlier information about the dependencies, CMake configuration variables and buildable targets is still valid for Windows, so look at the Linux build information in the section above. Then see the notes below on using the CMake GUI.
CMake CMake
----- -----
You need CMake installed so get the binary distribution from `CMake.org <http://cmake.org/cmake/resources/software.html>`_. Install it and run the CMake GUI. You need CMake installed so get the binary distribution from `CMake.org <http://cmake.org/cmake/resources/software.html>`_. Install it and run the CMake GUI.
Point the source directory to the directory holding this file and the build directory to the ``build`` subdirectory. Then, click the ``Configure`` button. Click through the dialog box that appears and once you've clicked ``Finish`` you should see text appearing in the bottom text area. Once this has finished, some options will appear in the top area. The purpose of these options in detailed in the Linux→CMake section above. Once you have set these options to what you please, click ``Configure`` again. If it completes without errors then you can click ``Generate`` which will generate your compilers project files in the build directory. Point the source directory to the PolyVox root directory (the directory holding the 'INSTALL.txt' file) and the build directory to the ``build`` subdirectory. Then, click the ``Configure`` button. Click through the dialog box that appears and once you've clicked ``Finish`` you should see text appearing in the bottom text area. Once this has finished, some options will appear in the top area. The purpose of these options in detailed in the Linux→CMake section above. Once you have set these options to what you please, click ``Configure`` again. If it completes without errors then you can click ``Generate`` which will generate your compilers project files in the build directory.
Building Building
-------- --------

View File

@ -1,20 +0,0 @@
Copyright (c) 2005-2012 David Williams and Matthew Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.

21
LICENSE.txt Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 David Williams and Matthew Williams
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.

View File

@ -1,23 +1,26 @@
# Copyright (c) 2009-2012 Matt Williams ################################################################################
# The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
################################################################################
#INCLUDE(InstallRequiredSystemLibraries) #INCLUDE(InstallRequiredSystemLibraries)

View File

@ -1,5 +1,8 @@
PolyVox - The voxel management and manipulation library PolyVox - The voxel management and manipulation library
======================================================= =======================================================
PolyVox is the core technology which lies behind our games. It is a fast, lightweight C++ library for the storage and processing of volumetric (voxel-based) environments. It has applications in both games and medical/scientific visualisation, and is released under the terms of the `zlib license <http://www.tldrlegal.com/l/ZLIB>`_. .. attention ::
This system is no longer under active development. For more details please see this blog post: http://www.volumesoffun.com/wrapping-up-polyvox-development-to-focus-on-cubiquity-2/
PolyVox is the core technology which lies behind our games. It is a fast, lightweight C++ library for the storage and processing of volumetric (voxel-based) environments. It has applications in both games and medical/scientific visualisation, and is released under the terms of the `MIT license <https://www.tldrlegal.com/l/mit>`_.
PolyVox is a relatively low-level library, and you will need experience in C++ and computer graphics/shaders to use it effectively. It is designed to be easily integrated into existing applications and is independent of your chosen graphics API. For more details please see `this page <http://www.volumesoffun.com/polyvox-about/>`_ on our website. PolyVox is a relatively low-level library, and you will need experience in C++ and computer graphics/shaders to use it effectively. It is designed to be easily integrated into existing applications and is independent of your chosen graphics API. For more details please see `this page <http://www.volumesoffun.com/polyvox-about/>`_ on our website.

View File

@ -1,23 +1,26 @@
# Copyright (c) 2009-2013 Matt Williams ################################################################################
# The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # 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.
################################################################################
option(ENABLE_BINDINGS "Build bindings" OFF) #Off by default option(ENABLE_BINDINGS "Build bindings" OFF) #Off by default
if(ENABLE_BINDINGS) if(ENABLE_BINDINGS)
@ -38,7 +41,7 @@ if(ENABLE_BINDINGS)
set(CMAKE_SWIG_FLAGS "") set(CMAKE_SWIG_FLAGS "")
set_source_files_properties(PolyVoxCore.i PROPERTIES CPLUSPLUS ON) set_source_files_properties(PolyVoxCore.i PROPERTIES CPLUSPLUS ON)
include_directories(${PolyVoxCore_BINARY_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include/PolyVoxCore) include_directories(${PolyVoxHeaders_SOURCE_DIR} ${PolyVoxHeaders_SOURCE_DIR}/PolyVox)
if(PYTHONLIBS_FOUND) if(PYTHONLIBS_FOUND)
include_directories(${PYTHON_INCLUDE_PATH}) include_directories(${PYTHON_INCLUDE_PATH})
link_directories(${PolyVoxCore_BINARY_DIR}) link_directories(${PolyVoxCore_BINARY_DIR})
@ -46,7 +49,7 @@ if(ENABLE_BINDINGS)
#set_source_files_properties(PolyVoxCore.i PROPERTIES SWIG_FLAGS "-builtin") #set_source_files_properties(PolyVoxCore.i PROPERTIES SWIG_FLAGS "-builtin")
set(SWIG_MODULE_PolyVoxCorePython_EXTRA_FLAGS "-py3") set(SWIG_MODULE_PolyVoxCorePython_EXTRA_FLAGS "-py3")
swig_add_module(PolyVoxCorePython python PolyVoxCore.i) swig_add_module(PolyVoxCorePython python PolyVoxCore.i)
swig_link_libraries(PolyVoxCorePython ${PYTHON_LIBRARIES} PolyVoxCore) swig_link_libraries(PolyVoxCorePython ${PYTHON_LIBRARIES})
set_target_properties(${SWIG_MODULE_PolyVoxCorePython_REAL_NAME} PROPERTIES OUTPUT_NAME _PolyVoxCore) set_target_properties(${SWIG_MODULE_PolyVoxCorePython_REAL_NAME} PROPERTIES OUTPUT_NAME _PolyVoxCore)
#set_target_properties(${SWIG_MODULE_PolyVoxCore_REAL_NAME} PROPERTIES SUFFIX ".pyd") #set_target_properties(${SWIG_MODULE_PolyVoxCore_REAL_NAME} PROPERTIES SUFFIX ".pyd")
SET_PROPERTY(TARGET ${SWIG_MODULE_PolyVoxCorePython_REAL_NAME} PROPERTY FOLDER "Bindings") SET_PROPERTY(TARGET ${SWIG_MODULE_PolyVoxCorePython_REAL_NAME} PROPERTY FOLDER "Bindings")
@ -54,7 +57,7 @@ if(ENABLE_BINDINGS)
set(SWIG_MODULE_PolyVoxCoreCSharp_EXTRA_FLAGS "-dllimport;PolyVoxCoreCSharp") #This _should_ be inside UseSWIG.cmake - http://www.cmake.org/Bug/view.php?id=13814 set(SWIG_MODULE_PolyVoxCoreCSharp_EXTRA_FLAGS "-dllimport;PolyVoxCoreCSharp") #This _should_ be inside UseSWIG.cmake - http://www.cmake.org/Bug/view.php?id=13814
swig_add_module(PolyVoxCoreCSharp csharp PolyVoxCore.i) swig_add_module(PolyVoxCoreCSharp csharp PolyVoxCore.i)
swig_link_libraries(PolyVoxCoreCSharp PolyVoxCore) swig_link_libraries(PolyVoxCoreCSharp)
SET_PROPERTY(TARGET ${SWIG_MODULE_PolyVoxCoreCSharp_REAL_NAME} PROPERTY FOLDER "Bindings") SET_PROPERTY(TARGET ${SWIG_MODULE_PolyVoxCoreCSharp_REAL_NAME} PROPERTY FOLDER "Bindings")
else() else()
set(BUILD_BINDINGS OFF CACHE BOOL "Will the bindings be built" FORCE) set(BUILD_BINDINGS OFF CACHE BOOL "Will the bindings be built" FORCE)

View File

@ -1,7 +1,7 @@
%module PolyVoxCore %module PolyVoxCore
#define POLYVOX_API #define POLYVOX_API
%include "Impl/TypeDef.h" %include "Impl/PlatformDefinitions.h"
#define __attribute__(x) //Silence DEPRECATED errors #define __attribute__(x) //Silence DEPRECATED errors
//This macro allows us to use Python properties on our classes //This macro allows us to use Python properties on our classes
@ -84,7 +84,7 @@ EXTRACTOR(shortname, RawVolume)
//%include "RLEBlockCompressor.i" //%include "RLEBlockCompressor.i"
%include "BaseVolume.i" %include "BaseVolume.i"
//%include "RawVolume.i" //%include "RawVolume.i"
%include "PagedVolume.i" //%include "PagedVolume.i"
//%include "VertexTypes.i" //%include "VertexTypes.i"
//%include "SurfaceMesh.i" //%include "SurfaceMesh.i"
////%include "MarchingCubesSurfaceExtractor.i" ////%include "MarchingCubesSurfaceExtractor.i"

View File

@ -1,23 +1,26 @@
# Copyright (c) 2010-2012 Matt Williams ################################################################################
# The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # 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.
################################################################################
find_program(SPHINXBUILD_EXECUTABLE sphinx-build DOC "The location of the sphinx-build executable") find_program(SPHINXBUILD_EXECUTABLE sphinx-build DOC "The location of the sphinx-build executable")

View File

@ -5,11 +5,11 @@ PolyVox includes a number of error handling features designed to help you identi
Logging Logging
======= =======
PolyVox has a simple logging mechanism which allows it to write messages with an associated severity (from Debug up to Fatal). This logging mechanism is not really intended for use by client code (i.e. calling the logging macros from your own application) but you can of course do so at your own risk. However, it is possible to redirect the output of these logging functions so you can integrate them with your applications logging framework or suppress them completely. PolyVox has a simple logging mechanism which allows it to write messages with an associated severity (from Debug up to Fatal). This logging mechanism is not really intended for use by client code (i.e. calling the logging macros from your own application) but you can of course do so at your own risk. However, it is possible to redirect the output of these logging functions so you can integrate them with your application's logging framework or suppress them completely.
Fatal messages are only issued in non-recoverable scenarios when the application is about to crash, and may provide the last piece of information you have about what went wrong. Error messages are issued when something has happened which prevents successful completion of a task, for example if you provide invalid parameters to a function (error messages are also issued whenever an exception is thrown). Warning messages mean the system was able to continue but the results may not be what you expected. Info messages are used for general information about what PolyVox is doing. Debug and trace messages produce very verbose output and a lot of detail about what PolyVox is doing internally. In general, debug messages are used for tasks the user has directly initiated (e.g. they might provide time information for surface extraction) while trace messages are used for things which happen spontaneously (such as data being paged out of memory). Fatal messages are only issued in non-recoverable scenarios when the application is about to crash, and may provide the last piece of information you have about what went wrong. Error messages are issued when something has happened which prevents successful completion of a task, for example if you provide invalid parameters to a function (error messages are also issued whenever an exception is thrown). Warning messages mean the system was able to continue but the results may not be what you expected. Info messages are used for general information about what PolyVox is doing. Debug and trace messages produce very verbose output and a lot of detail about what PolyVox is doing internally. In general, debug messages are used for tasks the user has directly initiated (e.g. they might provide timing information for surface extraction) while trace messages are used for things which happen spontaneously (such as data being paged out of memory).
To redirect log messages you can subclass Logger, create an instance, and set it as active as follows:: To redirect log messages you can subclass Logger, create an instance, and set it as active as follows:
.. sourcecode :: c++ .. sourcecode :: c++
@ -31,26 +31,19 @@ To redirect log messages you can subclass Logger, create an instance, and set it
setLogger(myCustomLogger); setLogger(myCustomLogger);
When shutting down you should then do something like the following:
.. sourcecode :: c++
setLogger(myCustomLogger);
delete myCustomLogger;
Note that the default implementation (DefaultLogger) sends the fatal, error and warning streams to std::cerr, the info stream to std:cout, and that the debug and trace streams are suppressed. Note that the default implementation (DefaultLogger) sends the fatal, error and warning streams to std::cerr, the info stream to std:cout, and that the debug and trace streams are suppressed.
PolyVox logging can be disabled completely in Config.h by undefining POLYVOX_LOG_TRACE_ENABLED through to POLYVOX_LOG_FATAL_ENABLED. Each of these can be disabled individually and the corresponding code will then be completely stripped from PolyVox. This is a compile-time setting - if you wish to change the log level at run-time then in your own implementation you could implement a filtering mechanism which only does something with the messages if some 'log severity' setting is greater than a certain threshold which can be changed at runtime. PolyVox logging can be disabled completely in Config.h by undefining POLYVOX_LOG_TRACE_ENABLED through to POLYVOX_LOG_FATAL_ENABLED. Each of these can be disabled individually and the corresponding code will then be completely stripped from PolyVox. This is a compile-time setting - if you wish to change the log level at run-time then in your own implementation you could implement a filtering mechanism which only does something with the messages if some 'log severity' setting is greater than a certain threshold which can be changed at runtime.
Exceptions Exceptions
========== ==========
Error handling in PolyVox is provided by using the C++ exception mechanism. Exceptions can be thrown for a variety of reasons and your code should be prepared to handle them to prevent your application from crashing. It is possible to disable the throwing of exeptions if they are not supported by your compiler. Error handling in PolyVox is provided by using the C++ exception mechanism. Exceptions can be thrown for a variety of reasons and your code should be prepared to handle them to prevent your application from crashing. It is possible to disable the throwing of exceptions if they are not supported by your compiler.
Usage Usage
----- -----
Most functions in PolyVox will validate their input parameters and throw an exception if the provided values do not meet the function's requirements (which should be specified in the API documentation). However, in certain performance critical cases we choose not to spend time validating the parameters and an exception will not be thrown, though we do still use an assertion if these are enabled. Most functions in PolyVox will validate their input parameters and throw an exception if the provided values do not meet the function's requirements (which should be specified in the API documentation). However, in certain performance critical cases we choose not to spend time validating the parameters and an exception will not be thrown, though we do still use an assertion if these are enabled.
The most notable example of this is when accessing volume data through the get/setVoxel() functions, as these are designed to be very fast. Validating an input position would require multiple conditional operations which we chose to avoid. Therefore, **accessing a voxel outside of a volume will cause undefined behaviour.** When reading voxels it is safer to use the function getVoxelWithWrapping() as this lets you specify how out-of-bounds voxels should be handled. The most notable example of this is when accessing volume data through the get/setVoxel() functions, as these are designed to be very fast. Validating an input position would require multiple conditional operations which we chose to avoid. Therefore, **accessing a voxel outside of a volume will cause undefined behaviour.**
Disabling exceptions Disabling exceptions
-------------------- --------------------
@ -74,4 +67,4 @@ In addition to the C++ exception handling mechanism, PolyVox also makes use of a
Assertions inside PolyVox are enabled by defining 'POLYVOX_ASSERTS_ENABLED' in Config.h and again we may expose this through CMake. Note that the presence of assertions is independant of whether you are building a debug or release version of your application. Assertions inside PolyVox are enabled by defining 'POLYVOX_ASSERTS_ENABLED' in Config.h and again we may expose this through CMake. Note that the presence of assertions is independant of whether you are building a debug or release version of your application.
As a user you are not really expected to encounter an assertions inside PolyVox - they are mostly there for our purposes as developers of the library. So if you hit one in PolyVox then there is a good chance it is a bug in the library, as user errors should have been prevented by throwing an exceptions. Again, there are exceptions to this rule as some speed-critical functions (getVoxel(), etc) do not validate their parameters. As a user you are not really expected to encounter an assertion inside PolyVox - they are mostly there for our purposes as developers of the library. So if you hit one in PolyVox then there is a good chance it is a bug in the library, as user errors should have been prevented by throwing an exceptions. Again, there are exceptions to this rule as some speed-critical functions (getVoxel(), etc) do not validate their parameters.

View File

@ -12,7 +12,7 @@ PolyVox volumes make it easy to access these neighbours, but the situation gets
Having established that edge cases can be problematic, we can now see that storing your data as a set of adjacent volumes is undesirable because these edge cases then exist throughout the data set. This causes a lot of problems such as gaps between pieces of extracted terrain or discontinuities in the computed normals. Having established that edge cases can be problematic, we can now see that storing your data as a set of adjacent volumes is undesirable because these edge cases then exist throughout the data set. This causes a lot of problems such as gaps between pieces of extracted terrain or discontinuities in the computed normals.
The usual reason why people attempt to break their terrain into separate volumes is so that they can perform some more advanced memory management for very big terrain, for example by only loading particular volumes into memory when they are within a certain distance from the camera. However, this kind of paging behaviour is already implemented by the LargeVolume class. The LargeVolume internally stores its data as a set of blocks, and does it in such a way that it is able to perform neighbourhood access across block boundaries. Whenever you find yourself trying to break terrain data into separate volumes you should probably use the LargeVolume instead. The usual reason why people attempt to break their terrain into separate volumes is so that they can perform some more advanced memory management for very big terrain, for example by only loading particular volumes into memory when they are within a certain distance from the camera. However, this kind of paging behaviour is already implemented by the PagedVolume class. The PagedVolume internally stores its data as a set of blocks, and does it in such a way that it is able to perform neighbourhood access across block boundaries. Whenever you find yourself trying to break terrain data into separate volumes you should probably use the PagedVolume instead.
Note that although you should only use a single volume for your data, it is still recommended that you split the mesh data into multiple pieces so that they can be culled against the view frustum, and so that you can update the smaller pieces more quickly when you need to. You can extract meshes from different parts of the volume by passing a Region to the surface extractor. Note that although you should only use a single volume for your data, it is still recommended that you split the mesh data into multiple pieces so that they can be culled against the view frustum, and so that you can update the smaller pieces more quickly when you need to. You can extract meshes from different parts of the volume by passing a Region to the surface extractor.
@ -20,6 +20,6 @@ Lastly, note that there are exceptions to the 'one volume' rule. An example migh
Can I combine smooth meshes with cubic ones? Can I combine smooth meshes with cubic ones?
-------------------------------------------- --------------------------------------------
We have never attempted to do this but in theory it should be possible. One option is simply to generate two meshes (one using the MarchingCubesSurfaceExtractor and the other using the CubicSurfaceExtractor) and render them on top of each other while allowing the depth buffer to resolve the intersections. Combining these two meshes into a single mesh is likely to be difficult as they use different vertex formats and have different texturing requirements (see the document on texture mapping). We have never attempted to do this but in theory it should be possible. One option is simply to generate two meshes (one using extractMarchingCubesSurface() and the other using extractCubicSurface()) and render them on top of each other while allowing the depth buffer to resolve the intersections. Combining these two meshes into a single mesh is likely to be difficult as they use different vertex formats and have different texturing requirements (see the document on texture mapping).
An alternative possibility may be to create a new surface extractor based on the Surface Nets (link) algorithm. The idea here is that the mesh would start with a cubic shape, but as the net was stretched it would be smoothed. The degree of smoothing could be controlled by a voxel property which could allow the full range from cubic to smooth to exist in a single mesh. As mentioned above, this may mean that some extra work has to be put into a fragment shader which is capable of texturing this kind of mesh. Come by the forums of you want to discuss this further. An alternative possibility may be to create a new surface extractor based on the Surface Nets (link) algorithm. The idea here is that the mesh would start with a cubic shape, but as the net was stretched it would be smoothed. The degree of smoothing could be controlled by a voxel property which could allow the full range from cubic to smooth to exist in a single mesh. As mentioned above, this may mean that some extra work has to be put into a fragment shader which is capable of texturing this kind of mesh. Come by the forums of you want to discuss this further.

View File

@ -7,20 +7,14 @@ For these reasons it is desirable to reduce the triangle count of the meshes as
Cubic Meshes Cubic Meshes
============ ============
A naive implementation of a cubic surface extractor would generate a mesh containing a quad for voxel face which lies on the boundary between a solid and an empty voxel. The CubicSurfaceExtractor is indeed capable of generating such a mesh, but it also provides the option to merge adjacent quads into a single quad subject to various conditions being satisfied (e.g. the faces must have the same material). This merging process drastically reduces the amount of geometry which must be drawn but does not modify the shape of the mesh. Because of these desirable properties such merging is performed by default, but it can be disabled if necessary. A naive implementation of a cubic surface extractor would generate a mesh containing a quad for each voxel face which lies on the boundary between a solid and an empty voxel. Our extractCubicSurface() function is indeed capable of generating such a mesh, but it also provides the option to merge adjacent quads into a single quad subject to various conditions being satisfied (e.g. the faces must have the same material). This merging process drastically reduces the amount of geometry which must be drawn but does not modify the shape of the mesh. Because of these desirable properties such merging is performed by default, but it can be disabled if necessary.
To our knowledge the only drawback of performing this quad merging is that it can create T-junctions in the resulting mesh. T-junctions are an undesirable property of mesh geometry because they can cause tiny cracks (usually just seen as flickering pixels) to occur between quads. The figure below shows a mesh before quad merging, a mesh where the merged quads have caused T-junctions, and how the resulting rendering might look (note the single pixel holes along the quad border). To our knowledge the only drawback of performing this quad merging is that it can create T-junctions in the resulting mesh. T-junctions are an undesirable property of mesh geometry because they can cause tiny cracks (usually just seen as flickering pixels) to occur between quads. Whether it's a problem in practice depends on hardware precision (16/32 bit), distance from origin, number of transforms which are applied, and probably a number of other factors. We have yet to investigate.
*Add figure here...*
Vertices C and D are supposed to lie exactly along the line which has A and B as its end points, so in theory the mesh should be valid and should render correctly. The reason T-junctions cause a problem in practice is due to limitations of the floating point number representation. Depending on the transformations which are applied, it may be that the positions of C and/or D can not be represented precisely enough to exactly lie on the line between A and B.
*Demo correct mesh. mention we don't have a solution to generate it.*
Whether it's a problem in practice depends on hardware precision (16/32 bit), distance from origin, number of transforms which are applied, and probably a number of other factors. We have yet to investigate.
We don't currently have a real solution to this problem. In Voxeliens the borders between voxels were darkened to simulate ambient occlusion and this had the desirable side effect of making any flickering pixels very hard to see. It's also possible that anti-aliasing strategies can reduce the problem, and storing vertex positions as integers may help as well. Lastly, it may be possible to construct some kind of post-process which would repair the image where it identifies single pixel discontinuities in the depth buffer. We don't currently have a real solution to this problem. In Voxeliens the borders between voxels were darkened to simulate ambient occlusion and this had the desirable side effect of making any flickering pixels very hard to see. It's also possible that anti-aliasing strategies can reduce the problem, and storing vertex positions as integers may help as well. Lastly, it may be possible to construct some kind of post-process which would repair the image where it identifies single pixel discontinuities in the depth buffer.
For more information on this topic we suggest the following article series: `Meshing in Voxel Engines <https://blackflux.wordpress.com/2014/02/23/meshing-in-voxel-engines-part-1/>`_
Smooth Meshes Smooth Meshes
============= =============
Level of detail for smooth meshes is a lot more complex than for cubic ones, and we'll admit upfront that we do not currently have a good solution to this problem. None the less, we do have a couple of partial solutions which you might be able to use or adapt for your specific scenario. Level of detail for smooth meshes is a lot more complex than for cubic ones, and we'll admit upfront that we do not currently have a good solution to this problem. None the less, we do have a couple of partial solutions which you might be able to use or adapt for your specific scenario.
@ -33,16 +27,16 @@ The VolumeResampler class can be used to copy volume data from a source region t
One of the problems with this approach is that the lower resolution mesh does not *exactly* line up with the higher resolution mesh, and this can cause cracks to be visible where the two meshes meet. The SmoothLOD sample attempts to avoid this problem by overlapping the meshes slightly but this may not be effective in all situations or from all viewpoints. One of the problems with this approach is that the lower resolution mesh does not *exactly* line up with the higher resolution mesh, and this can cause cracks to be visible where the two meshes meet. The SmoothLOD sample attempts to avoid this problem by overlapping the meshes slightly but this may not be effective in all situations or from all viewpoints.
An alternative is the Transvoxel algorithm (link) developed by Eric Lengyel. This essentially extends the original Marching Cubes lookup table with additional entries which handle seamless transitions between LOD levels, and it is a very promising solution to level of detail for voxel terrain. At this point in time we do not have an implementation of this algorithm but work is being undertaking in the area. For the latest developments see: http://www.volumesoffun.com/phpBB3/viewtopic.php?f=2&t=338 An alternative is the `Transvoxel algorithm <http://www.terathon.com/voxels/>`_ developed by Eric Lengyel. This essentially extends the original Marching Cubes lookup table with additional entries which handle seamless transitions between LOD levels, and it is a very promising solution to level of detail for voxel terrain. At this point in time we do not have an implementation of this algorithm.
However, in all volume reduction approaches there is some uncertainty about how materials should be handled. Creating a lower resolution volume means that several voxel values from the high resolution volume need to be combined into a single value. For density values this is straightforward as a simple average gives good results, but it is not clear how this extends to material identifiers. Averaging them doesn't make sense, and it is hard to imagine an approach which would not lead to visible artifacts as LOD levels change. Perhaps the visible effects can be reduced by blending between two LOD levels, but more investigation needs to be done here. However, in all volume reduction approaches there is some uncertainty about how materials should be handled. Creating a lower resolution volume means that several voxel values from the high resolution volume need to be combined into a single value. For density values this is straightforward as a simple average gives good results, but it is not clear how this extends to material identifiers. Averaging them doesn't make sense, and it is hard to imagine an approach which would not lead to visible artifacts as LOD levels change. Perhaps the visible effects can be reduced by blending between two LOD levels, but more investigation needs to be done here.
Mesh Simplification Mesh Simplification
------------------- -------------------
The other main approach is to generate the mesh at the full resolution and then reduce the number of triangles using a postprocessing step. This can draw on the large body of mesh simplification research (link to survey) and typically involves merging adjacent faces or collapsing vertices. When using this approach there are a couple of additional complications compared to the implementations which are normally seen. The other main approach is to generate the mesh at the full resolution and then reduce the number of triangles using a postprocessing step. This can draw on the large body of mesh simplification research and typically involves merging adjacent faces or collapsing vertices. When using this approach there are a couple of additional complications compared to the implementations which are normally seen.
The first additional complication is that the decimation algorithm needs to preserve material boundaries so that they don't move between LOD levels. When choosing whether a particular simplification can be made (i.e deciding if one vertex can be collapsed on to another or whether two faces can be merged) a metric is usually used to determine how much the simplification would affect the visual appearance of the mesh. When working with smooth voxel meshes this metric needs to also consider the material identifiers. The first additional complication is that the decimation algorithm needs to preserve material boundaries so that they don't move between LOD levels. When choosing whether a particular simplification can be made (i.e deciding if one vertex can be collapsed on to another or whether two faces can be merged) a metric is usually used to determine how much the simplification would affect the visual appearance of the mesh. When working with smooth voxel meshes this metric needs to also consider the material identifiers.
We also need to ensure that the metric preserves the geometric boundary of the mesh, so that no cracks are visible when a simplified mesh is place next to an original one. Maintaining this geometric boundary can be difficult, as the straightforward approach of locking the edge vertices in place will tend to limit the amount of simplification which can be performed. Alternatively, cracks can be allowed to develop if they are later hidden through the use of 'skirts' around the resulting mesh. We also need to ensure that the metric preserves the geometric boundary of the mesh, so that no cracks are visible when a simplified mesh is placed next to an original one. Maintaining this geometric boundary can be difficult, as the straightforward approach of locking the edge vertices in place will tend to limit the amount of simplification which can be performed. Alternatively, cracks can be allowed to develop if they are later hidden through the use of 'skirts' around the resulting mesh.
PolyVox used to contain code for performing simplification of the smooth voxel meshes, but unfortunately it had significant performance and functionality issues. Therefore it has been deprecated and it will be removed in a future version of the library. We will instead investigate the use of external mesh simplification libraries and OpenMesh (link) may be a good candidate here. PolyVox used to contain code for performing simplification of the smooth voxel meshes, but unfortunately it had significant performance and functionality issues and so it has been removed. We will instead investigate the use of external mesh simplification libraries and `OpenMesh <http://www.openmesh.org/>`_ may be a good candidate here.

View File

@ -11,7 +11,7 @@ Normal Calculation for Smooth Meshes
------------------------------------ ------------------------------------
When working with smooth voxel terrain meshes, PolyVox provides vertex normals as part of the extracted surface mesh. A common approach for computing these normals would be to compute normals for each face in the mesh, and then compute the vertex normals as a weighted average of the normals of the faces which share it. Actually this is not the approach used by PolyVox, as PolyVox instead computes the vertex normals directly from the underlying volume data. When working with smooth voxel terrain meshes, PolyVox provides vertex normals as part of the extracted surface mesh. A common approach for computing these normals would be to compute normals for each face in the mesh, and then compute the vertex normals as a weighted average of the normals of the faces which share it. Actually this is not the approach used by PolyVox, as PolyVox instead computes the vertex normals directly from the underlying volume data.
More specifically, PolyVox is able to compute the *gradient* of the volume data at any given point using well established image processing methods. The normalised gradient value is used as the vertex normal and in general it is smoother than the value computed by averaging neighbouring faces. Actually there are two approaches to this gradient computation known as *Central Differencing* and *Sobel Filter*. The central differencing approach is generally recommended but the Sobel filter can be used to obtain slightly smoother results but with lower performance. See the MarchingCubesSurfaceExtractor documentation for details on how to select between these (check this exists...). More specifically, PolyVox is able to compute the *gradient* of the volume data at any given point using well established image processing methods. The normalised gradient value is used as the vertex normal and in general it is smoother than the value computed by averaging neighbouring faces.
Normal Calculation for Cubic Meshes Normal Calculation for Cubic Meshes
----------------------------------- -----------------------------------
@ -19,18 +19,17 @@ For cubic meshes PolyVox doesn't actually generate any vertex normals at all, an
Therefore PolyVox does not generate per-vertex normals for cubic meshes, and as a result the cubic mesh's vertices are both smaller and less numerous. Of course, we still need a way to obtain normals for lighting calculations and so our suggestion is to compute the normals in a fragment program using the *derivative operations* which are provided by modern graphics hardware. Therefore PolyVox does not generate per-vertex normals for cubic meshes, and as a result the cubic mesh's vertices are both smaller and less numerous. Of course, we still need a way to obtain normals for lighting calculations and so our suggestion is to compute the normals in a fragment program using the *derivative operations* which are provided by modern graphics hardware.
The description here is rather oversimplified, but the idea behind these operation is that they can tell you how much a variable has changed between two adjacent pixels. If we use our fragment world space position as the input to these derivative operations then we can obtain two vectors which lie on the surface of our face. The cross product of these then gives us a vector which is perpendicular to both and which is therefore our normal. The description here is rather oversimplified, but the idea behind these operations is that they can tell you how much a variable has changed between two adjacent pixels. If we use our fragment world space position as the input to these derivative operations then we can obtain two vectors which lie on the surface of our face. The cross product of these then gives us a vector which is perpendicular to both and which is therefore our normal.
Further information about the derivative operations can be found in the OpenGL/Direct3D API documentation, but the implementation in code is quite simple. Firstly you need to make sure that you have access to the fragments world space position in your shader, which means you need to pass it through from the vertex shader. Then you can use the following code in your fragment shader: Further information about the derivative operations can be found in the OpenGL/Direct3D API documentation, but the implementation in code is quite simple. Firstly you need to make sure that you have access to the fragment's world space position in your shader, which means you need to pass it through from the vertex shader. Then you can use the following code in your fragment shader:
.. sourcecode:: glsl .. sourcecode:: glsl
vec3 worldNormal = cross(dFdy(inWorldPosition.xyz), dFdx(inWorldPosition.xyz)); vec3 worldNormal = cross(dFdy(inWorldPosition.xyz), dFdx(inWorldPosition.xyz));
worldNormal = normalize(worldNormal); worldNormal = normalize(worldNormal);
**TODO: Check the normal direction** .. note ::
Depending on your graphics API and/or engine setup, you may actually need to flip the resulting normal.
Similar code can be implemented in HLSL but you may need to invert the normal due to coordinate system differences between the two APIs. Also, be aware that it may be necessary to use OpenGL ES XXX extension in order to access this derivative functionality on mobile hardware.
Shadows Shadows
------- -------

View File

@ -5,13 +5,13 @@ The PolyVox library is aimed at experienced games and graphics programmers who w
As a result you will need a decent amount of graphics programming experience to effectively make use of the library. The purpose of this document is to highlight some of the core areas with which you will need to be familiar. In some cases we also provide links to places where you can find more information about the subject in question. As a result you will need a decent amount of graphics programming experience to effectively make use of the library. The purpose of this document is to highlight some of the core areas with which you will need to be familiar. In some cases we also provide links to places where you can find more information about the subject in question.
You should also be aware that voxel terrain is still an open research area and has not yet seen widespread adoption in games and simulations. There are many questions to which we do not currently know the best answer and so you may have to do some research and experimentation yourself when trying to obtain your desired result. Please do let us know if you come up with a trick or technique which you think could benefit other users. You should also be aware that voxel terrain is still an open research area which is only just seeing widespread adoption in games and simulations. There are many questions to which we do not currently know the best answer and so you may have to do some research and experimentation yourself when trying to obtain your desired result. Please do let us know if you come up with a trick or technique which you think could benefit other users.
Programming Programming
=========== ===========
This section describes some of the programming concepts with which you will need to be familiar: This section describes some of the programming concepts with which you will need to be familiar:
**C++:** PolyVox is written using the C++ language and we expect this is what the majority of our users will be developing in. You will need to be familiar with the basic process of building and linking against external libraries as well as setting up your development environment. Note that you do have the option of working with other languages via the SWIG bindings but you may not have as much flexibility with this approach. **C++:** PolyVox is written using the C++ language and we expect this is what the majority of our users will be developing in. Note that you do have the option of working with other languages via the SWIG bindings but you may not have as much flexibility with this approach, and you will need to undertake additional work as the bindings are not currently complete.
**Templates:** PolyVox also makes heavy use of template programming in order to be both fast and generic, so familiarity with templates will be very useful. You shouldn't need to do much template programming yourself but an understanding of them will help you understand errors and resolve any problems. **Templates:** PolyVox also makes heavy use of template programming in order to be both fast and generic, so familiarity with templates will be very useful. You shouldn't need to do much template programming yourself but an understanding of them will help you understand errors and resolve any problems.
@ -23,16 +23,16 @@ Several core graphics principles will be useful in understanding and using PolyV
**Volume representation:** PolyVox revolves around the idea of storing and manipulating volume data and using this as a representation of a 3d world. This is a fairly intuitive extension of traditional heightmap terrain but does require the ability to 'think in 3D'. You will need to understand that data stored in this way can become very large, and understand the idea that paging and compression can be used to combat this. **Volume representation:** PolyVox revolves around the idea of storing and manipulating volume data and using this as a representation of a 3d world. This is a fairly intuitive extension of traditional heightmap terrain but does require the ability to 'think in 3D'. You will need to understand that data stored in this way can become very large, and understand the idea that paging and compression can be used to combat this.
**Mesh representation:** Most PolyVox projects will involve using one of the surface extractors, which output their data as index and vertex buffers. Therefore you will need to understand this representation in order to pass the data to your rendering engine or in order to perform further modifications to it. You can find out about more about this here: (ADD LINK) **Mesh representation:** Most PolyVox projects will involve using one of the surface extractors, which output their data as index and vertex buffers. Therefore you will need to understand this representation in order to pass the data to your rendering engine or in order to perform further modifications to it. You can find out about more about this in the Wikipedia article on `Polygon Meshes <https://en.wikipedia.org/wiki/Polygon_mesh>`_
**Image processing:** For certain advanced application an understanding of image processing methods can be useful. For example the process of blurring an image via a low pass filter can be used to effectively smooth out voxel terrain. There are plans to add more image processing operations to PolyVox particularly with regard to morphological operations which you might want to use to modify your environment. **Image processing:** For certain advanced applications an understanding of image processing methods can be useful. For example, the process of blurring an image via a low pass filter can be used to effectively smooth out voxel terrain. There are plans to add more image processing operations to PolyVox particularly with regard to morphological operations which you might want to use to modify your environment.
Rendering Rendering
========= =========
**Runtime geometry creation:** PolyVox is independent of any particular graphics API which means it outputs its data using API-neutral structures such as index and vertex buffers (as mentioned above). You will need to write the code which converts these structures into a format which your API or engine can understand. This is not a difficult task but does require some knowledge of the rendering technology which you are using. **Runtime geometry creation:** PolyVox is independent of any particular graphics API which means it outputs its data using API-neutral structures such as index and vertex buffers (as mentioned above). You will need to write the code which converts these structures into a format which your API or engine can understand. This is not a difficult task but does require some knowledge of the rendering technology which you are using.
**Scene management:** PolyVox is only responsible for providing you with the mesh data to be displayed, so you application or engine will need to make sensible decisions about how this data should be organised in terms of a spatial structure (octree, bounding volumes tree, etc). It will also need to provide some approach to visibility determination such as frustum culling or a more advanced approach. If you are integrating PolyVox with an existing rendering engine then you should find that many of these aspects are already handled for you. **Scene management:** PolyVox is only responsible for providing you with the mesh data to be displayed, so your application or engine will need to make sensible decisions about how this data should be organised in terms of a spatial structure (octree, bounding volumes tree, etc). It will also need to provide some approach to visibility determination such as frustum culling or a more advanced approach. If you are integrating PolyVox with an existing rendering engine then you should find that many of these aspects are already handled for you.
**Shader programming:** The meshes which are generated by PolyVox are very basic in terms of the vertex data they provide. You get vertex positions, a material identifier, and sometimes vertex normals. It is the responsibility of application programmer to decide how to use this data to create visually interesting renderings. This means you will almost certainly want to make use of shader programs. Of course, in our texturing (LINK) and lighting (LINK) documents you will find many ideas and common solutions, but you will need strong shader programming experience to make effective use of these. **Shader programming:** The meshes which are generated by PolyVox are very basic in terms of the vertex data they provide. You get vertex positions, sometimes vertex normals, and sometimes additional data copied/interpolated from the volume. It is the responsibility of application programmer to decide how to use this data to create visually interesting renderings. This means you will almost certainly want to make use of shader programs. Of course, in our :doc:`texturing <texturing>` and :doc:`lighting <lighting>` documents you will find many ideas and common solutions, but you will need strong shader programming experience to make effective use of these.
If you don't have much experience with shader programming then there are many free resources available. The Cg Tutorial (LINK) provides a good introduction here (the concepts are applicable to other shader languages) as does the documentation for the main graphics (LINK to OpenGL docs) APIs (Link to D3D docs). there is nothing special about PolyVox meshes so you would be advised to practice development on simple meshes such as spheres and cubes before trying to apply it to the output of the mesh extractors. If you don't have much experience with shader programming then there are many free resources available. The Wikipedia page on `Shaders <https://en.wikipedia.org/wiki/Shader>`_ may provide a starting point, as may the documentation for the `OpenGL <https://www.opengl.org/documentation/>`_ and `Direct3D <https://msdn.microsoft.com/en-us/library/windows/desktop/ff476080>`_ libraries. There is nothing special about PolyVox meshes so you would be advised to practice development on simple meshes such as spheres and cubes before trying to apply it to the output of the mesh extractors.

View File

@ -31,7 +31,7 @@ The rational in the cubic case is almost the opposite. For Minecraft style terra
Triplanar Texturing Triplanar Texturing
------------------- -------------------
The most common approach to texture mapping smooth voxel terrain is to use *triplanar texturing*. The basic idea is to project a texture along all three main axes and blend between the three texture samples according to the surface normal. As an example, suppose that we wish to write a fragment shader to apply a single texture to our terrain, and assume that we have access to both the world space position of the fragment and also its normalised surface normal. Also, note that your textures should be set to wrap because the world space position will quickly go outside the bounds of 0.0-1.0. The world space position will need to have been passed through from earlier in the pipeline while the normal can be computed using one of the approaches in the lighting (link) document. The shader code would then look something like this [footnote: code is untested as is simplified compared to real world code. hopefully it compiles, but if not it should still give you an idea of how it works]: The most common approach to texture mapping smooth voxel terrain is to use *triplanar texturing*. The basic idea is to project a texture along all three main axes and blend between the three texture samples according to the surface normal. As an example, suppose that we wish to write a fragment shader to apply a single texture to our terrain, and assume that we have access to both the world space position of the fragment and also its normalised surface normal. Also, note that your textures should be set to wrap because the world space position will quickly go outside the bounds of 0.0-1.0. The world space position will need to have been passed through from earlier in the pipeline while the normal can be computed using one of the approaches in the :doc:`lighting <Lighting>` document. The shader code would then look something like this [footnote: code is untested as is simplified compared to real world code. hopefully it compiles, but if not it should still give you an idea of how it works]:
.. sourcecode:: glsl .. sourcecode:: glsl
@ -67,9 +67,9 @@ Using the material identifier
----------------------------- -----------------------------
So far we have assumed that only a single material is being used for the entire voxel world, but this is seldom the case. It is common to associate a particular material with each voxel so that it can represent rock, wood, sand or any other type of material as required. The usual approach is to store a simple integer identifier with each voxel, and then map this identifier to material properties within your application. So far we have assumed that only a single material is being used for the entire voxel world, but this is seldom the case. It is common to associate a particular material with each voxel so that it can represent rock, wood, sand or any other type of material as required. The usual approach is to store a simple integer identifier with each voxel, and then map this identifier to material properties within your application.
Both the CubicSurfaceExtractor and the MarchingCubesSurfacExtractor understand the concept of a material being associated with a voxel, and they will take this into account when generating a mesh. Specifically, they will both copy the material identifier into the vertex data of the output mesh, so you can pass it through to your shaders and use it to affect the way the surface is rendered. Both extractCubicSurface() and the extractMarchingCubesSurface() include a 'data' member in their vertices, and this is copied/interpolated directly from the corresponding voxels. Therefore you can store a material identifier as part of your voxel type, and then pass this through to your shader as a vertex attribute. You can then use this to affect the way the surface is rendered.
The following code snippet assumes that you have passed the material identifier to your shaders and that you can access it in the fragment shader. It then chooses which colour to draw the polygon based on this identifier: The following code snippet assumes that you have passed a material identifier to your shaders and that you can access it in the fragment shader. It then chooses which colour to draw the polygon based on this identifier:
.. sourcecode:: glsl .. sourcecode:: glsl
@ -92,17 +92,13 @@ The following code snippet assumes that you have passed the material identifier
This is a very simple example, and such use of conditional branching within the shader may not be the best approach as it incurs some performance overhead and becomes unwieldy with a large number of materials. Other approaches include encoding a colour directly into the material identifier, or using the identifier as an index into a texture atlas or array. This is a very simple example, and such use of conditional branching within the shader may not be the best approach as it incurs some performance overhead and becomes unwieldy with a large number of materials. Other approaches include encoding a colour directly into the material identifier, or using the identifier as an index into a texture atlas or array.
Note that PolyVox currently stores that material identifier for the vertex as a float, but this will probably change in the future to use the same type as is stored in the volume. It will then be up to you which type you pass to the GPU (older GPUs may not support integer values) but if you do use floats then watch out for precision issues and avoid equality comparisons.
Blending between materials Blending between materials
-------------------------- --------------------------
An additional complication when working with smooth voxel terrain is that it is usually desirable to blend smoothly between adjacent voxels with different materials. This situation does not occur with cubic meshes because the texture is considered to be per-face instead of per-vertex, and PolyVox enforces this by ensuring that all the vertices of a given face have the same material. An additional complication when working with smooth voxel terrain is that it is usually desirable to blend smoothly between adjacent voxels with different materials. This situation does not occur with cubic meshes because the texture is considered to be per-face instead of per-vertex, and PolyVox enforces this by ensuring that all the vertices of a given face have the same material.
With a smooth mesh it is possible for each of the three vertices of any given triangle to have different material identifiers. If this is not explicitly handled then the graphics hardware will interpolate these material values across the face of the triangle. Fundamentally, the concept of interpolating between material identifiers does not make sense, because if we have (for example) 1='grass', 2='rock' and 3='sand' then it does not make sense to say rock is the average of grass and sand. With a smooth mesh it is possible for each of the three vertices of any given triangle to have different material identifiers. If this is not explicitly handled then the graphics hardware will interpolate these material values across the face of the triangle. Fundamentally, the concept of interpolating between material identifiers does not make sense, because if we have (for example) 1='grass', 2='rock' and 3='sand' then it does not make sense to say rock is the average of grass and sand.
Correctly handling of this is a surprising difficult problem. For now, the best approach is described in our article 'Volumetric representation of virtual terrain' which appeared in Game Engine Gems Volume 1 and which is freely available through the Google Books preview here: http://books.google.com/books?id=WNfD2u8nIlIC&lpg=PR1&dq=game%20engine%20gems&pg=PA39#v=onepage&q&f=false Correctly handling of this is a surprising difficult problem. For now, one approach is described in our article 'Volumetric representation of virtual terrain' which appeared in Game Engine Gems Volume 1 and which is freely available through the Google Books preview here: http://books.google.com/books?id=WNfD2u8nIlIC&lpg=PR1&dq=game%20engine%20gems&pg=PA39#v=onepage&q&f=false
As off October 2012 we are actively researching alternative solutions to this problem though it will be some time before the results become available.
Actual implementation of these material blending approaches is left as an exercise to the reader, though it is possible that in the future we will add some utility functions to PolyVox to assist with tasks such as splitting the mesh or adding the required extra vertex attributes. Our test implementations have performed the mesh processing on the CPU before the mesh is uploaded to the graphics card, but it does seem like there is a lot of potential for implementing these approaches in the geometry shader. Actual implementation of these material blending approaches is left as an exercise to the reader, though it is possible that in the future we will add some utility functions to PolyVox to assist with tasks such as splitting the mesh or adding the required extra vertex attributes. Our test implementations have performed the mesh processing on the CPU before the mesh is uploaded to the graphics card, but it does seem like there is a lot of potential for implementing these approaches in the geometry shader.
@ -110,7 +106,7 @@ Storage of textures
=================== ===================
The other major challenge in texturing voxel based geometry is handling the large number of textures which such environments often require. As an example, a game like Minecraft has hundreds of different material types each with their own texture. The traditional approach to mesh texturing is to bind textures to *texture units* on the GPU before rendering a batch, but even modern GPUs only allow between 16-64 textures to be bound at a time. In this section we discuss various solutions to overcoming this limitation. The other major challenge in texturing voxel based geometry is handling the large number of textures which such environments often require. As an example, a game like Minecraft has hundreds of different material types each with their own texture. The traditional approach to mesh texturing is to bind textures to *texture units* on the GPU before rendering a batch, but even modern GPUs only allow between 16-64 textures to be bound at a time. In this section we discuss various solutions to overcoming this limitation.
There are various trade offs involved, but if you are targeting hardware with support for *texture arrays* (available from OpenGL 3 and Direct3D 10 on-wards) then we can save you some time and tell you that they are almost certainly the best solution. Otherwise you have to understand the various pros and cons of the other approaches described below. There are various trade offs involved, but if you are targeting hardware with support for *texture arrays* (available from OpenGL 3 and Direct3D 10 onwards) then we can save you some time and tell you that they are almost certainly the best solution. Otherwise you have to understand the various pros and cons of the other approaches described below.
Separate texture units Separate texture units
---------------------- ----------------------
@ -122,7 +118,7 @@ If your required number of textures do indeed exceed the available number of tex
A more practical approach would be to break the mesh into a smaller number of pieces such that each mesh uses several textures but less than the maximum number of texture units. For example, our mesh with one hundred materials could be split into ten meshes, the first of which contains those triangles using materials 0-9, the seconds contains those triangles using materials 10-19, and so forth. There is a trade off here between the number of batches and the number of textures units used per batch. A more practical approach would be to break the mesh into a smaller number of pieces such that each mesh uses several textures but less than the maximum number of texture units. For example, our mesh with one hundred materials could be split into ten meshes, the first of which contains those triangles using materials 0-9, the seconds contains those triangles using materials 10-19, and so forth. There is a trade off here between the number of batches and the number of textures units used per batch.
Furthermore, you could realise that although your terrain may use hundreds of different textures, any given region is likely to use only a small fraction of those. We have yet to experiment with this, but it seems if you region uses only (for example) materials 12, 47, and 231, then you could conceptually map these materials to the first three textures slots. This means that for each region you draw the mapping between material IDs and texture units would be different. This may require some complex logic in the application but could allow you to do much more with only a few texture units. We will investigate this further in the future. Furthermore, you could realise that although your terrain may use hundreds of different textures, any given region is likely to use only a small fraction of those. We have yet to experiment with this, but it seems if you region uses only (for example) materials 12, 47, and 231, then you could conceptually map these materials to the first three textures slots. This means that for each region you draw the mapping between material IDs and texture units would be different. This may require some complex logic in the application but could allow you to do much more with only a few texture units.
Texture atlases Texture atlases
--------------- ---------------
@ -138,7 +134,7 @@ It is possible to combat these problems but the solutions are non-trivial. You w
3D texture slices 3D texture slices
----------------- -----------------
The idea here is similar to the texture atlas approach, but rather than packing texture side-by-side in an atlas they are instead packed as slices in a 3D texture. We haven't actually tested this but in theory it may have a couple of benefits. Firstly, it simplifies the addressing of the texture as there is no need to offset/scale the UV coordinates, and the W coordinate (the slice index) can be more easily computed from the material identifier. Secondly, a single volume texture will usually be able to hold more texels than a single 2D texture (for example, 512x512x512 is bigger than 4096x4096). Lastly, it should simplify the filtering problem as packed textures are no longer tiled and so should wrap correctly. The idea here is similar to the texture atlas approach, but rather than packing textures side-by-side in an atlas they are instead packed as slices in a 3D texture. We haven't actually tested this but in theory it may have a couple of benefits. Firstly, it simplifies the addressing of the texture as there is no need to offset/scale the UV coordinates, and the W coordinate (the slice index) can be more easily computed from the material identifier. Secondly, a single volume texture will usually be able to hold more texels than a single 2D texture (for example, 512x512x512 is bigger than 4096x4096). Lastly, it should simplify the filtering problem as packed textures are no longer tiled and so should wrap correctly.
However, MIP mapping will probably be more complex than the texture atlas case because even the first MIP level will involve combining adjacent slices. Volume textures are also not so widely supported and may be particularly problematic on mobile hardware. However, MIP mapping will probably be more complex than the texture atlas case because even the first MIP level will involve combining adjacent slices. Volume textures are also not so widely supported and may be particularly problematic on mobile hardware.

View File

@ -29,30 +29,28 @@ Lastly, note that PolyVox volumes are templatised which means the voxel type mig
PagedVolume PagedVolume
----------- -----------
NOTE: The info below is based on LargeVolume, which PagedVolume has replaced. It is likely that the same limitations apply but this has not been well tested. We do intend to improve the thread safty of PagedVolume in the future. The PagedVolume provides even less thread safety than the RawVolume, in that even concurrent read operations can cause problems. The reason for this is the more complex memory management which is performed behind the scenes, and which allows pieces of volume data to be moved around and deleted. For example, a read of a single voxel may mean that the block of data associated with that voxel has to be paged in to memory, which in turn may mean that another block of data has to be paged out of memory. If second thread was halfway through reading a voxel in this second block of data then a problem will occur.
The LargeVolume provides even less thread safety than the RawVolume, in that even concurrent read operations can cause problems. The reason for this is the more complex memory management which is performed behind the scenes, and which allows pieces of volume data to be moved around and deleted. For example, a read of a single voxel may mean that the block of data associated with that voxel has to be paged in to memory, which in turn may mean that another block of data has to be paged out of memory. If second thread was halfway through reading a voxel in this second block of data then a problem will occur. In the future we may do a more comprehensive analysis of thread safety in the PagedVolume, but for now you should assume that any multithreaded access can cause problems.
In the future we may do a more comprehensive analysis of thread safety in the LargeVolume, but for now you should assume that any multithreaded access can cause problems.
Consequences of abuse Consequences of abuse
--------------------- ---------------------
We have outlined above the rules for multithreaded access of volumes, but what actually happens if you violate these? There's a couple of things to watch out for: We have outlined above the rules for multithreaded access of volumes, but what actually happens if you violate these? There's a couple of things to watch out for:
- As mentioned, performing unprotected writes to the volume can cause problems because the data may be copied into the CPU cache and/or registers, and so a subsequent read could retrieve the old value. This is not what you want but probably won't be fatal (i.e. it shouldn't crash). It would basically manifest itself as data corruption. - As mentioned, performing unprotected writes to the volume can cause problems because the data may be copied into the CPU cache and/or registers, and so a subsequent read could retrieve the old value. This is not what you want but probably won't be fatal (i.e. it shouldn't crash). It would basically manifest itself as data corruption.
- If you access the LargeVolume in a multithreaded fashion then you risk trying to access data which has been removed by another thread, and in this case you will get undefined behaviour. This will probably be a crash (out of bounds access) but really anything could happen. - If you access the PagedVolume in a multithreaded fashion then you risk trying to access data which has been removed by another thread, and in this case you will get undefined behaviour. This will probably be a crash (out of bounds access) but really anything could happen.
Surface Extraction Surface Extraction
================== ==================
Despite the lack of thread safety built in to PolyVox, it is still possible and often desirable to make use of multiple threads for tasks such as surface extraction. Performing surface extraction does not require write access to the data, and we've already established that you can safely perform reads from different threads *provided you are not using the LargeVolume*. Despite the lack of thread safety built in to PolyVox, it is still possible and often desirable to make use of multiple threads for tasks such as surface extraction. Performing surface extraction does not require write access to the data, and we've already established that you can safely perform reads from different threads *provided you are not using the PagedVolume*.
Combining multiple surface extraction threads with the *LargeVolume* is something we will need to experiment with in the future, to determine how it can be improved. Combining multiple surface extraction threads with the *PagedVolume* is something we will need to experiment with in the future, to determine how it can be improved.
In the future we will expand this section to discuss how to split surface extraction across a number of threads, but for now please see Section XX of the book chapter 'Volumetric Representation of Virtual environments', available for free here: http://books.google.nl/books?id=WNfD2u8nIlIC&lpg=PR1&dq=game+engine+gems&pg=PA39&redir_esc=y#v=onepage&q&f=false In the future we will expand this section to discuss how to split surface extraction across a number of threads, but for now please see Section 3.4.3 of the book chapter 'Volumetric Representation of Virtual environments', available for free here: http://books.google.nl/books?id=WNfD2u8nIlIC&lpg=PR1&dq=game+engine+gems&pg=PA39&redir_esc=y#v=onepage&q&f=false
GPU thread safety GPU thread safety
================= =================
Be aware that even if you successfully perform surface across multiple threads you still need to take care when uploading the data to the GPU. For Direct3D 9.0 and OpenGL 2.0 it is only possible to upload data from the main thread (or more accurately the one which owns the rendering context). So after you have performed your multi-threaded surface extraction you need to bring the data back to the main thread for uploading to the GPU. Be aware that even if you successfully perform surface extraction across multiple threads then you still need to take care when uploading the data to the GPU. For Direct3D 9.0 and OpenGL 2.0 it is only possible to upload data from the main thread (or more accurately the one which owns the rendering context). So after you have performed your multi-threaded surface extraction you need to bring the data back to the main thread for uploading to the GPU.
More recent versions of the Direct3D and OpenGL APIs lift this restriction and provide means of accessing GPU resources from multiple threads. Please consult the documentation for your API for details. More recent versions of the Direct3D and OpenGL APIs lift this restriction and provide means of accessing GPU resources from multiple threads. Please consult the documentation for your API for details.

View File

@ -3,12 +3,10 @@ Principles of PolyVox
********************** **********************
.. warning :: .. warning ::
This section is being written and is just a skeleton for now This section is yet to be fully written and is just a skeleton for now.
PolyVox provides a library for managing 3D arrays (volumes) of data (voxels). It gives you the tools to iterate through, randomly access, read and write volumes. It supports any type you'd like to represent each voxel whether it's just an ``int`` or a class which encapsulates both density and colour. PolyVox provides a library for managing 3D arrays (volumes) of data (voxels). It gives you the tools to iterate through, randomly access, read and write volumes. The volumes are templatized on voxel type, so that each voxel can be as simple as just an number or as complex as a class with a range of properties.
Once you have a volume, PolyVox provides a number of tools for turning it into something that you can pass to your rendering engine. These are called `surface extractors`. Once you have created a volume, PolyVox provides a number of tools for turning it into a mesh that you can pass to your rendering engine. These are called `surface extractors`. A 'Marching Cubes' surface extractor and a 'cubic' (Minecraft-style) surface extractor are included, and it is possible to write your own.
Each surface extractor needs to be told how to interperet your voxel type and that is done using... PolyVox primarily handles this task of storing volume data and extracting surfaces from it. Most other aspects of you voxel application or game will need to be implemented by you (rendering, logic, physics, AI, networking, etc) though PolyVox does have a few utility classes for things like the A* algorithm on a 3D grid.
Link to a page describing how to write your own voxel type and link it to a surface extractor...

View File

@ -14,18 +14,18 @@ To get started, we need to include the following headers:
.. sourcecode:: c++ .. sourcecode:: c++
#include "PolyVoxCore/CubicSurfaceExtractorWithNormals.h" #include "PolyVox/CubicSurfaceExtractor.h"
#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h" #include "PolyVox/MarchingCubesSurfaceExtractor.h"
#include "PolyVoxCore/SurfaceMesh.h" #include "PolyVox/Mesh.h"
#include "PolyVoxCore/SimpleVolume.h" #include "PolyVox/RawVolume.h"
The most fundamental construct when working with PolyVox is that of the volume. This is represented by the :polyvox:`SimpleVolume` class which stores a 3D grid of voxels. Our basic example application creates a volume with the following line of code: The most fundamental construct when working with PolyVox is that of the volume. This is represented by the :polyvox:`RawVolume` class which stores a 3D grid of voxels. Our basic example application creates a volume with the following line of code:
.. sourcecode:: c++ .. sourcecode:: c++
SimpleVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(63, 63, 63))); RawVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63)));
As can be seen, the SimpleVolume class is templated upon the voxel type. This means it is straightforward to create a volume of integers, floats, or a custom voxel type (see the :polyvox:`SimpleVolume documentation <PolyVox::SimpleVolume>` for more details). In this particular case we have created a volume in which each voxel is of type `uint8_t` which is an unsigned 8-bit integer. As can be seen, the RawVolume class is templated upon the voxel type. This means it is straightforward to create a volume of integers, floats, or a custom voxel type (see the :polyvox:`RawVolume documentation <PolyVox::RawVolume>` for more details). In this particular case we have created a volume in which each voxel is of type `uint8_t` which is an unsigned 8-bit integer.
Next, we set some of the voxels in the volume to be 'solid' in order to create a large sphere in the centre of the volume. We do this with the following function call: Next, we set some of the voxels in the volume to be 'solid' in order to create a large sphere in the centre of the volume. We do this with the following function call:
@ -37,7 +37,7 @@ Note that this function is part of the BasicExample (rather than being part of t
.. sourcecode:: c++ .. sourcecode:: c++
void createSphereInVolume(SimpleVolume<uint8_t>& volData, float fRadius) void createSphereInVolume(RawVolume<uint8_t>& volData, float fRadius)
{ {
//This vector hold the position of the center of the volume //This vector hold the position of the center of the volume
Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2); Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2);
@ -50,117 +50,145 @@ Note that this function is part of the BasicExample (rather than being part of t
for (int x = 0; x < volData.getWidth(); x++) for (int x = 0; x < volData.getWidth(); x++)
{ {
//Store our current position as a vector... //Store our current position as a vector...
Vector3DFloat v3dCurrentPos(x,y,z); Vector3DFloat v3dCurrentPos(x, y, z);
//And compute how far the current position is from the center of the volume //And compute how far the current position is from the center of the volume
float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length(); float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length();
uint8_t uVoxelValue = 0; uint8_t uVoxelValue = 0;
//If the current voxel is less than 'radius' units from the center then we make it solid. //If the current voxel is less than 'radius' units from the center then we make it solid.
if(fDistToCenter <= fRadius) if (fDistToCenter <= fRadius)
{ {
//Our new voxel value //Our new voxel value
uVoxelValue = 255; uVoxelValue = 255;
} }
//Wrte the voxel value into the volume //Wrte the voxel value into the volume
volData.setVoxelAt(x, y, z, uVoxelValue); volData.setVoxel(x, y, z, uVoxelValue);
} }
} }
} }
} }
This function takes as input the :polyvox:`SimpleVolume` in which we want to create the sphere, and also a radius specifying how large we want the sphere to be. In our case we have specified a radius of 30 voxels, which will fit nicely inside our :polyvox:`SimpleVolume` of dimensions 64x64x64. This function takes as input the :polyvox:`RawVolume` in which we want to create the sphere, and also a radius specifying how large we want the sphere to be. In our case we have specified a radius of 30 voxels, which will fit nicely inside our :polyvox:`RawVolume` of dimensions 64x64x64.
Because this is a simple example function it always places the sphere at the centre of the volume. It computes this centre by halving the dimensions of the volume as given by the functions :polyvox:`SimpleVolume::getWidth`, :polyvox:`SimpleVolume::getHeight` and :polyvox:`SimpleVolume::getDepth`. The resulting position is stored using a :polyvox:`Vector3DFloat`. This is simply a typedef from our templatised :polyvox:`Vector` class, meaning that other sizes and storage types are available if you need them. Because this is a simple example function it always places the sphere at the centre of the volume. It computes this centre by halving the dimensions of the volume as given by the functions :polyvox:`SimpleVolume::getWidth`, :polyvox:`SimpleVolume::getHeight` and :polyvox:`SimpleVolume::getDepth`. The resulting position is stored using a :polyvox:`Vector3DFloat`. This is simply a typedef from our templatised :polyvox:`Vector` class, meaning that other sizes and storage types are available if you need them.
Next, the function uses a three-level 'for' loop to iterate over each voxel in the volume. For each voxel it computes the distance from the voxel to the centre of the volume. If this distance is less than or equal to the specified radius then the voxel forms part of the sphere and is made solid. During surface extraction, the voxel will be considered empty if it has a value of zero, and otherwise it will be considered solid. In our case we simply set it to 255 which is the largest value a uint8_t can contain. Next, the function uses a three-level 'for' loop to iterate over each voxel in the volume. For each voxel it computes the distance from the voxel to the centre of the volume. If this distance is less than or equal to the specified radius then the voxel forms part of the sphere and is made solid.
Extracting the surface Extracting the surface
====================== ======================
Now that we have built our volume we need to convert it into a triangle mesh for rendering. This process can be performed by the :polyvox:`CubicSurfaceExtractorWithNormals` class. An instance of the :polyvox:`CubicSurfaceExtractorWithNormals` is created as follows: Now that we have built our volume we need to convert it into a triangle mesh for rendering. This process can be performed by the :polyvox:`extractCubicMesh` function:
.. sourcecode:: c++ .. sourcecode:: c++
SurfaceMesh<PositionMaterialNormal> mesh; auto mesh = extractCubicMesh(&volData, volData.getEnclosingRegion());
CubicSurfaceExtractorWithNormals< SimpleVolume<uint8_t> > surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh);
The :polyvox:`CubicSurfaceExtractorWithNormals` takes a pointer to the volume data, and also it needs to be told which :polyvox:`Region` of the volume the extraction should be performed on (in more advanced applications this is useful for extracting only those parts of the volume which have been modified since the last extraction). For our purpose the :polyvox:`SimpleVolume` class provides a convenient :polyvox:`SimpleVolume::getEnclosingRegion` function which returns a :polyvox:`Region` representing the whole volume. The constructor also takes a pointer to a :polyvox:`SurfaceMesh` object where it will store the result, so we need to create one of these before we can construct the :polyvox:`CubicSurfaceExtractorWithNormals`. The :polyvox:`extractCubicMesh` function takes a pointer to the volume data, and also it needs to be told which :polyvox:`Region` of the volume the extraction should be performed on (in more advanced applications this is useful for extracting only those parts of the volume which have been modified since the last extraction). For our purpose the :polyvox:`RawVolume` class provides a convenient :polyvox:`RawVolume::getEnclosingRegion` function which returns a :polyvox:`Region` representing the whole volume.
The actual extraction happens in the :polyvox:`CubicSurfaceExtractorWithNormals::execute` function. This means you can set up a :polyvox:`CubicSurfaceExtractorWithNormals` with the required parameters and then actually execute it later. For this example we just call it straight away. The resulting mesh has a complex templatized type and so we assign it to a variable declared with 'auto', This way the compiler will determine the correct type for us. PolyVox also makes use of some compression techniques to store the vertex data in a compact way. Therefore the vertices of the mesh need to be decompressed ('decoded') before they can be used. For now the easiest approach is to use the provided ``decode()`` function, though advanced users can actually do this decoding on the GPU (see 'DecodeOnGPUExample'):
.. sourcecode:: c++ .. sourcecode:: c++
surfaceExtractor.execute(); auto decodedMesh = decodeMesh(mesh);
This fills in our :polyvox:`SurfaceMesh` object, which basically contains an index and vertex buffer representing the desired triangle mesh. Our ``decodedMesh`` variable contains an index and vertex buffer representing the desired triangle mesh.
Note: If you like you can try swapping the :polyvox:`CubicSurfaceExtractorWithNormals` for :polyvox:`MarchingCubesSurfaceExtractor`. We have already included the relevant header, and in the BasicExample you just need to change which line in commented out. The :polyvox:`MarchingCubesSurfaceExtractor` makes use of a smooth density field and will consider a voxel to be solid if it is above a threshold of half the voxel's maximum value (so in this case that's half of 255, which is 127). Note: If you like you can try swapping the :polyvox:`extractCubicMesh` for :polyvox:`extractMarchingCubesMesh`. We have already included the relevant header, and in the BasicExample you just need to change which line in commented out. The :polyvox:`MarchingCubesSurfaceExtractor` makes use of a smooth density field and will consider a voxel to be solid if it is above a threshold of half the voxel's maximum value (so in this case that's half of 255, which is 127).
Rendering the surface Rendering the surface
===================== =====================
Rendering the surface with OpenGL is handled by the OpenGLWidget class. Again, this is not part of PolyVox, it is simply an example based on Qt and OpenGL which demonstrates how rendering can be performed. Within this class there are mainly two functions which are of interest - the OpenGLWidget::setSurfaceMeshToRender() function which constructs OpenGL buffers from our :polyvox:`SurfaceMesh` and the OpenGLWidget::paintGL() function which is called each frame to perform the rendering. Rendering the surface with OpenGL is handled by our ``PolyVoxExample`` which is an ``OpenGLWidget`` subclass. Again, this is not part of PolyVox, it is simply an example based on Qt and OpenGL which demonstrates how rendering can be performed. Within this class there are mainly two functions which are of interest - the PolyVoxExample::addMesh() function which constructs OpenGL buffers from our :polyvox:`Mesh` and the PolyVoxExample::renderOneFrame() function which is called each frame to perform the rendering.
The OpenGLWidget::setSurfaceMeshToRender() function is implemented as follows: The PolyVoxExample::addMesh() function is implemented as follows:
.. sourcecode:: c++ .. sourcecode:: c++
void OpenGLWidget::setSurfaceMeshToRender(const PolyVox::SurfaceMesh<PositionMaterialNormal>& surfaceMesh) template <typename MeshType>
void addMesh(const MeshType& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f)
{ {
//Convienient access to the vertices and indices // This struct holds the OpenGL properties (buffer handles, etc) which will be used
const vector<uint32_t>& vecIndices = surfaceMesh.getIndices(); // to render our mesh. We copy the data from the PolyVox mesh into this structure.
const vector<PositionMaterialNormal>& vecVertices = surfaceMesh.getVertices(); OpenGLMeshData meshData;
//Build an OpenGL index buffer // Create the VAO for the mesh
glGenBuffers(1, &indexBuffer); glGenVertexArrays(1, &(meshData.vertexArrayObject));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBindVertexArray(meshData.vertexArrayObject);
const GLvoid* pIndices = static_cast<const GLvoid*>(&(vecIndices[0]));
glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), pIndices, GL_STATIC_DRAW);
//Build an OpenGL vertex buffer // The GL_ARRAY_BUFFER will contain the list of vertex positions
glGenBuffers(1, &vertexBuffer); glGenBuffers(1, &(meshData.vertexBuffer));
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, meshData.vertexBuffer);
const GLvoid* pVertices = static_cast<const GLvoid*>(&(vecVertices[0])); glBufferData(GL_ARRAY_BUFFER, surfaceMesh.getNoOfVertices() * sizeof(typename MeshType::VertexType), surfaceMesh.getRawVertexData(), GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(PositionMaterialNormal), pVertices, GL_STATIC_DRAW);
m_uBeginIndex = 0; // and GL_ELEMENT_ARRAY_BUFFER will contain the indices
m_uEndIndex = vecIndices.size(); glGenBuffers(1, &(meshData.indexBuffer));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshData.indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, surfaceMesh.getNoOfIndices() * sizeof(typename MeshType::IndexType), surfaceMesh.getRawIndexData(), GL_STATIC_DRAW);
// Every surface extractor outputs valid positions for the vertices, so tell OpenGL how these are laid out
glEnableVertexAttribArray(0); // Attrib '0' is the vertex positions
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(typename MeshType::VertexType), (GLvoid*)(offsetof(typename MeshType::VertexType, position))); //take the first 3 floats from every sizeof(decltype(vecVertices)::value_type)
// Some surface extractors also generate normals, so tell OpenGL how these are laid out. If a surface extractor
// does not generate normals then nonsense values are written into the buffer here and sghould be ignored by the
// shader. This is mostly just to simplify this example code - in a real application you will know whether your
// chosen surface extractor generates normals and can skip uploading them if not.
glEnableVertexAttribArray(1); // Attrib '1' is the vertex normals.
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(typename MeshType::VertexType), (GLvoid*)(offsetof(typename MeshType::VertexType, normal)));
// Finally a surface extractor will probably output additional data. This is highly application dependant. For this example code
// we're just uploading it as a set of bytes which we can read individually, but real code will want to do something specialised here.
glEnableVertexAttribArray(2); //We're talking about shader attribute '2'
GLint size = (std::min)(sizeof(typename MeshType::VertexType::DataType), size_t(4)); // Can't upload more that 4 components (vec4 is GLSL's biggest type)
glVertexAttribIPointer(2, size, GL_UNSIGNED_BYTE, sizeof(typename MeshType::VertexType), (GLvoid*)(offsetof(typename MeshType::VertexType, data)));
// We're done uploading and can now unbind.
glBindVertexArray(0);
// A few additional properties can be copied across for use during rendering.
meshData.noOfIndices = surfaceMesh.getNoOfIndices();
meshData.translation = QVector3D(translation.getX(), translation.getY(), translation.getZ());
meshData.scale = scale;
// Set 16 or 32-bit index buffer size.
meshData.indexType = sizeof(typename MeshType::IndexType) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
// Now add the mesh to the list of meshes to render.
addMeshData(meshData);
} }
We begin by obtaining direct access to the index and vertex buffer in the :polyvox:`SurfaceMesh` class in order to make the following code slightly cleaner. Both the :polyvox:`SurfaceMesh::getIndices` and :polyvox:`SurfaceMesh::getVertices` functions return an std::vector containing the relevant data.
The OpenGL functions which are called to construct the index and vertex buffer are best explained by the OpenGL documentation. In both cases we are making an exact copy of the data stored in the :polyvox:`SurfaceMesh`.
The begin and end indices are used in the OpenGLWidget::paintGL() to control what part of the index buffer is actually rendered. For this simple example we will render the whole buffer from '0' to 'vecIndices.size()'.
With the OpenGL index and vertex buffers set up, we can now look at the code which is called each frame to render them: With the OpenGL index and vertex buffers set up, we can now look at the code which is called each frame to render them:
.. sourcecode:: c++ .. sourcecode:: c++
void OpenGLWidget::paintGL() void renderOneFrame() override
{ {
//Clear the screen // Our example framework only uses a single shader for the scene (for all meshes).
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); mShader->bind();
//Set up the viewing transformation // These two matrices are constant for all meshes.
glMatrixMode(GL_MODELVIEW); mShader->setUniformValue("viewMatrix", viewMatrix());
glLoadIdentity(); mShader->setUniformValue("projectionMatrix", projectionMatrix());
glTranslatef(0.0f,0.0f,-100.0f); //Centre volume and move back
glRotatef(-m_xRotation, 0.0f, 1.0f, 0.0f);
glRotatef(-m_yRotation, 1.0f, 0.0f, 0.0f);
glTranslatef(-32.0f,-32.0f,-32.0f); //Centre volume and move back
//Bind the index buffer // Iterate over each mesh which the user added to our list, and render it.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); for (OpenGLMeshData meshData : mMeshData)
{
//Set up the model matrrix based on provided translation and scale.
QMatrix4x4 modelMatrix;
modelMatrix.translate(meshData.translation);
modelMatrix.scale(meshData.scale);
mShader->setUniformValue("modelMatrix", modelMatrix);
//Bind the vertex buffer // Bind the vertex array for the current mesh
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBindVertexArray(meshData.vertexArrayObject);
glVertexPointer(3, GL_FLOAT, sizeof(PositionMaterialNormal), 0); // Draw the mesh
glNormalPointer(GL_FLOAT, sizeof(PositionMaterialNormal), (GLvoid*)12); glDrawElements(GL_TRIANGLES, meshData.noOfIndices, meshData.indexType, 0);
// Unbind the vertex array.
glDrawRangeElements(GL_TRIANGLES, m_uBeginIndex, m_uEndIndex-1, m_uEndIndex - m_uBeginIndex, GL_UNSIGNED_INT, 0); glBindVertexArray(0);
//Error checking code here...
} }
Again, the explanation of this code is best left to the OpenGL documentation. Note that is is called automatically by Qt each time the display needs to be updated. // We're done with the shader for this frame.
mShader->release();
}
Again, the explanation of this code is best left to the OpenGL documentation.

View File

@ -1,23 +1,26 @@
# Copyright (c) 2010-2012 David Williams ################################################################################
# The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # 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.
################################################################################
PROJECT(BasicExample) PROJECT(BasicExample)

View File

@ -1,24 +1,25 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams The MIT License (MIT)
This software is provided 'as-is', without any express or implied Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is hereby granted, free of charge, to any person obtaining a copy
including commercial applications, and to alter it and redistribute it of this software and associated documentation files (the "Software"), to deal
freely, subject to the following restrictions: 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:
1. The origin of this software must not be misrepresented; you must not The above copyright notice and this permission notice shall be included in all
claim that you wrote the original software. If you use this software copies or substantial portions of the Software.
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
misrepresented as being the original software. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3. This notice may not be removed or altered from any source AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
distribution. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "PolyVoxExample.h" #include "PolyVoxExample.h"
@ -26,14 +27,14 @@ freely, subject to the following restrictions:
#include "PolyVox/CubicSurfaceExtractor.h" #include "PolyVox/CubicSurfaceExtractor.h"
#include "PolyVox/MarchingCubesSurfaceExtractor.h" #include "PolyVox/MarchingCubesSurfaceExtractor.h"
#include "PolyVox/Mesh.h" #include "PolyVox/Mesh.h"
#include "PolyVox/PagedVolume.h" #include "PolyVox/RawVolume.h"
#include <QApplication> #include <QApplication>
//Use the PolyVox namespace //Use the PolyVox namespace
using namespace PolyVox; using namespace PolyVox;
void createSphereInVolume(PagedVolume<uint8_t>& volData, float fRadius) void createSphereInVolume(RawVolume<uint8_t>& volData, float fRadius)
{ {
//This vector hold the position of the center of the volume //This vector hold the position of the center of the volume
Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2); Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2);
@ -46,21 +47,21 @@ void createSphereInVolume(PagedVolume<uint8_t>& volData, float fRadius)
for (int x = 0; x < volData.getWidth(); x++) for (int x = 0; x < volData.getWidth(); x++)
{ {
//Store our current position as a vector... //Store our current position as a vector...
Vector3DFloat v3dCurrentPos(x,y,z); Vector3DFloat v3dCurrentPos(x, y, z);
//And compute how far the current position is from the center of the volume //And compute how far the current position is from the center of the volume
float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length(); float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length();
uint8_t uVoxelValue = 0; uint8_t uVoxelValue = 0;
//If the current voxel is less than 'radius' units from the center then we make it solid. //If the current voxel is less than 'radius' units from the center then we make it solid.
if(fDistToCenter <= fRadius) if (fDistToCenter <= fRadius)
{ {
//Our new voxel value //Our new voxel value
uVoxelValue = 255; uVoxelValue = 255;
} }
//Wrte the voxel value into the volume //Wrte the voxel value into the volume
volData.setVoxelAt(x, y, z, uVoxelValue); volData.setVoxel(x, y, z, uVoxelValue);
} }
} }
} }
@ -78,7 +79,7 @@ protected:
void initializeExample() override void initializeExample() override
{ {
// Create an empty volume and then place a sphere in it // Create an empty volume and then place a sphere in it
PagedVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63))); RawVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63)));
createSphereInVolume(volData, 30); createSphereInVolume(volData, 30);
// Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see. // Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see.

View File

@ -1,7 +1,40 @@
ADD_SUBDIRECTORY(common) ################################################################################
ADD_SUBDIRECTORY(Basic) # The MIT License (MIT)
ADD_SUBDIRECTORY(Paging) #
ADD_SUBDIRECTORY(OpenGL) # Copyright (c) 2015 Matthew Williams and David Williams
ADD_SUBDIRECTORY(SmoothLOD) #
ADD_SUBDIRECTORY(DecodeOnGPU) # Permission is hereby granted, free of charge, to any person obtaining a copy
ADD_SUBDIRECTORY(Python) # 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.
################################################################################
find_package(Qt5OpenGL 5.2)
set_package_properties(Qt5OpenGL PROPERTIES DESCRIPTION "C++ framework" URL http://qt-project.org)
set_package_properties(Qt5OpenGL PROPERTIES TYPE RECOMMENDED PURPOSE "Building the examples")
if(Qt5OpenGL_FOUND)
SET(BUILD_EXAMPLES ON PARENT_SCOPE)
ADD_SUBDIRECTORY(Basic)
ADD_SUBDIRECTORY(Paging)
ADD_SUBDIRECTORY(OpenGL)
ADD_SUBDIRECTORY(SmoothLOD)
ADD_SUBDIRECTORY(DecodeOnGPU)
ADD_SUBDIRECTORY(Python)
else()
SET(BUILD_EXAMPLES OFF PARENT_SCOPE)
endif()

View File

@ -1,23 +1,26 @@
# Copyright (c) 2010-2012 David Williams ################################################################################
# The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # 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.
################################################################################
PROJECT(DecodeOnGPUExample) PROJECT(DecodeOnGPUExample)

View File

@ -1,24 +1,25 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams The MIT License (MIT)
This software is provided 'as-is', without any express or implied Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is hereby granted, free of charge, to any person obtaining a copy
including commercial applications, and to alter it and redistribute it of this software and associated documentation files (the "Software"), to deal
freely, subject to the following restrictions: 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:
1. The origin of this software must not be misrepresented; you must not The above copyright notice and this permission notice shall be included in all
claim that you wrote the original software. If you use this software copies or substantial portions of the Software.
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
misrepresented as being the original software. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3. This notice may not be removed or altered from any source AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
distribution. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "PolyVoxExample.h" #include "PolyVoxExample.h"
@ -26,14 +27,14 @@ freely, subject to the following restrictions:
#include "PolyVox/CubicSurfaceExtractor.h" #include "PolyVox/CubicSurfaceExtractor.h"
#include "PolyVox/MarchingCubesSurfaceExtractor.h" #include "PolyVox/MarchingCubesSurfaceExtractor.h"
#include "PolyVox/Mesh.h" #include "PolyVox/Mesh.h"
#include "PolyVox/PagedVolume.h" #include "PolyVox/RawVolume.h"
#include <QApplication> #include <QApplication>
//Use the PolyVox namespace //Use the PolyVox namespace
using namespace PolyVox; using namespace PolyVox;
void createSphereInVolume(PagedVolume<uint8_t>& volData, float fRadius) void createSphereInVolume(RawVolume<uint8_t>& volData, float fRadius)
{ {
//This vector hold the position of the center of the volume //This vector hold the position of the center of the volume
Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2); Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2);
@ -46,21 +47,21 @@ void createSphereInVolume(PagedVolume<uint8_t>& volData, float fRadius)
for (int x = 0; x < volData.getWidth(); x++) for (int x = 0; x < volData.getWidth(); x++)
{ {
//Store our current position as a vector... //Store our current position as a vector...
Vector3DFloat v3dCurrentPos(x,y,z); Vector3DFloat v3dCurrentPos(x, y, z);
//And compute how far the current position is from the center of the volume //And compute how far the current position is from the center of the volume
float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length(); float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length();
uint8_t uVoxelValue = 0; uint8_t uVoxelValue = 0;
//If the current voxel is less than 'radius' units from the center then we make it solid. //If the current voxel is less than 'radius' units from the center then we make it solid.
if(fDistToCenter <= fRadius) if (fDistToCenter <= fRadius)
{ {
//Our new voxel value //Our new voxel value
uVoxelValue = 255; uVoxelValue = 255;
} }
//Wrte the voxel value into the volume //Wrte the voxel value into the volume
volData.setVoxelAt(x, y, z, uVoxelValue); volData.setVoxel(x, y, z, uVoxelValue);
} }
} }
} }
@ -94,17 +95,12 @@ protected:
setShader(shader); setShader(shader);
//Create an empty volume and then place a sphere in it //Create an empty volume and then place a sphere in it
PagedVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63))); RawVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63)));
createSphereInVolume(volData, 30); createSphereInVolume(volData, 30);
// Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see. // Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see.
//auto mesh = extractCubicMesh(&volData, volData.getEnclosingRegion());
auto mesh = extractMarchingCubesMesh(&volData, volData.getEnclosingRegion()); auto mesh = extractMarchingCubesMesh(&volData, volData.getEnclosingRegion());
// The surface extractor outputs the mesh in an efficient compressed format which is not directly suitable for rendering. The easiest approach is to
// decode this on the CPU as shown below, though more advanced applications can upload the compressed mesh to the GPU and decompress in shader code.
//auto decodedMesh = decodeMesh(mesh);
//Pass the surface to the OpenGL window //Pass the surface to the OpenGL window
OpenGLMeshData meshData = buildOpenGLMeshData(mesh); OpenGLMeshData meshData = buildOpenGLMeshData(mesh);
addMeshData(meshData); addMeshData(meshData);
@ -115,10 +111,6 @@ protected:
private: private:
OpenGLMeshData buildOpenGLMeshData(const PolyVox::Mesh< PolyVox::MarchingCubesVertex< uint8_t > >& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f) OpenGLMeshData buildOpenGLMeshData(const PolyVox::Mesh< PolyVox::MarchingCubesVertex< uint8_t > >& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f)
{ {
// Convienient access to the vertices and indices
const auto& vecIndices = surfaceMesh.getIndices();
const auto& vecVertices = surfaceMesh.getVertices();
// This struct holds the OpenGL properties (buffer handles, etc) which will be used // This struct holds the OpenGL properties (buffer handles, etc) which will be used
// to render our mesh. We copy the data from the PolyVox mesh into this structure. // to render our mesh. We copy the data from the PolyVox mesh into this structure.
OpenGLMeshData meshData; OpenGLMeshData meshData;
@ -130,12 +122,12 @@ private:
// The GL_ARRAY_BUFFER will contain the list of vertex positions // The GL_ARRAY_BUFFER will contain the list of vertex positions
glGenBuffers(1, &(meshData.vertexBuffer)); glGenBuffers(1, &(meshData.vertexBuffer));
glBindBuffer(GL_ARRAY_BUFFER, meshData.vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, meshData.vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(MarchingCubesVertex< uint8_t >), vecVertices.data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, surfaceMesh.getNoOfVertices() * sizeof(MarchingCubesVertex< uint8_t >), surfaceMesh.getRawVertexData(), GL_STATIC_DRAW);
// and GL_ELEMENT_ARRAY_BUFFER will contain the indices // and GL_ELEMENT_ARRAY_BUFFER will contain the indices
glGenBuffers(1, &(meshData.indexBuffer)); glGenBuffers(1, &(meshData.indexBuffer));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshData.indexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshData.indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), vecIndices.data(), GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, surfaceMesh.getNoOfIndices() * sizeof(uint32_t), surfaceMesh.getRawIndexData(), GL_STATIC_DRAW);
// Every surface extractor outputs valid positions for the vertices, so tell OpenGL how these are laid out // Every surface extractor outputs valid positions for the vertices, so tell OpenGL how these are laid out
glEnableVertexAttribArray(0); // Attrib '0' is the vertex positions glEnableVertexAttribArray(0); // Attrib '0' is the vertex positions
@ -158,7 +150,7 @@ private:
glBindVertexArray(0); glBindVertexArray(0);
// A few additional properties can be copied across for use during rendering. // A few additional properties can be copied across for use during rendering.
meshData.noOfIndices = vecIndices.size(); meshData.noOfIndices = surfaceMesh.getNoOfIndices();
meshData.translation = QVector3D(translation.getX(), translation.getY(), translation.getZ()); meshData.translation = QVector3D(translation.getX(), translation.getY(), translation.getZ());
meshData.scale = scale; meshData.scale = scale;

View File

@ -1,23 +1,26 @@
# Copyright (c) 2010-2012 David Williams ################################################################################
# The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # 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.
################################################################################
CMAKE_MINIMUM_REQUIRED(VERSION 2.6) CMAKE_MINIMUM_REQUIRED(VERSION 2.6)

View File

@ -1,24 +1,25 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams The MIT License (MIT)
This software is provided 'as-is', without any express or implied Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is hereby granted, free of charge, to any person obtaining a copy
including commercial applications, and to alter it and redistribute it of this software and associated documentation files (the "Software"), to deal
freely, subject to the following restrictions: 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:
1. The origin of this software must not be misrepresented; you must not The above copyright notice and this permission notice shall be included in all
claim that you wrote the original software. If you use this software copies or substantial portions of the Software.
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
misrepresented as being the original software. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3. This notice may not be removed or altered from any source AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
distribution. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "Shapes.h" #include "Shapes.h"
@ -27,7 +28,7 @@ freely, subject to the following restrictions:
using namespace PolyVox; using namespace PolyVox;
void createSphereInVolume(PagedVolume<MaterialDensityPair88>& volData, float fRadius, uint8_t uValue) void createSphereInVolume(RawVolume<MaterialDensityPair88>& volData, float fRadius, uint8_t uValue)
{ {
//This vector hold the position of the center of the volume //This vector hold the position of the center of the volume
Vector3DInt32 v3dVolCenter = (volData.getEnclosingRegion().getUpperCorner() - volData.getEnclosingRegion().getLowerCorner()) / static_cast<int32_t>(2); Vector3DInt32 v3dVolCenter = (volData.getEnclosingRegion().getUpperCorner() - volData.getEnclosingRegion().getLowerCorner()) / static_cast<int32_t>(2);
@ -40,33 +41,33 @@ void createSphereInVolume(PagedVolume<MaterialDensityPair88>& volData, float fRa
for (int x = 0; x < volData.getWidth(); x++) for (int x = 0; x < volData.getWidth(); x++)
{ {
//Store our current position as a vector... //Store our current position as a vector...
Vector3DInt32 v3dCurrentPos(x,y,z); Vector3DInt32 v3dCurrentPos(x, y, z);
//And compute how far the current position is from the center of the volume //And compute how far the current position is from the center of the volume
double fDistToCenter = (v3dCurrentPos - v3dVolCenter).length(); double fDistToCenter = (v3dCurrentPos - v3dVolCenter).length();
//If the current voxel is less than 'radius' units from the center //If the current voxel is less than 'radius' units from the center
//then we make it solid, otherwise we make it empty space. //then we make it solid, otherwise we make it empty space.
if(fDistToCenter <= fRadius) if (fDistToCenter <= fRadius)
{ {
volData.setVoxelAt(x,y,z, MaterialDensityPair88(uValue, uValue > 0 ? MaterialDensityPair88::getMaxDensity() : MaterialDensityPair88::getMinDensity())); volData.setVoxel(x, y, z, MaterialDensityPair88(uValue, uValue > 0 ? MaterialDensityPair88::getMaxDensity() : MaterialDensityPair88::getMinDensity()));
} }
} }
} }
} }
} }
void createCubeInVolume(PagedVolume<MaterialDensityPair88>& volData, Vector3DInt32 lowerCorner, Vector3DInt32 upperCorner, uint8_t uValue) void createCubeInVolume(RawVolume<MaterialDensityPair88>& volData, Vector3DInt32 lowerCorner, Vector3DInt32 upperCorner, uint8_t uValue)
{ {
uint8_t maxDen = MaterialDensityPair88::getMaxDensity(); uint8_t maxDen = static_cast<uint8_t>(MaterialDensityPair88::getMaxDensity());
uint8_t minDen = MaterialDensityPair88::getMinDensity(); uint8_t minDen = static_cast<uint8_t>(MaterialDensityPair88::getMinDensity());
//This three-level for loop iterates over every voxel between the specified corners //This three-level for loop iterates over every voxel between the specified corners
for (int z = lowerCorner.getZ(); z <= upperCorner.getZ(); z++) for (int z = lowerCorner.getZ(); z <= upperCorner.getZ(); z++)
{ {
for (int y = lowerCorner.getY(); y <= upperCorner.getY(); y++) for (int y = lowerCorner.getY(); y <= upperCorner.getY(); y++)
{ {
for (int x = lowerCorner.getX() ; x <= upperCorner.getX(); x++) for (int x = lowerCorner.getX(); x <= upperCorner.getX(); x++)
{ {
volData.setVoxelAt(x,y,z, MaterialDensityPair88(uValue, uValue > 0 ? maxDen : minDen)); volData.setVoxel(x, y, z, MaterialDensityPair88(uValue, uValue > 0 ? maxDen : minDen));
} }
} }
} }

View File

@ -1,33 +1,34 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams The MIT License (MIT)
This software is provided 'as-is', without any express or implied Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is hereby granted, free of charge, to any person obtaining a copy
including commercial applications, and to alter it and redistribute it of this software and associated documentation files (the "Software"), to deal
freely, subject to the following restrictions: 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:
1. The origin of this software must not be misrepresented; you must not The above copyright notice and this permission notice shall be included in all
claim that you wrote the original software. If you use this software copies or substantial portions of the Software.
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
misrepresented as being the original software. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3. This notice may not be removed or altered from any source AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
distribution. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __OpenGLExample_Shapes_H__ #ifndef __OpenGLExample_Shapes_H__
#define __OpenGLExample_Shapes_H__ #define __OpenGLExample_Shapes_H__
#include "PolyVox/PagedVolume.h" #include "PolyVox/RawVolume.h"
#include "PolyVox/MaterialDensityPair.h" #include "PolyVox/MaterialDensityPair.h"
void createSphereInVolume(PolyVox::LargeVolume<PolyVox::MaterialDensityPair88>& volData, float fRadius, uint8_t uValue); void createSphereInVolume(PolyVox::RawVolume<PolyVox::MaterialDensityPair88>& volData, float fRadius, uint8_t uValue);
void createCubeInVolume(PolyVox::LargeVolume<PolyVox::MaterialDensityPair88>& volData, PolyVox::Vector3DInt32 lowerCorner, PolyVox::Vector3DInt32 upperCorner, uint8_t uValue); void createCubeInVolume(PolyVox::RawVolume<PolyVox::MaterialDensityPair88>& volData, PolyVox::Vector3DInt32 lowerCorner, PolyVox::Vector3DInt32 upperCorner, uint8_t uValue);
#endif //__OpenGLExample_Shapes_H__ #endif //__OpenGLExample_Shapes_H__

View File

@ -1,24 +1,25 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams The MIT License (MIT)
This software is provided 'as-is', without any express or implied Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is hereby granted, free of charge, to any person obtaining a copy
including commercial applications, and to alter it and redistribute it of this software and associated documentation files (the "Software"), to deal
freely, subject to the following restrictions: 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:
1. The origin of this software must not be misrepresented; you must not The above copyright notice and this permission notice shall be included in all
claim that you wrote the original software. If you use this software copies or substantial portions of the Software.
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
misrepresented as being the original software. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3. This notice may not be removed or altered from any source AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
distribution. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "PolyVox/FilePager.h" #include "PolyVox/FilePager.h"
@ -58,8 +59,7 @@ public:
protected: protected:
void initializeExample() override void initializeExample() override
{ {
FilePager<MaterialDensityPair88>* pager = new FilePager<MaterialDensityPair88>("."); RawVolume<MaterialDensityPair88> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(g_uVolumeSideLength - 1, g_uVolumeSideLength - 1, g_uVolumeSideLength - 1)));
PagedVolume<MaterialDensityPair88> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(g_uVolumeSideLength - 1, g_uVolumeSideLength - 1, g_uVolumeSideLength - 1)), pager);
//Make our volume contain a sphere in the center. //Make our volume contain a sphere in the center.
int32_t minPos = 0; int32_t minPos = 0;

View File

@ -1,23 +1,26 @@
# Copyright (c) 2010-2012 David Williams ################################################################################
# The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # 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.
################################################################################
PROJECT(PagingExample) PROJECT(PagingExample)

View File

@ -42,12 +42,12 @@ float Perlin::noise1(float arg)
init(); init();
} }
setup(0, bx0,bx1, rx0,rx1); setup(0, bx0, bx1, rx0, rx1);
sx = s_curve(rx0); sx = s_curve(rx0);
u = rx0 * g1[ p[ bx0 ] ]; u = rx0 * g1[p[bx0]];
v = rx1 * g1[ p[ bx1 ] ]; v = rx1 * g1[p[bx1]];
return lerp(sx, u, v); return lerp(sx, u, v);
} }
@ -65,8 +65,8 @@ float Perlin::noise2(float vec[2])
init(); init();
} }
setup(0,bx0,bx1,rx0,rx1); setup(0, bx0, bx1, rx0, rx1);
setup(1,by0,by1,ry0,ry1); setup(1, by0, by1, ry0, ry1);
i = p[bx0]; i = p[bx0];
j = p[bx1]; j = p[bx1];
@ -79,18 +79,18 @@ float Perlin::noise2(float vec[2])
sx = s_curve(rx0); sx = s_curve(rx0);
sy = s_curve(ry0); sy = s_curve(ry0);
#define at2(rx,ry) ( rx * q[0] + ry * q[1] ) #define at2(rx,ry) ( rx * q[0] + ry * q[1] )
q = g2[b00]; q = g2[b00];
u = at2(rx0,ry0); u = at2(rx0, ry0);
q = g2[b10]; q = g2[b10];
v = at2(rx1,ry0); v = at2(rx1, ry0);
a = lerp(sx, u, v); a = lerp(sx, u, v);
q = g2[b01]; q = g2[b01];
u = at2(rx0,ry1); u = at2(rx0, ry1);
q = g2[b11]; q = g2[b11];
v = at2(rx1,ry1); v = at2(rx1, ry1);
b = lerp(sx, u, v); b = lerp(sx, u, v);
return lerp(sy, a, b); return lerp(sy, a, b);
@ -109,40 +109,40 @@ float Perlin::noise3(float vec[3])
init(); init();
} }
setup(0, bx0,bx1, rx0,rx1); setup(0, bx0, bx1, rx0, rx1);
setup(1, by0,by1, ry0,ry1); setup(1, by0, by1, ry0, ry1);
setup(2, bz0,bz1, rz0,rz1); setup(2, bz0, bz1, rz0, rz1);
i = p[ bx0 ]; i = p[bx0];
j = p[ bx1 ]; j = p[bx1];
b00 = p[ i + by0 ]; b00 = p[i + by0];
b10 = p[ j + by0 ]; b10 = p[j + by0];
b01 = p[ i + by1 ]; b01 = p[i + by1];
b11 = p[ j + by1 ]; b11 = p[j + by1];
t = s_curve(rx0); t = s_curve(rx0);
sy = s_curve(ry0); sy = s_curve(ry0);
sz = s_curve(rz0); sz = s_curve(rz0);
#define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] ) #define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )
q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0); q = g3[b00 + bz0]; u = at3(rx0, ry0, rz0);
q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0); q = g3[b10 + bz0]; v = at3(rx1, ry0, rz0);
a = lerp(t, u, v); a = lerp(t, u, v);
q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0); q = g3[b01 + bz0]; u = at3(rx0, ry1, rz0);
q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0); q = g3[b11 + bz0]; v = at3(rx1, ry1, rz0);
b = lerp(t, u, v); b = lerp(t, u, v);
c = lerp(sy, a, b); c = lerp(sy, a, b);
q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1); q = g3[b00 + bz1]; u = at3(rx0, ry0, rz1);
q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1); q = g3[b10 + bz1]; v = at3(rx1, ry0, rz1);
a = lerp(t, u, v); a = lerp(t, u, v);
q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1); q = g3[b01 + bz1]; u = at3(rx0, ry1, rz1);
q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1); q = g3[b11 + bz1]; v = at3(rx1, ry1, rz1);
b = lerp(t, u, v); b = lerp(t, u, v);
d = lerp(sy, a, b); d = lerp(sy, a, b);
@ -155,7 +155,7 @@ void Perlin::normalize2(float v[2])
float s; float s;
s = (float)sqrt(v[0] * v[0] + v[1] * v[1]); s = (float)sqrt(v[0] * v[0] + v[1] * v[1]);
s = 1.0f/s; s = 1.0f / s;
v[0] = v[0] * s; v[0] = v[0] * s;
v[1] = v[1] * s; v[1] = v[1] * s;
} }
@ -165,7 +165,7 @@ void Perlin::normalize3(float v[3])
float s; float s;
s = (float)sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); s = (float)sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
s = 1.0f/s; s = 1.0f / s;
v[0] = v[0] * s; v[0] = v[0] * s;
v[1] = v[1] * s; v[1] = v[1] * s;
@ -176,14 +176,14 @@ void Perlin::init(void)
{ {
int i, j, k; int i, j, k;
for (i = 0 ; i < B ; i++) for (i = 0; i < B; i++)
{ {
p[i] = i; p[i] = i;
g1[i] = (float)((rand() % (B + B)) - B) / B; g1[i] = (float)((rand() % (B + B)) - B) / B;
for (j = 0 ; j < 2 ; j++) for (j = 0; j < 2; j++)
g2[i][j] = (float)((rand() % (B + B)) - B) / B; g2[i][j] = (float)((rand() % (B + B)) - B) / B;
normalize2(g2[i]); normalize2(g2[i]);
for (j = 0 ; j < 3 ; j++) for (j = 0; j < 3; j++)
g3[i][j] = (float)((rand() % (B + B)) - B) / B; g3[i][j] = (float)((rand() % (B + B)) - B) / B;
normalize3(g3[i]); normalize3(g3[i]);
} }
@ -195,13 +195,13 @@ void Perlin::init(void)
p[j] = k; p[j] = k;
} }
for (i = 0 ; i < B + 2 ; i++) for (i = 0; i < B + 2; i++)
{ {
p[B + i] = p[i]; p[B + i] = p[i];
g1[B + i] = g1[i]; g1[B + i] = g1[i];
for (j = 0 ; j < 2 ; j++) for (j = 0; j < 2; j++)
g2[B + i][j] = g2[i][j]; g2[B + i][j] = g2[i][j];
for (j = 0 ; j < 3 ; j++) for (j = 0; j < 3; j++)
g3[B + i][j] = g3[i][j]; g3[B + i][j] = g3[i][j];
} }
@ -214,15 +214,15 @@ float Perlin::perlin_noise_2D(float vec[2])
float result = 0.0f; float result = 0.0f;
float amp = mAmplitude; float amp = mAmplitude;
vec[0]*=mFrequency; vec[0] *= mFrequency;
vec[1]*=mFrequency; vec[1] *= mFrequency;
for( int i=0; i<terms; i++ ) for (int i = 0; i < terms; i++)
{ {
result += noise2(vec)*amp; result += noise2(vec)*amp;
vec[0] *= 2.0f; vec[0] *= 2.0f;
vec[1] *= 2.0f; vec[1] *= 2.0f;
amp*=0.5f; amp *= 0.5f;
} }
@ -235,17 +235,17 @@ float Perlin::perlin_noise_3D(float vec[3])
float result = 0.0f; float result = 0.0f;
float amp = mAmplitude; float amp = mAmplitude;
vec[0]*=mFrequency; vec[0] *= mFrequency;
vec[1]*=mFrequency; vec[1] *= mFrequency;
vec[2]*=mFrequency; vec[2] *= mFrequency;
for( int i=0; i<terms; i++ ) for (int i = 0; i < terms; i++)
{ {
result += noise3(vec)*amp; result += noise3(vec)*amp;
vec[0] *= 2.0f; vec[0] *= 2.0f;
vec[1] *= 2.0f; vec[1] *= 2.0f;
vec[2] *= 2.0f; vec[2] *= 2.0f;
amp*=0.5f; amp *= 0.5f;
} }
@ -254,7 +254,7 @@ float Perlin::perlin_noise_3D(float vec[3])
Perlin::Perlin(int octaves,float freq,float amp,int seed) Perlin::Perlin(int octaves, float freq, float amp, int seed)
{ {
mOctaves = octaves; mOctaves = octaves;
mFrequency = freq; mFrequency = freq;

View File

@ -1,24 +1,25 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams The MIT License (MIT)
This software is provided 'as-is', without any express or implied Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is hereby granted, free of charge, to any person obtaining a copy
including commercial applications, and to alter it and redistribute it of this software and associated documentation files (the "Software"), to deal
freely, subject to the following restrictions: 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:
1. The origin of this software must not be misrepresented; you must not The above copyright notice and this permission notice shall be included in all
claim that you wrote the original software. If you use this software copies or substantial portions of the Software.
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
misrepresented as being the original software. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3. This notice may not be removed or altered from any source AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
distribution. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "PolyVoxExample.h" #include "PolyVoxExample.h"
@ -32,48 +33,9 @@ freely, subject to the following restrictions:
#include <QApplication> #include <QApplication>
//Use the PolyVox namespace // Use the PolyVox namespace
using namespace PolyVox; using namespace PolyVox;
void createSphereInVolume(PagedVolume<MaterialDensityPair44>& volData, Vector3DFloat v3dVolCenter, float fRadius)
{
//This vector hold the position of the center of the volume
//Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2);
int iRadius = fRadius;
//This three-level for loop iterates over every voxel in the volume
for (int z = v3dVolCenter.getZ() - iRadius; z <= v3dVolCenter.getZ() + iRadius; z++)
{
for (int y = v3dVolCenter.getY() - iRadius; y <= v3dVolCenter.getY() + iRadius; y++)
{
for (int x = v3dVolCenter.getX() - iRadius; x <= v3dVolCenter.getX() + iRadius; x++)
{
//Store our current position as a vector...
Vector3DFloat v3dCurrentPos(x,y,z);
//And compute how far the current position is from the center of the volume
float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length();
//If the current voxel is less than 'radius' units from the center then we make it solid.
if(fDistToCenter <= fRadius)
{
//Our new density value
uint8_t uDensity = MaterialDensityPair44::getMaxDensity();
//Get the old voxel
MaterialDensityPair44 voxel = volData.getVoxel(x,y,z);
//Modify the density
voxel.setDensity(uDensity);
//Wrte the voxel value into the volume
volData.setVoxelAt(x, y, z, voxel);
}
}
}
}
}
/** /**
* Generates data using Perlin noise. * Generates data using Perlin noise.
*/ */
@ -91,28 +53,31 @@ public:
virtual void pageIn(const PolyVox::Region& region, PagedVolume<MaterialDensityPair44>::Chunk* pChunk) virtual void pageIn(const PolyVox::Region& region, PagedVolume<MaterialDensityPair44>::Chunk* pChunk)
{ {
Perlin perlin(2,2,1,234); Perlin perlin(2, 2, 1, 234);
for(int x = region.getLowerX(); x <= region.getUpperX(); x++) for (int x = region.getLowerX(); x <= region.getUpperX(); x++)
{ {
for(int y = region.getLowerY(); y <= region.getUpperY(); y++) for (int y = region.getLowerY(); y <= region.getUpperY(); y++)
{ {
float perlinVal = perlin.Get(x / static_cast<float>(255-1), y / static_cast<float>(255-1)); float perlinVal = perlin.Get(x / static_cast<float>(255 - 1), y / static_cast<float>(255 - 1));
perlinVal += 1.0f; perlinVal += 1.0f;
perlinVal *= 0.5f; perlinVal *= 0.5f;
perlinVal *= 255; perlinVal *= 255;
for(int z = region.getLowerZ(); z <= region.getUpperZ(); z++) for (int z = region.getLowerZ(); z <= region.getUpperZ(); z++)
{ {
MaterialDensityPair44 voxel; MaterialDensityPair44 voxel;
if(z < perlinVal) if (z < perlinVal)
{ {
const int xpos = 50; const int xpos = 50;
const int zpos = 100; const int zpos = 100;
if((x-xpos)*(x-xpos) + (z-zpos)*(z-zpos) < 200) { if ((x - xpos)*(x - xpos) + (z - zpos)*(z - zpos) < 200)
{
// tunnel // tunnel
voxel.setMaterial(0); voxel.setMaterial(0);
voxel.setDensity(MaterialDensityPair44::getMinDensity()); voxel.setDensity(MaterialDensityPair44::getMinDensity());
} else { }
else
{
// solid // solid
voxel.setMaterial(245); voxel.setMaterial(245);
voxel.setDensity(MaterialDensityPair44::getMaxDensity()); voxel.setDensity(MaterialDensityPair44::getMaxDensity());
@ -127,7 +92,7 @@ public:
// Voxel position within a chunk always start from zero. So if a chunk represents region (4, 8, 12) to (11, 19, 15) // Voxel position within a chunk always start from zero. So if a chunk represents region (4, 8, 12) to (11, 19, 15)
// then the valid chunk voxels are from (0, 0, 0) to (7, 11, 3). Hence we subtract the lower corner position of the // then the valid chunk voxels are from (0, 0, 0) to (7, 11, 3). Hence we subtract the lower corner position of the
// region from the volume space position in order to get the chunk space position. // region from the volume space position in order to get the chunk space position.
pChunk->setVoxelAt(x - region.getLowerX(), y - region.getLowerY(), z - region.getLowerZ(), voxel); pChunk->setVoxel(x - region.getLowerX(), y - region.getLowerY(), z - region.getLowerZ(), voxel);
} }
} }
} }
@ -151,36 +116,26 @@ protected:
void initializeExample() override void initializeExample() override
{ {
PerlinNoisePager* pager = new PerlinNoisePager(); PerlinNoisePager* pager = new PerlinNoisePager();
PagedVolume<MaterialDensityPair44> volData(PolyVox::Region::MaxRegion(), pager, 64); PagedVolume<MaterialDensityPair44> volData(pager, 8 * 1024 * 1024, 64);
volData.setMemoryUsageLimit(8 * 1024 * 1024); // 8Mb
//createSphereInVolume(volData, 30); // Just some tests of memory usage, etc.
//createPerlinTerrain(volData);
//createPerlinVolumeSlow(volData);
std::cout << "Memory usage: " << (volData.calculateSizeInBytes() / 1024.0 / 1024.0) << "MB" << std::endl; std::cout << "Memory usage: " << (volData.calculateSizeInBytes() / 1024.0 / 1024.0) << "MB" << std::endl;
//std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl;
PolyVox::Region reg(Vector3DInt32(-255, 0, 0), Vector3DInt32(255, 255, 255)); PolyVox::Region reg(Vector3DInt32(-255, 0, 0), Vector3DInt32(255, 255, 255));
std::cout << "Prefetching region: " << reg.getLowerCorner() << " -> " << reg.getUpperCorner() << std::endl; std::cout << "Prefetching region: " << reg.getLowerCorner() << " -> " << reg.getUpperCorner() << std::endl;
volData.prefetch(reg); volData.prefetch(reg);
std::cout << "Memory usage: " << (volData.calculateSizeInBytes() / 1024.0 / 1024.0) << "MB" << std::endl; std::cout << "Memory usage: " << (volData.calculateSizeInBytes() / 1024.0 / 1024.0) << "MB" << std::endl;
//std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl;
PolyVox::Region reg2(Vector3DInt32(0, 0, 0), Vector3DInt32(255, 255, 255));
std::cout << "Flushing region: " << reg2.getLowerCorner() << " -> " << reg2.getUpperCorner() << std::endl;
volData.flush(reg2);
std::cout << "Memory usage: " << (volData.calculateSizeInBytes() / 1024.0 / 1024.0) << "MB" << std::endl;
//std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl;
std::cout << "Flushing entire volume" << std::endl; std::cout << "Flushing entire volume" << std::endl;
volData.flushAll(); volData.flushAll();
std::cout << "Memory usage: " << (volData.calculateSizeInBytes() / 1024.0 / 1024.0) << "MB" << std::endl; std::cout << "Memory usage: " << (volData.calculateSizeInBytes() / 1024.0 / 1024.0) << "MB" << std::endl;
//std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl;
//Extract the surface // Extract the surface
PolyVox::Region reg2(Vector3DInt32(0, 0, 0), Vector3DInt32(254, 254, 254));
auto mesh = extractCubicMesh(&volData, reg2); auto mesh = extractCubicMesh(&volData, reg2);
std::cout << "#vertices: " << mesh.getNoOfVertices() << std::endl; std::cout << "#vertices: " << mesh.getNoOfVertices() << std::endl;
auto decodedMesh = decodeMesh(mesh); auto decodedMesh = decodeMesh(mesh);
//Pass the surface to the OpenGL window // Pass the surface to the OpenGL window
addMesh(decodedMesh); addMesh(decodedMesh);
setCameraTransform(QVector3D(300.0f, 300.0f, 300.0f), -(PI / 4.0f), PI + (PI / 4.0f)); setCameraTransform(QVector3D(300.0f, 300.0f, 300.0f), -(PI / 4.0f), PI + (PI / 4.0f));
@ -189,11 +144,11 @@ protected:
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
//Create and show the Qt OpenGL window // Create and show the Qt OpenGL window
QApplication app(argc, argv); QApplication app(argc, argv);
PagingExample openGLWidget(0); PagingExample openGLWidget(0);
openGLWidget.show(); openGLWidget.show();
//Run the message pump. // Run the message pump.
return app.exec(); return app.exec();
} }

View File

@ -1,23 +1,26 @@
# Copyright (c) 2010-2013 Matt Williams ################################################################################
# The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # 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.
################################################################################
PROJECT(PythonExample) PROJECT(PythonExample)

View File

@ -1,26 +1,27 @@
#! /usr/bin/env python3 #! /usr/bin/env python3
################################################################################ ################################################################################
# Copyright (c) 2013 Matt Williams # The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # 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.
################################################################################ ################################################################################
import sys import sys

View File

@ -1,23 +1,26 @@
# Copyright (c) 2010-2012 David Williams ################################################################################
# The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # 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.
################################################################################
PROJECT(SmoothLODExample) PROJECT(SmoothLODExample)

View File

@ -1,24 +1,25 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams The MIT License (MIT)
This software is provided 'as-is', without any express or implied Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is hereby granted, free of charge, to any person obtaining a copy
including commercial applications, and to alter it and redistribute it of this software and associated documentation files (the "Software"), to deal
freely, subject to the following restrictions: 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:
1. The origin of this software must not be misrepresented; you must not The above copyright notice and this permission notice shall be included in all
claim that you wrote the original software. If you use this software copies or substantial portions of the Software.
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
misrepresented as being the original software. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3. This notice may not be removed or altered from any source AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
distribution. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "PolyVoxExample.h" #include "PolyVoxExample.h"
@ -27,7 +28,6 @@ freely, subject to the following restrictions:
#include "PolyVox/MarchingCubesSurfaceExtractor.h" #include "PolyVox/MarchingCubesSurfaceExtractor.h"
#include "PolyVox/Mesh.h" #include "PolyVox/Mesh.h"
#include "PolyVox/RawVolume.h" #include "PolyVox/RawVolume.h"
#include "PolyVox/PagedVolume.h"
#include "PolyVox/VolumeResampler.h" #include "PolyVox/VolumeResampler.h"
#include <QApplication> #include <QApplication>
@ -35,7 +35,7 @@ freely, subject to the following restrictions:
//Use the PolyVox namespace //Use the PolyVox namespace
using namespace PolyVox; using namespace PolyVox;
void createSphereInVolume(PagedVolume<uint8_t>& volData, float fRadius) void createSphereInVolume(RawVolume<uint8_t>& volData, float fRadius)
{ {
//This vector hold the position of the center of the volume //This vector hold the position of the center of the volume
Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2); Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2);
@ -48,21 +48,21 @@ void createSphereInVolume(PagedVolume<uint8_t>& volData, float fRadius)
for (int x = 0; x < volData.getWidth(); x++) for (int x = 0; x < volData.getWidth(); x++)
{ {
//Store our current position as a vector... //Store our current position as a vector...
Vector3DFloat v3dCurrentPos(x,y,z); Vector3DFloat v3dCurrentPos(x, y, z);
//And compute how far the current position is from the center of the volume //And compute how far the current position is from the center of the volume
float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length(); float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length();
if(fDistToCenter <= fRadius) if (fDistToCenter <= fRadius)
{ {
//Our new density value //Our new density value
uint8_t uDensity = std::numeric_limits<uint8_t>::max(); uint8_t uDensity = std::numeric_limits<uint8_t>::max();
//Wrte the voxel value into the volume //Wrte the voxel value into the volume
volData.setVoxelAt(x, y, z, uDensity); volData.setVoxel(x, y, z, uDensity);
} }
//144 in the middle, (144 - 32) at the edges. Threshold of 128 is between these //144 in the middle, (144 - 32) at the edges. Threshold of 128 is between these
//volData.setVoxelAt(x, y, z, 144 - fDistToCenter); //volData.setVoxel(x, y, z, 144 - fDistToCenter);
} }
} }
} }
@ -80,7 +80,7 @@ protected:
void initializeExample() override void initializeExample() override
{ {
//Create an empty volume and then place a sphere in it //Create an empty volume and then place a sphere in it
PagedVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63))); RawVolume<uint8_t> volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(63, 63, 63)));
createSphereInVolume(volData, 28); createSphereInVolume(volData, 28);
//Smooth the data - should reimplement this using LowPassFilter //Smooth the data - should reimplement this using LowPassFilter
@ -90,7 +90,7 @@ protected:
RawVolume<uint8_t> volDataLowLOD(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(15, 31, 31))); RawVolume<uint8_t> volDataLowLOD(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(15, 31, 31)));
VolumeResampler< PagedVolume<uint8_t>, RawVolume<uint8_t> > volumeResampler(&volData, PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(31, 63, 63)), &volDataLowLOD, volDataLowLOD.getEnclosingRegion()); VolumeResampler< RawVolume<uint8_t>, RawVolume<uint8_t> > volumeResampler(&volData, PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(31, 63, 63)), &volDataLowLOD, volDataLowLOD.getEnclosingRegion());
volumeResampler.execute(); volumeResampler.execute();
//Extract the surface //Extract the surface

View File

@ -1,24 +1,25 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams The MIT License (MIT)
This software is provided 'as-is', without any express or implied Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is hereby granted, free of charge, to any person obtaining a copy
including commercial applications, and to alter it and redistribute it of this software and associated documentation files (the "Software"), to deal
freely, subject to the following restrictions: 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:
1. The origin of this software must not be misrepresented; you must not The above copyright notice and this permission notice shall be included in all
claim that you wrote the original software. If you use this software copies or substantial portions of the Software.
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
misrepresented as being the original software. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3. This notice may not be removed or altered from any source AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
distribution. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __OpenGLWidget_H_A72D4D2F8E__ // Random junk as 'OpenGLWidget seems like it could be a common name. #ifndef __OpenGLWidget_H_A72D4D2F8E__ // Random junk as 'OpenGLWidget seems like it could be a common name.

View File

@ -10,7 +10,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename QOpenGLFunctionsType> template <typename QOpenGLFunctionsType>
OpenGLWidget<QOpenGLFunctionsType>::OpenGLWidget(QWidget *parent) OpenGLWidget<QOpenGLFunctionsType>::OpenGLWidget(QWidget *parent)
:QGLWidget(parent) :QGLWidget(parent)
{ {
} }
@ -48,13 +48,13 @@ void OpenGLWidget<QOpenGLFunctionsType>::initializeGL()
//Print out some information about the OpenGL implementation. //Print out some information about the OpenGL implementation.
std::cout << "OpenGL Implementation Details:" << std::endl; std::cout << "OpenGL Implementation Details:" << std::endl;
if(this->glGetString(GL_VENDOR)) if (this->glGetString(GL_VENDOR))
std::cout << "\tGL_VENDOR: " << this->glGetString(GL_VENDOR) << std::endl; std::cout << "\tGL_VENDOR: " << this->glGetString(GL_VENDOR) << std::endl;
if(this->glGetString(GL_RENDERER)) if (this->glGetString(GL_RENDERER))
std::cout << "\tGL_RENDERER: " << this->glGetString(GL_RENDERER) << std::endl; std::cout << "\tGL_RENDERER: " << this->glGetString(GL_RENDERER) << std::endl;
if(this->glGetString(GL_VERSION)) if (this->glGetString(GL_VERSION))
std::cout << "\tGL_VERSION: " << this->glGetString(GL_VERSION) << std::endl; std::cout << "\tGL_VERSION: " << this->glGetString(GL_VERSION) << std::endl;
if(this->glGetString(GL_SHADING_LANGUAGE_VERSION)) if (this->glGetString(GL_SHADING_LANGUAGE_VERSION))
std::cout << "\tGL_SHADING_LANGUAGE_VERSION: " << this->glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; std::cout << "\tGL_SHADING_LANGUAGE_VERSION: " << this->glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
//Set up the clear colour //Set up the clear colour
@ -148,7 +148,7 @@ void OpenGLWidget<QOpenGLFunctionsType>::paintGL()
// Check for errors. // Check for errors.
GLenum errCode = this->glGetError(); GLenum errCode = this->glGetError();
if(errCode != GL_NO_ERROR) if (errCode != GL_NO_ERROR)
{ {
std::cerr << "OpenGL Error: " << errCode << std::endl; std::cerr << "OpenGL Error: " << errCode << std::endl;
} }

View File

@ -1,3 +1,27 @@
/*******************************************************************************
The MIT License (MIT)
Copyright (c) 2015 David Williams and Matthew Williams
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.
*******************************************************************************/
#include "PolyVoxExample.h" #include "PolyVoxExample.h"
void PolyVoxExample::setShader(QSharedPointer<QGLShaderProgram> shader) void PolyVoxExample::setShader(QSharedPointer<QGLShaderProgram> shader)

View File

@ -1,24 +1,25 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams The MIT License (MIT)
This software is provided 'as-is', without any express or implied Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is hereby granted, free of charge, to any person obtaining a copy
including commercial applications, and to alter it and redistribute it of this software and associated documentation files (the "Software"), to deal
freely, subject to the following restrictions: 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:
1. The origin of this software must not be misrepresented; you must not The above copyright notice and this permission notice shall be included in all
claim that you wrote the original software. If you use this software copies or substantial portions of the Software.
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
misrepresented as being the original software. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3. This notice may not be removed or altered from any source AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
distribution. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVoxExample_H__ #ifndef __PolyVoxExample_H__
@ -62,10 +63,6 @@ public:
template <typename MeshType> template <typename MeshType>
void addMesh(const MeshType& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f) void addMesh(const MeshType& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f)
{ {
// Convienient access to the vertices and indices
const auto& vecIndices = surfaceMesh.getIndices();
const auto& vecVertices = surfaceMesh.getVertices();
// This struct holds the OpenGL properties (buffer handles, etc) which will be used // This struct holds the OpenGL properties (buffer handles, etc) which will be used
// to render our mesh. We copy the data from the PolyVox mesh into this structure. // to render our mesh. We copy the data from the PolyVox mesh into this structure.
OpenGLMeshData meshData; OpenGLMeshData meshData;
@ -77,12 +74,12 @@ public:
// The GL_ARRAY_BUFFER will contain the list of vertex positions // The GL_ARRAY_BUFFER will contain the list of vertex positions
glGenBuffers(1, &(meshData.vertexBuffer)); glGenBuffers(1, &(meshData.vertexBuffer));
glBindBuffer(GL_ARRAY_BUFFER, meshData.vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, meshData.vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(typename MeshType::VertexType), vecVertices.data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, surfaceMesh.getNoOfVertices() * sizeof(typename MeshType::VertexType), surfaceMesh.getRawVertexData(), GL_STATIC_DRAW);
// and GL_ELEMENT_ARRAY_BUFFER will contain the indices // and GL_ELEMENT_ARRAY_BUFFER will contain the indices
glGenBuffers(1, &(meshData.indexBuffer)); glGenBuffers(1, &(meshData.indexBuffer));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshData.indexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshData.indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(typename MeshType::IndexType), vecIndices.data(), GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, surfaceMesh.getNoOfIndices() * sizeof(typename MeshType::IndexType), surfaceMesh.getRawIndexData(), GL_STATIC_DRAW);
// Every surface extractor outputs valid positions for the vertices, so tell OpenGL how these are laid out // Every surface extractor outputs valid positions for the vertices, so tell OpenGL how these are laid out
glEnableVertexAttribArray(0); // Attrib '0' is the vertex positions glEnableVertexAttribArray(0); // Attrib '0' is the vertex positions
@ -105,7 +102,7 @@ public:
glBindVertexArray(0); glBindVertexArray(0);
// A few additional properties can be copied across for use during rendering. // A few additional properties can be copied across for use during rendering.
meshData.noOfIndices = vecIndices.size(); meshData.noOfIndices = surfaceMesh.getNoOfIndices();
meshData.translation = QVector3D(translation.getX(), translation.getY(), translation.getZ()); meshData.translation = QVector3D(translation.getX(), translation.getY(), translation.getZ());
meshData.scale = scale; meshData.scale = scale;

View File

@ -1,24 +1,26 @@
# Copyright (c) 2008-2012 Matt Williams ################################################################################
# Copyright (c) 2008-2012 David Williams # The MIT License (MIT)
# #
# This software is provided 'as-is', without any express or implied # Copyright (c) 2015 Matthew Williams and David Williams
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# #
# Permission is granted to anyone to use this software for any purpose, # Permission is hereby granted, free of charge, to any person obtaining a copy
# including commercial applications, and to alter it and redistribute it # of this software and associated documentation files (the "Software"), to deal
# freely, subject to the following restrictions: # 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:
# #
# 1. The origin of this software must not be misrepresented; you must not # The above copyright notice and this permission notice shall be included in all
# claim that you wrote the original software. If you use this software # copies or substantial portions of the Software.
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# #
# 2. Altered source versions must be plainly marked as such, and must not be # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# misrepresented as being the original software. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# 3. This notice may not be removed or altered from any source # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# distribution. # 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.
################################################################################
CMAKE_MINIMUM_REQUIRED(VERSION 2.6) CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
@ -39,15 +41,9 @@ SET(CORE_INC_FILES
PolyVox/DefaultIsQuadNeeded.h PolyVox/DefaultIsQuadNeeded.h
PolyVox/DefaultMarchingCubesController.h PolyVox/DefaultMarchingCubesController.h
PolyVox/Density.h PolyVox/Density.h
PolyVox/DualContouringSurfaceExtractor.h PolyVox/Exceptions.h
PolyVox/DualContouringSurfaceExtractor.inl
PolyVox/FilePager.h PolyVox/FilePager.h
PolyVox/GradientEstimators.h PolyVox/Logging.h
PolyVox/GradientEstimators.inl
PolyVox/Interpolation.h
PolyVox/IteratorController.h
PolyVox/IteratorController.inl
PolyVox/LargeVolume.h
PolyVox/LowPassFilter.h PolyVox/LowPassFilter.h
PolyVox/LowPassFilter.inl PolyVox/LowPassFilter.inl
PolyVox/MarchingCubesSurfaceExtractor.h PolyVox/MarchingCubesSurfaceExtractor.h
@ -60,7 +56,6 @@ SET(CORE_INC_FILES
PolyVox/PagedVolume.inl PolyVox/PagedVolume.inl
PolyVox/PagedVolumeChunk.inl PolyVox/PagedVolumeChunk.inl
PolyVox/PagedVolumeSampler.inl PolyVox/PagedVolumeSampler.inl
PolyVox/PolyVoxForwardDeclarations.h
PolyVox/Picking.h PolyVox/Picking.h
PolyVox/Picking.inl PolyVox/Picking.inl
PolyVox/RawVolume.h PolyVox/RawVolume.h
@ -70,28 +65,28 @@ SET(CORE_INC_FILES
PolyVox/Raycast.inl PolyVox/Raycast.inl
PolyVox/Region.h PolyVox/Region.h
PolyVox/Region.inl PolyVox/Region.inl
PolyVox/SimpleVolume.h
PolyVox/Vector.h PolyVox/Vector.h
PolyVox/Vector.inl PolyVox/Vector.inl
PolyVox/Vertex.h PolyVox/Vertex.h
PolyVox/VolumeResampler.h PolyVox/VolumeResampler.h
PolyVox/VolumeResampler.inl PolyVox/VolumeResampler.inl
PolyVox/VoxelFilters.h
PolyVox/VoxelFilters.inl
) )
SET(IMPL_INC_FILES SET(IMPL_INC_FILES
PolyVox/Impl/Assertions.h
PolyVox/Impl/AStarPathfinderImpl.h PolyVox/Impl/AStarPathfinderImpl.h
PolyVox/Impl/Config.h PolyVox/Impl/Config.h
PolyVox/Impl/ErrorHandling.h PolyVox/Impl/ErrorHandling.h
PolyVox/Impl/Logging.h PolyVox/Impl/ExceptionsImpl.h
PolyVox/Impl/Interpolation.h
PolyVox/Impl/IteratorController.h
PolyVox/Impl/IteratorController.inl
PolyVox/Impl/LoggingImpl.h
PolyVox/Impl/MarchingCubesTables.h PolyVox/Impl/MarchingCubesTables.h
PolyVox/Impl/QEF.h PolyVox/Impl/PlatformDefinitions.h
PolyVox/Impl/QEF.inl
PolyVox/Impl/RandomUnitVectors.h PolyVox/Impl/RandomUnitVectors.h
PolyVox/Impl/RandomVectors.h PolyVox/Impl/RandomVectors.h
PolyVox/Impl/Timer.h PolyVox/Impl/Timer.h
PolyVox/Impl/TypeDef.h
PolyVox/Impl/Utility.h PolyVox/Impl/Utility.h
) )
@ -134,8 +129,12 @@ endif(WIN32)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/PolyVoxConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/PolyVoxConfig.cmake @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/PolyVoxConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/PolyVoxConfig.cmake @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/PolyVoxConfig.cmake DESTINATION ${CONFIG_FILE_DIR} COMPONENT development) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/PolyVoxConfig.cmake DESTINATION ${CONFIG_FILE_DIR} COMPONENT development)
FIND_PACKAGE(Doxygen)
set_package_properties(Doxygen PROPERTIES URL http://www.doxygen.org DESCRIPTION "API documentation generator" TYPE OPTIONAL PURPOSE "Building the API documentation")
#Documentation #Documentation
if(DOXYGEN_FOUND) if(DOXYGEN_FOUND)
SET(BUILD_DOCS ON PARENT_SCOPE)
#configure_file(${CMAKE_CURRENT_SOURCE_DIR}/polyvox.css ${CMAKE_CURRENT_BINARY_DIR}/polyvox.css) #configure_file(${CMAKE_CURRENT_SOURCE_DIR}/polyvox.css ${CMAKE_CURRENT_BINARY_DIR}/polyvox.css)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
#This is just the default doc target which only runs Doxygen #This is just the default doc target which only runs Doxygen
@ -168,4 +167,6 @@ if(DOXYGEN_FOUND)
OPTIONAL OPTIONAL
) )
endif() endif()
else()
SET(BUILD_DOCS OFF PARENT_SCOPE)
endif() endif()

View File

@ -1,31 +1,32 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_AStarPathfinder_H__ #ifndef __PolyVox_AStarPathfinder_H__
#define __PolyVox_AStarPathfinder_H__ #define __PolyVox_AStarPathfinder_H__
#include "Impl/AStarPathfinderImpl.h" #include "Impl/AStarPathfinderImpl.h"
#include "Impl/TypeDef.h" #include "Impl/PlatformDefinitions.h"
#include <functional> #include <functional>
#include <list> #include <list>
@ -33,48 +34,6 @@ freely, subject to the following restrictions:
namespace PolyVox namespace PolyVox
{ {
const float sqrt_1 = 1.0f;
const float sqrt_2 = 1.4143f;
const float sqrt_3 = 1.7321f;
const Vector3DInt32 arrayPathfinderFaces[6] =
{
Vector3DInt32(0, 0, -1),
Vector3DInt32(0, 0, +1),
Vector3DInt32(0, -1, 0),
Vector3DInt32(0, +1, 0),
Vector3DInt32(-1, 0, 0),
Vector3DInt32(+1, 0, 0)
};
const Vector3DInt32 arrayPathfinderEdges[12] =
{
Vector3DInt32(0, -1, -1),
Vector3DInt32(0, -1, +1),
Vector3DInt32(0, +1, -1),
Vector3DInt32(0, +1, +1),
Vector3DInt32(-1, 0, -1),
Vector3DInt32(-1, 0, +1),
Vector3DInt32(+1, 0, -1),
Vector3DInt32(+1, 0, +1),
Vector3DInt32(-1, -1, 0),
Vector3DInt32(-1, +1, 0),
Vector3DInt32(+1, -1, 0),
Vector3DInt32(+1, +1, 0)
};
const Vector3DInt32 arrayPathfinderCorners[8] =
{
Vector3DInt32(-1, -1, -1),
Vector3DInt32(-1, -1, +1),
Vector3DInt32(-1, +1, -1),
Vector3DInt32(-1, +1, +1),
Vector3DInt32(+1, -1, -1),
Vector3DInt32(+1, -1, +1),
Vector3DInt32(+1, +1, -1),
Vector3DInt32(+1, +1, +1)
};
/// This function provides the default method for checking whether a given voxel /// This function provides the default method for checking whether a given voxel
/// is valid for the path computed by the AStarPathfinder. /// is valid for the path computed by the AStarPathfinder.
template<typename VolumeType> template<typename VolumeType>
@ -104,18 +63,18 @@ namespace PolyVox
float fHBias = 1.0, float fHBias = 1.0,
uint32_t uMaxNoOfNodes = 10000, uint32_t uMaxNoOfNodes = 10000,
Connectivity requiredConnectivity = TwentySixConnected, Connectivity requiredConnectivity = TwentySixConnected,
std::function<bool (const VolumeType*, const Vector3DInt32&)> funcIsVoxelValidForPath = &aStarDefaultVoxelValidator, std::function<bool(const VolumeType*, const Vector3DInt32&)> funcIsVoxelValidForPath = &aStarDefaultVoxelValidator,
std::function<void (float)> funcProgressCallback = nullptr std::function<void(float)> funcProgressCallback = nullptr
) )
:volume(volData) :volume(volData)
,start(v3dStart) , start(v3dStart)
,end(v3dEnd) , end(v3dEnd)
,result(listResult) , result(listResult)
,connectivity(requiredConnectivity) , connectivity(requiredConnectivity)
,hBias(fHBias) , hBias(fHBias)
,maxNumberOfNodes(uMaxNoOfNodes) , maxNumberOfNodes(uMaxNoOfNodes)
,isVoxelValidForPath(funcIsVoxelValidForPath) , isVoxelValidForPath(funcIsVoxelValidForPath)
,progressCallback(funcProgressCallback) , progressCallback(funcProgressCallback)
{ {
} }
@ -159,14 +118,14 @@ namespace PolyVox
/// you could check to ensure that the voxel above is empty and the voxel below is solid. /// you could check to ensure that the voxel above is empty and the voxel below is solid.
/// ///
/// \sa aStarDefaultVoxelValidator /// \sa aStarDefaultVoxelValidator
std::function<bool (const VolumeType*, const Vector3DInt32&)> isVoxelValidForPath; std::function<bool(const VolumeType*, const Vector3DInt32&)> isVoxelValidForPath;
/// This function is called by the AStarPathfinder to report on its progress in getting to /// This function is called by the AStarPathfinder to report on its progress in getting to
/// the goal. The progress is reported by computing the distance from the closest node found /// the goal. The progress is reported by computing the distance from the closest node found
/// so far to the end node, and comparing this with the distance from the start node to the /// so far to the end node, and comparing this with the distance from the start node to the
/// end node. This progress value is guarenteed to never decrease, but it may stop increasing /// end node. This progress value is guarenteed to never decrease, but it may stop increasing
///for short periods of time. It may even stop increasing altogether if a path cannot be found. ///for short periods of time. It may even stop increasing altogether if a path cannot be found.
std::function<void (float)> progressCallback; std::function<void(float)> progressCallback;
}; };
/// The AStarPathfinder compute a path from one point in the volume to another. /// The AStarPathfinder compute a path from one point in the volume to another.
@ -224,6 +183,6 @@ namespace PolyVox
}; };
} }
#include "PolyVox/AStarPathfinder.inl" #include "AStarPathfinder.inl"
#endif //__PolyVox_AStarPathfinder_H__ #endif //__PolyVox_AStarPathfinder_H__

View File

@ -1,30 +1,76 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "PolyVox/Impl/ErrorHandling.h" #include "Impl/ErrorHandling.h"
namespace PolyVox namespace PolyVox
{ {
////////////////////////////////////////////////////////////////////////////////
// Useful constants
////////////////////////////////////////////////////////////////////////////////
const float sqrt_1 = 1.0f;
const float sqrt_2 = 1.4143f;
const float sqrt_3 = 1.7321f;
const Vector3DInt32 arrayPathfinderFaces[6] =
{
Vector3DInt32(0, 0, -1),
Vector3DInt32(0, 0, +1),
Vector3DInt32(0, -1, 0),
Vector3DInt32(0, +1, 0),
Vector3DInt32(-1, 0, 0),
Vector3DInt32(+1, 0, 0)
};
const Vector3DInt32 arrayPathfinderEdges[12] =
{
Vector3DInt32(0, -1, -1),
Vector3DInt32(0, -1, +1),
Vector3DInt32(0, +1, -1),
Vector3DInt32(0, +1, +1),
Vector3DInt32(-1, 0, -1),
Vector3DInt32(-1, 0, +1),
Vector3DInt32(+1, 0, -1),
Vector3DInt32(+1, 0, +1),
Vector3DInt32(-1, -1, 0),
Vector3DInt32(-1, +1, 0),
Vector3DInt32(+1, -1, 0),
Vector3DInt32(+1, +1, 0)
};
const Vector3DInt32 arrayPathfinderCorners[8] =
{
Vector3DInt32(-1, -1, -1),
Vector3DInt32(-1, -1, +1),
Vector3DInt32(-1, +1, -1),
Vector3DInt32(-1, +1, +1),
Vector3DInt32(+1, -1, -1),
Vector3DInt32(+1, -1, +1),
Vector3DInt32(+1, +1, -1),
Vector3DInt32(+1, +1, +1)
};
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// Using this function, a voxel is considered valid for the path if it is inside the /// Using this function, a voxel is considered valid for the path if it is inside the
/// volume and if its density is below that returned by the voxel's getDensity() function. /// volume and if its density is below that returned by the voxel's getDensity() function.
@ -34,7 +80,7 @@ namespace PolyVox
bool aStarDefaultVoxelValidator(const VolumeType* volData, const Vector3DInt32& v3dPos) bool aStarDefaultVoxelValidator(const VolumeType* volData, const Vector3DInt32& v3dPos)
{ {
//Voxels are considered valid candidates for the path if they are inside the volume... //Voxels are considered valid candidates for the path if they are inside the volume...
if(volData->getEnclosingRegion().containsPoint(v3dPos) == false) if (volData->getEnclosingRegion().containsPoint(v3dPos) == false)
{ {
return false; return false;
} }
@ -82,12 +128,12 @@ namespace PolyVox
float fDistStartToEnd = (endNode->position - startNode->position).length(); float fDistStartToEnd = (endNode->position - startNode->position).length();
m_fProgress = 0.0f; m_fProgress = 0.0f;
if(m_params.progressCallback) if (m_params.progressCallback)
{ {
m_params.progressCallback(m_fProgress); m_params.progressCallback(m_fProgress);
} }
while((openNodes.empty() == false) && (openNodes.getFirst() != endNode)) while ((openNodes.empty() == false) && (openNodes.getFirst() != endNode))
{ {
//Move the first node from open to closed. //Move the first node from open to closed.
current = openNodes.getFirst(); current = openNodes.getFirst();
@ -95,13 +141,13 @@ namespace PolyVox
closedNodes.insert(current); closedNodes.insert(current);
//Update the user on our progress //Update the user on our progress
if(m_params.progressCallback) if (m_params.progressCallback)
{ {
const float fMinProgresIncreament = 0.001f; const float fMinProgresIncreament = 0.001f;
float fDistCurrentToEnd = (endNode->position - current->position).length(); float fDistCurrentToEnd = (endNode->position - current->position).length();
float fDistNormalised = fDistCurrentToEnd / fDistStartToEnd; float fDistNormalised = fDistCurrentToEnd / fDistStartToEnd;
float fProgress = 1.0f - fDistNormalised; float fProgress = 1.0f - fDistNormalised;
if(fProgress >= m_fProgress + fMinProgresIncreament) if (fProgress >= m_fProgress + fMinProgresIncreament)
{ {
m_fProgress = fProgress; m_fProgress = fProgress;
m_params.progressCallback(m_fProgress); m_params.progressCallback(m_fProgress);
@ -115,7 +161,7 @@ namespace PolyVox
//Process the neighbours. Note the deliberate lack of 'break' //Process the neighbours. Note the deliberate lack of 'break'
//statements, larger connectivities include smaller ones. //statements, larger connectivities include smaller ones.
switch(m_params.connectivity) switch (m_params.connectivity)
{ {
case TwentySixConnected: case TwentySixConnected:
processNeighbour(current->position + arrayPathfinderCorners[0], current->gVal + fCornerCost); processNeighbour(current->position + arrayPathfinderCorners[0], current->gVal + fCornerCost);
@ -128,16 +174,16 @@ namespace PolyVox
processNeighbour(current->position + arrayPathfinderCorners[7], current->gVal + fCornerCost); processNeighbour(current->position + arrayPathfinderCorners[7], current->gVal + fCornerCost);
case EighteenConnected: case EighteenConnected:
processNeighbour(current->position + arrayPathfinderEdges[ 0], current->gVal + fEdgeCost); processNeighbour(current->position + arrayPathfinderEdges[0], current->gVal + fEdgeCost);
processNeighbour(current->position + arrayPathfinderEdges[ 1], current->gVal + fEdgeCost); processNeighbour(current->position + arrayPathfinderEdges[1], current->gVal + fEdgeCost);
processNeighbour(current->position + arrayPathfinderEdges[ 2], current->gVal + fEdgeCost); processNeighbour(current->position + arrayPathfinderEdges[2], current->gVal + fEdgeCost);
processNeighbour(current->position + arrayPathfinderEdges[ 3], current->gVal + fEdgeCost); processNeighbour(current->position + arrayPathfinderEdges[3], current->gVal + fEdgeCost);
processNeighbour(current->position + arrayPathfinderEdges[ 4], current->gVal + fEdgeCost); processNeighbour(current->position + arrayPathfinderEdges[4], current->gVal + fEdgeCost);
processNeighbour(current->position + arrayPathfinderEdges[ 5], current->gVal + fEdgeCost); processNeighbour(current->position + arrayPathfinderEdges[5], current->gVal + fEdgeCost);
processNeighbour(current->position + arrayPathfinderEdges[ 6], current->gVal + fEdgeCost); processNeighbour(current->position + arrayPathfinderEdges[6], current->gVal + fEdgeCost);
processNeighbour(current->position + arrayPathfinderEdges[ 7], current->gVal + fEdgeCost); processNeighbour(current->position + arrayPathfinderEdges[7], current->gVal + fEdgeCost);
processNeighbour(current->position + arrayPathfinderEdges[ 8], current->gVal + fEdgeCost); processNeighbour(current->position + arrayPathfinderEdges[8], current->gVal + fEdgeCost);
processNeighbour(current->position + arrayPathfinderEdges[ 9], current->gVal + fEdgeCost); processNeighbour(current->position + arrayPathfinderEdges[9], current->gVal + fEdgeCost);
processNeighbour(current->position + arrayPathfinderEdges[10], current->gVal + fEdgeCost); processNeighbour(current->position + arrayPathfinderEdges[10], current->gVal + fEdgeCost);
processNeighbour(current->position + arrayPathfinderEdges[11], current->gVal + fEdgeCost); processNeighbour(current->position + arrayPathfinderEdges[11], current->gVal + fEdgeCost);
@ -150,7 +196,7 @@ namespace PolyVox
processNeighbour(current->position + arrayPathfinderFaces[5], current->gVal + fFaceCost); processNeighbour(current->position + arrayPathfinderFaces[5], current->gVal + fFaceCost);
} }
if(allNodes.size() > m_params.maxNumberOfNodes) if (allNodes.size() > m_params.maxNumberOfNodes)
{ {
//We've reached the specified maximum number //We've reached the specified maximum number
//of nodes. Just give up on the search. //of nodes. Just give up on the search.
@ -158,7 +204,7 @@ namespace PolyVox
} }
} }
if((openNodes.empty()) || (openNodes.getFirst() != endNode)) if ((openNodes.empty()) || (openNodes.getFirst() != endNode))
{ {
//In this case we failed to find a valid path. //In this case we failed to find a valid path.
POLYVOX_THROW(std::runtime_error, "No path found"); POLYVOX_THROW(std::runtime_error, "No path found");
@ -171,14 +217,14 @@ namespace PolyVox
//custom sort operator for the set which we know only uses the position to sort. Hence we can safely //custom sort operator for the set which we know only uses the position to sort. Hence we can safely
//modify other properties of the object while it is in the set. //modify other properties of the object while it is in the set.
Node* n = const_cast<Node*>(&(*endNode)); Node* n = const_cast<Node*>(&(*endNode));
while(n != 0) while (n != 0)
{ {
m_params.result->push_front(n->position); m_params.result->push_front(n->position);
n = n->parent; n = n->parent;
} }
} }
if(m_params.progressCallback) if (m_params.progressCallback)
{ {
m_params.progressCallback(1.0f); m_params.progressCallback(1.0f);
} }
@ -188,7 +234,7 @@ namespace PolyVox
void AStarPathfinder<VolumeType>::processNeighbour(const Vector3DInt32& neighbourPos, float neighbourGVal) void AStarPathfinder<VolumeType>::processNeighbour(const Vector3DInt32& neighbourPos, float neighbourGVal)
{ {
bool bIsVoxelValidForPath = m_params.isVoxelValidForPath(m_params.volume, neighbourPos); bool bIsVoxelValidForPath = m_params.isVoxelValidForPath(m_params.volume, neighbourPos);
if(!bIsVoxelValidForPath) if (!bIsVoxelValidForPath)
{ {
return; return;
} }
@ -198,16 +244,16 @@ namespace PolyVox
std::pair<AllNodesContainer::iterator, bool> insertResult = allNodes.insert(Node(neighbourPos.getX(), neighbourPos.getY(), neighbourPos.getZ())); std::pair<AllNodesContainer::iterator, bool> insertResult = allNodes.insert(Node(neighbourPos.getX(), neighbourPos.getY(), neighbourPos.getZ()));
AllNodesContainer::iterator neighbour = insertResult.first; AllNodesContainer::iterator neighbour = insertResult.first;
if(insertResult.second == true) //New node, compute h. if (insertResult.second == true) //New node, compute h.
{ {
Node* tempNeighbour = const_cast<Node*>(&(*neighbour)); Node* tempNeighbour = const_cast<Node*>(&(*neighbour));
tempNeighbour -> hVal = computeH(neighbour->position, m_params.end); tempNeighbour->hVal = computeH(neighbour->position, m_params.end);
} }
OpenNodesContainer::iterator openIter = openNodes.find(neighbour); OpenNodesContainer::iterator openIter = openNodes.find(neighbour);
if(openIter != openNodes.end()) if (openIter != openNodes.end())
{ {
if(cost < neighbour->gVal) if (cost < neighbour->gVal)
{ {
openNodes.remove(openIter); openNodes.remove(openIter);
openIter = openNodes.end(); openIter = openNodes.end();
@ -216,9 +262,9 @@ namespace PolyVox
//TODO - Nodes could keep track of if they are in open or closed? And a pointer to where they are? //TODO - Nodes could keep track of if they are in open or closed? And a pointer to where they are?
ClosedNodesContainer::iterator closedIter = closedNodes.find(neighbour); ClosedNodesContainer::iterator closedIter = closedNodes.find(neighbour);
if(closedIter != closedNodes.end()) if (closedIter != closedNodes.end())
{ {
if(cost < neighbour->gVal) if (cost < neighbour->gVal)
{ {
//Probably shouldn't happen? //Probably shouldn't happen?
closedNodes.remove(closedIter); closedNodes.remove(closedIter);
@ -226,7 +272,7 @@ namespace PolyVox
} }
} }
if((openIter == openNodes.end()) && (closedIter == closedNodes.end())) if ((openIter == openNodes.end()) && (closedIter == closedNodes.end()))
{ {
//Regarding the const_cast - normally you should not modify an object which is in an sdt::set. //Regarding the const_cast - normally you should not modify an object which is in an sdt::set.
//The reason is that objects in a set are stored sorted in a tree so they can be accessed quickly, //The reason is that objects in a set are stored sorted in a tree so they can be accessed quickly,
@ -244,7 +290,7 @@ namespace PolyVox
float AStarPathfinder<VolumeType>::SixConnectedCost(const Vector3DInt32& a, const Vector3DInt32& b) float AStarPathfinder<VolumeType>::SixConnectedCost(const Vector3DInt32& a, const Vector3DInt32& b)
{ {
//This is the only heuristic I'm sure of - just use the manhatten distance for the 6-connected case. //This is the only heuristic I'm sure of - just use the manhatten distance for the 6-connected case.
uint32_t faceSteps = std::abs(a.getX()-b.getX()) + std::abs(a.getY()-b.getY()) + std::abs(a.getZ()-b.getZ()); uint32_t faceSteps = std::abs(a.getX() - b.getX()) + std::abs(a.getY() - b.getY()) + std::abs(a.getZ() - b.getZ());
return faceSteps * 1.0f; return faceSteps * 1.0f;
} }
@ -256,7 +302,7 @@ namespace PolyVox
//6-connected case. This means 'h' will be bigger than it should be, resulting in a faster path which may not //6-connected case. This means 'h' will be bigger than it should be, resulting in a faster path which may not
//actually be the shortest one. If you have a correct heuristic for the 18-connected case then please let me know. //actually be the shortest one. If you have a correct heuristic for the 18-connected case then please let me know.
return SixConnectedCost(a,b); return SixConnectedCost(a, b);
} }
template<typename VolumeType> template<typename VolumeType>
@ -286,7 +332,7 @@ namespace PolyVox
{ {
float hVal; float hVal;
switch(m_params.connectivity) switch (m_params.connectivity)
{ {
case TwentySixConnected: case TwentySixConnected:
hVal = TwentySixConnectedCost(a, b); hVal = TwentySixConnectedCost(a, b);
@ -303,9 +349,9 @@ namespace PolyVox
//Sanity checks in debug mode. These can come out eventually, but I //Sanity checks in debug mode. These can come out eventually, but I
//want to make sure that the heuristics I've come up with make sense. //want to make sure that the heuristics I've come up with make sense.
POLYVOX_ASSERT((a-b).length() <= TwentySixConnectedCost(a,b), "A* heuristic error."); POLYVOX_ASSERT((a - b).length() <= TwentySixConnectedCost(a, b), "A* heuristic error.");
POLYVOX_ASSERT(TwentySixConnectedCost(a,b) <= EighteenConnectedCost(a,b), "A* heuristic error."); POLYVOX_ASSERT(TwentySixConnectedCost(a, b) <= EighteenConnectedCost(a, b), "A* heuristic error.");
POLYVOX_ASSERT(EighteenConnectedCost(a,b) <= SixConnectedCost(a,b), "A* heuristic error."); POLYVOX_ASSERT(EighteenConnectedCost(a, b) <= SixConnectedCost(a, b), "A* heuristic error.");
//Apply the bias to the computed h value; //Apply the bias to the computed h value;
hVal *= m_params.hBias; hVal *= m_params.hBias;
@ -323,7 +369,7 @@ namespace PolyVox
//to make sure that position (x,y,z) has a differnt hash from e.g. position (x,z,y). //to make sure that position (x,y,z) has a differnt hash from e.g. position (x,z,y).
uint32_t aX = (a.getX() << 16) & 0x00FF0000; uint32_t aX = (a.getX() << 16) & 0x00FF0000;
uint32_t aY = (a.getY() << 8) & 0x0000FF00; uint32_t aY = (a.getY() << 8) & 0x0000FF00;
uint32_t aZ = (a.getZ() ) & 0x000000FF; uint32_t aZ = (a.getZ()) & 0x000000FF;
uint32_t hashVal = hash(aX | aY | aZ); uint32_t hashVal = hash(aX | aY | aZ);
//Stop hashVal going over 65535, and divide by 1000000 to make sure it is small. //Stop hashVal going over 65535, and divide by 1000000 to make sure it is small.
@ -338,14 +384,14 @@ namespace PolyVox
// Robert Jenkins' 32 bit integer hash function // Robert Jenkins' 32 bit integer hash function
// http://www.burtleburtle.net/bob/hash/integer.html // http://www.burtleburtle.net/bob/hash/integer.html
template<typename VolumeType> template<typename VolumeType>
uint32_t AStarPathfinder<VolumeType>::hash( uint32_t a) uint32_t AStarPathfinder<VolumeType>::hash(uint32_t a)
{ {
a = (a+0x7ed55d16) + (a<<12); a = (a + 0x7ed55d16) + (a << 12);
a = (a^0xc761c23c) ^ (a>>19); a = (a ^ 0xc761c23c) ^ (a >> 19);
a = (a+0x165667b1) + (a<<5); a = (a + 0x165667b1) + (a << 5);
a = (a+0xd3a2646c) ^ (a<<9); a = (a + 0xd3a2646c) ^ (a << 9);
a = (a+0xfd7046c5) + (a<<3); a = (a + 0xfd7046c5) + (a << 3);
a = (a^0xb55a4f09) ^ (a>>16); a = (a ^ 0xb55a4f09) ^ (a >> 16);
return a; return a;
} }
} }

View File

@ -1,24 +1,25 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __AmbientOcclusionCalculator_H__ #ifndef __AmbientOcclusionCalculator_H__
@ -27,13 +28,9 @@ freely, subject to the following restrictions:
#include "Impl/RandomUnitVectors.h" #include "Impl/RandomUnitVectors.h"
#include "Impl/RandomVectors.h" #include "Impl/RandomVectors.h"
#include "PolyVox/Array.h" #include "Array.h"
#include "PolyVox/Region.h" #include "Region.h"
#include "PolyVox/Raycast.h" #include "Raycast.h"
//These two should not be here!
#include "PolyVox/Material.h"
#include "PolyVox/PagedVolume.h"
#include <algorithm> #include <algorithm>
@ -45,7 +42,7 @@ namespace PolyVox
* Ambient occlusion * Ambient occlusion
*/ */
template<typename IsVoxelTransparentCallback> template<typename VolumeType, typename IsVoxelTransparentCallback>
class AmbientOcclusionCalculatorRaycastCallback class AmbientOcclusionCalculatorRaycastCallback
{ {
public: public:
@ -53,9 +50,9 @@ namespace PolyVox
{ {
} }
bool operator()(const PagedVolume<uint8_t>::Sampler& sampler) bool operator()(const typename VolumeType::Sampler& sampler)
{ {
uint8_t sample = sampler.getVoxel(); auto sample = sampler.getVoxel();
bool func = mIsVoxelTransparentCallback(sample); bool func = mIsVoxelTransparentCallback(sample);
return func; return func;
} }
@ -74,9 +71,9 @@ namespace PolyVox
/// Calculate the ambient occlusion for the volume /// Calculate the ambient occlusion for the volume
template<typename VolumeType, typename IsVoxelTransparentCallback> template<typename VolumeType, typename IsVoxelTransparentCallback>
void calculateAmbientOcclusion(VolumeType* volInput, Array<3, uint8_t>* arrayResult, Region region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement, IsVoxelTransparentCallback isVoxelTransparentCallback); void calculateAmbientOcclusion(VolumeType* volInput, Array<3, uint8_t>* arrayResult, const Region& region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement, IsVoxelTransparentCallback isVoxelTransparentCallback);
} }
#include "PolyVox/AmbientOcclusionCalculator.inl" #include "AmbientOcclusionCalculator.inl"
#endif //__AmbientOcclusionCalculator_H__ #endif //__AmbientOcclusionCalculator_H__

View File

@ -1,29 +1,40 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
namespace PolyVox namespace PolyVox
{ {
/** /**
* This function fills a 3D array with ambient occlusion values computed by raycasting through the volume.
* This approach to ambient occlusion is only appropriate for relatvely small volumes, otherwise it will
* become very slow and consume a lot of memory. You will need to find a way to actually use the generated
* ambient occlusion data, which might mean uploading it the the GPU as a volume texture or sampling on
* the CPU using the vertex positions from your generated mesh.
*
* In practice we have not made much use of this implementation ourselves, so you may find it needs some
* optimizations or improvements to be useful. It is likely that there are actually better approaches to
* the ambient occlusion problem.
*
* \param volInput The volume to calculate the ambient occlusion for * \param volInput The volume to calculate the ambient occlusion for
* \param[out] arrayResult The output of the calculator * \param[out] arrayResult The output of the calculator
* \param region The region of the volume for which the occlusion should be calculated * \param region The region of the volume for which the occlusion should be calculated
@ -32,18 +43,18 @@ namespace PolyVox
* \param isVoxelTransparentCallback A callback which takes a \a VoxelType and returns a \a bool whether the voxel is transparent * \param isVoxelTransparentCallback A callback which takes a \a VoxelType and returns a \a bool whether the voxel is transparent
*/ */
template<typename VolumeType, typename IsVoxelTransparentCallback> template<typename VolumeType, typename IsVoxelTransparentCallback>
void calculateAmbientOcclusion(VolumeType* volInput, Array<3, uint8_t>* arrayResult, Region region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement, IsVoxelTransparentCallback isVoxelTransparentCallback) void calculateAmbientOcclusion(VolumeType* volInput, Array<3, uint8_t>* arrayResult, const Region& region, float fRayLength, uint8_t uNoOfSamplesPerOutputElement, IsVoxelTransparentCallback isVoxelTransparentCallback)
{ {
//Make sure that the size of the volume is an exact multiple of the size of the array. //Make sure that the size of the volume is an exact multiple of the size of the array.
if(volInput->getWidth() % arrayResult->getDimension(0) != 0) if (region.getWidthInVoxels() % arrayResult->getDimension(0) != 0)
{ {
POLYVOX_THROW(std::invalid_argument, "Volume width must be an exact multiple of array width."); POLYVOX_THROW(std::invalid_argument, "Volume width must be an exact multiple of array width.");
} }
if(volInput->getHeight() % arrayResult->getDimension(1) != 0) if (region.getHeightInVoxels() % arrayResult->getDimension(1) != 0)
{ {
POLYVOX_THROW(std::invalid_argument, "Volume width must be an exact multiple of array height."); POLYVOX_THROW(std::invalid_argument, "Volume width must be an exact multiple of array height.");
} }
if(volInput->getDepth() % arrayResult->getDimension(2) != 0) if (region.getDepthInVoxels() % arrayResult->getDimension(2) != 0)
{ {
POLYVOX_THROW(std::invalid_argument, "Volume width must be an exact multiple of array depth."); POLYVOX_THROW(std::invalid_argument, "Volume width must be an exact multiple of array depth.");
} }
@ -61,9 +72,9 @@ namespace PolyVox
//nth 'random' value isn't always followed by the n+1th 'random' value. //nth 'random' value isn't always followed by the n+1th 'random' value.
uIndexIncreament = 1; uIndexIncreament = 1;
const int iRatioX = volInput->getWidth() / arrayResult->getDimension(0); const int iRatioX = region.getWidthInVoxels() / arrayResult->getDimension(0);
const int iRatioY = volInput->getHeight() / arrayResult->getDimension(1); const int iRatioY = region.getHeightInVoxels() / arrayResult->getDimension(1);
const int iRatioZ = volInput->getDepth() / arrayResult->getDimension(2); const int iRatioZ = region.getDepthInVoxels() / arrayResult->getDimension(2);
const float fRatioX = iRatioX; const float fRatioX = iRatioX;
const float fRatioY = iRatioY; const float fRatioY = iRatioY;
@ -75,14 +86,14 @@ namespace PolyVox
const float fHalfRatioZ = fRatioZ * 0.5f; const float fHalfRatioZ = fRatioZ * 0.5f;
const Vector3DFloat v3dHalfRatio(fHalfRatioX, fHalfRatioY, fHalfRatioZ); const Vector3DFloat v3dHalfRatio(fHalfRatioX, fHalfRatioY, fHalfRatioZ);
const Vector3DFloat v3dOffset(0.5f,0.5f,0.5f); const Vector3DFloat v3dOffset(0.5f, 0.5f, 0.5f);
//This loop iterates over the bottom-lower-left voxel in each of the cells in the output array //This loop iterates over the bottom-lower-left voxel in each of the cells in the output array
for(uint16_t z = region.getLowerZ(); z <= region.getUpperZ(); z += iRatioZ) for (uint16_t z = region.getLowerZ(); z <= region.getUpperZ(); z += iRatioZ)
{ {
for(uint16_t y = region.getLowerY(); y <= region.getUpperY(); y += iRatioY) for (uint16_t y = region.getLowerY(); y <= region.getUpperY(); y += iRatioY)
{ {
for(uint16_t x = region.getLowerX(); x <= region.getUpperX(); x += iRatioX) for (uint16_t x = region.getLowerX(); x <= region.getUpperX(); x += iRatioX)
{ {
//Compute a start position corresponding to //Compute a start position corresponding to
//the centre of the cell in the output array. //the centre of the cell in the output array.
@ -93,7 +104,7 @@ namespace PolyVox
//Keep track of how many rays did not hit anything //Keep track of how many rays did not hit anything
uint8_t uVisibleDirections = 0; uint8_t uVisibleDirections = 0;
for(int ct = 0; ct < uNoOfSamplesPerOutputElement; ct++) for (int ct = 0; ct < uNoOfSamplesPerOutputElement; ct++)
{ {
//We take a random vector with components going from -1 to 1 and scale it to go from -halfRatio to +halfRatio. //We take a random vector with components going from -1 to 1 and scale it to go from -halfRatio to +halfRatio.
//This jitter value moves our sample point from the centre of the array cell to somewhere else in the array cell //This jitter value moves our sample point from the centre of the array cell to somewhere else in the array cell
@ -104,19 +115,19 @@ namespace PolyVox
Vector3DFloat v3dRayDirection = randomUnitVectors[(uRandomUnitVectorIndex += (++uIndexIncreament)) % 1021]; //Different prime number. Vector3DFloat v3dRayDirection = randomUnitVectors[(uRandomUnitVectorIndex += (++uIndexIncreament)) % 1021]; //Different prime number.
v3dRayDirection *= fRayLength; v3dRayDirection *= fRayLength;
AmbientOcclusionCalculatorRaycastCallback<IsVoxelTransparentCallback> ambientOcclusionCalculatorRaycastCallback(isVoxelTransparentCallback); AmbientOcclusionCalculatorRaycastCallback<VolumeType, IsVoxelTransparentCallback> ambientOcclusionCalculatorRaycastCallback(isVoxelTransparentCallback);
RaycastResult result = raycastWithDirection(volInput, v3dRayStart, v3dRayDirection, ambientOcclusionCalculatorRaycastCallback); RaycastResult result = raycastWithDirection(volInput, v3dRayStart, v3dRayDirection, ambientOcclusionCalculatorRaycastCallback);
// Note - The performance of this could actually be improved it we exited as soon // Note - The performance of this could actually be improved it we exited as soon
// as the ray left the volume. The raycast test has an example of how to do this. // as the ray left the volume. The raycast test has an example of how to do this.
if(result == RaycastResults::Completed) if (result == RaycastResults::Completed)
{ {
++uVisibleDirections; ++uVisibleDirections;
} }
} }
float fVisibility; float fVisibility;
if(uNoOfSamplesPerOutputElement == 0) if (uNoOfSamplesPerOutputElement == 0)
{ {
//The user might request zero samples (I've done this in the past while debugging - I don't want to //The user might request zero samples (I've done this in the past while debugging - I don't want to
//wait for ambient occlusion but I do want as valid result for rendering). Avoid the divide by zero. //wait for ambient occlusion but I do want as valid result for rendering). Avoid the divide by zero.

View File

@ -1,30 +1,32 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-20014 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_Array_H__ #ifndef __PolyVox_Array_H__
#define __PolyVox_Array_H__ #define __PolyVox_Array_H__
#include <PolyVox/Impl/ErrorHandling.h> #include "Impl/ErrorHandling.h"
#include "Impl/PlatformDefinitions.h"
#include <cstdint> #include <cstdint>
@ -98,7 +100,7 @@ namespace PolyVox
return m_pElements[z * m_uDimensions[0] * m_uDimensions[1] + y * m_uDimensions[0] + x]; return m_pElements[z * m_uDimensions[0] * m_uDimensions[1] + y * m_uDimensions[0] + x];
} }
uint32_t getDimension(uint32_t dimension) uint32_t getDimension(uint32_t dimension) const
{ {
return m_uDimensions[dimension]; return m_uDimensions[dimension];
} }

View File

@ -1,65 +1,49 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_BaseVolume_H__ #ifndef __PolyVox_BaseVolume_H__
#define __PolyVox_BaseVolume_H__ #define __PolyVox_BaseVolume_H__
#include "PolyVox/Region.h" #include "Region.h"
#include "PolyVox/Vector.h" #include "Vector.h"
#include <limits> #include <limits>
namespace PolyVox namespace PolyVox
{ {
/// The BaseVolume class provides common functionality and an interface for other volume classes to implement. You should not try to create an instance of this /// The BaseVolume class provides common functionality and an interface for other volume classes to implement.
/// class directly. Instead you should use RawVolume or PagedVolume. /// You should not try to create an instance of this class directly. Instead you should use RawVolume or PagedVolume.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// More details to come... /// \sa RawVolume, PagedVolume
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace WrapModes
{
enum WrapMode
{
Validate = 0,
Clamp = 1,
Border = 2,
AssumeValid = 3
};
}
typedef WrapModes::WrapMode WrapMode;
// Required for a trick to implement specialization of template member
// functions in template classes. See http://stackoverflow.com/a/4951057
template <WrapMode W> struct WrapModeType{};
template <typename _VoxelType> template <typename _VoxelType>
class BaseVolume class BaseVolume
{ {
public: public:
typedef _VoxelType VoxelType; typedef _VoxelType VoxelType;
#ifndef SWIG #ifndef SWIG
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
class Sampler class Sampler
{ {
@ -70,12 +54,9 @@ namespace PolyVox
Vector3DInt32 getPosition(void) const; Vector3DInt32 getPosition(void) const;
inline VoxelType getVoxel(void) const; inline VoxelType getVoxel(void) const;
bool isCurrentPositionValid(void) const;
void setPosition(const Vector3DInt32& v3dNewPos); void setPosition(const Vector3DInt32& v3dNewPos);
void setPosition(int32_t xPos, int32_t yPos, int32_t zPos); void setPosition(int32_t xPos, int32_t yPos, int32_t zPos);
inline bool setVoxel(VoxelType tValue); inline bool setVoxel(VoxelType tValue);
void setWrapMode(WrapMode eWrapMode, VoxelType tBorder = VoxelType());
void movePositiveX(void); void movePositiveX(void);
void movePositiveY(void); void movePositiveY(void);
@ -116,7 +97,6 @@ namespace PolyVox
inline VoxelType peekVoxel1px1py1pz(void) const; inline VoxelType peekVoxel1px1py1pz(void) const;
protected: protected:
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
DerivedVolumeType* mVolume; DerivedVolumeType* mVolume;
@ -124,70 +104,26 @@ namespace PolyVox
int32_t mXPosInVolume; int32_t mXPosInVolume;
int32_t mYPosInVolume; int32_t mYPosInVolume;
int32_t mZPosInVolume; int32_t mZPosInVolume;
WrapMode m_eWrapMode;
VoxelType m_tBorder;
//Whether the current position is inside the volume
//FIXME - Replace these with flags
bool m_bIsCurrentPositionValidInX;
bool m_bIsCurrentPositionValidInY;
bool m_bIsCurrentPositionValidInZ;
}; };
#endif #endif // SWIG
public: public:
/// Gets the value used for voxels which are outside the volume
VoxelType getBorderValue(void) const;
/// Gets a Region representing the extents of the Volume.
const Region& getEnclosingRegion(void) const;
/// Gets the width of the volume in voxels.
int32_t getWidth(void) const;
/// Gets the height of the volume in voxels.
int32_t getHeight(void) const;
/// Gets the depth of the volume in voxels.
int32_t getDepth(void) const;
/// Gets the length of the longest side in voxels
int32_t getLongestSideLength(void) const;
/// Gets the length of the shortest side in voxels
int32_t getShortestSideLength(void) const;
/// Gets the length of the diagonal in voxels
float getDiagonalLength(void) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates /// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
template <WrapMode eWrapMode> VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const;
/// Gets a voxel at the position given by a 3D vector /// Gets a voxel at the position given by a 3D vector
template <WrapMode eWrapMode> VoxelType getVoxel(const Vector3DInt32& v3dPos) const;
VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
POLYVOX_DEPRECATED VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
/// Gets a voxel at the position given by a 3D vector
POLYVOX_DEPRECATED VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const;
/// Sets the value used for voxels which are outside the volume
void setBorderValue(const VoxelType& tBorder);
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates /// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue);
/// Sets the voxel at the position given by a 3D vector /// Sets the voxel at the position given by a 3D vector
void setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); void setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue);
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue);
/// Sets the voxel at the position given by a 3D vector
bool setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue);
/// Calculates approximatly how many bytes of memory the volume is currently using. /// Calculates approximatly how many bytes of memory the volume is currently using.
uint32_t calculateSizeInBytes(void); uint32_t calculateSizeInBytes(void);
protected: protected:
/// Constructor for creating a fixed size volume. /// Constructor for creating a volume.
BaseVolume(const Region& regValid); BaseVolume();
/// Copy constructor /// Copy constructor
BaseVolume(const BaseVolume& rhs); BaseVolume(const BaseVolume& rhs);
@ -197,21 +133,10 @@ namespace PolyVox
/// Assignment operator /// Assignment operator
BaseVolume& operator=(const BaseVolume& rhs); BaseVolume& operator=(const BaseVolume& rhs);
//The size of the volume
Region m_regValidRegion;
//Some useful sizes
int32_t m_uLongestSideLength;
int32_t m_uShortestSideLength;
float m_fDiagonalLength;
//The border value
VoxelType m_tBorderValue;
}; };
} }
#include "PolyVox/BaseVolume.inl" #include "BaseVolume.inl"
#include "PolyVox/BaseVolumeSampler.inl" #include "BaseVolumeSampler.inl"
#endif //__PolyVox_BaseVolume_H__ #endif //__PolyVox_BaseVolume_H__

View File

@ -1,24 +1,25 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
namespace PolyVox namespace PolyVox
@ -29,9 +30,7 @@ namespace PolyVox
/// \sa RawVolume, PagedVolume /// \sa RawVolume, PagedVolume
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
BaseVolume<VoxelType>::BaseVolume(const Region& regValid) BaseVolume<VoxelType>::BaseVolume()
:m_regValidRegion(regValid)
,m_tBorderValue()
{ {
} }
@ -45,7 +44,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
BaseVolume<VoxelType>::BaseVolume(const BaseVolume<VoxelType>& /*rhs*/) BaseVolume<VoxelType>::BaseVolume(const BaseVolume<VoxelType>& /*rhs*/)
{ {
POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented for performance reasons."); POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented to prevent accidental copying.");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -66,127 +65,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
BaseVolume<VoxelType>& BaseVolume<VoxelType>::operator=(const BaseVolume<VoxelType>& /*rhs*/) BaseVolume<VoxelType>& BaseVolume<VoxelType>::operator=(const BaseVolume<VoxelType>& /*rhs*/)
{ {
POLYVOX_THROW(not_implemented, "Volume assignment operator not implemented for performance reasons."); POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented to prevent accidental copying.");
}
////////////////////////////////////////////////////////////////////////////////
/// The border value is returned whenever an attempt is made to read a voxel which
/// is outside the extents of the volume.
/// \return The value used for voxels outside of the volume
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getBorderValue(void) const
{
return m_tBorderValue;
}
////////////////////////////////////////////////////////////////////////////////
/// \return A Region representing the extent of the volume.
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
const Region& BaseVolume<VoxelType>::getEnclosingRegion(void) const
{
return m_regValidRegion;
}
////////////////////////////////////////////////////////////////////////////////
/// \return The width of the volume in voxels. Note that this value is inclusive, so that if the valid range is e.g. 0 to 63 then the width is 64.
/// \sa getHeight(), getDepth()
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
int32_t BaseVolume<VoxelType>::getWidth(void) const
{
return m_regValidRegion.getUpperX() - m_regValidRegion.getLowerX() + 1;
}
////////////////////////////////////////////////////////////////////////////////
/// \return The height of the volume in voxels. Note that this value is inclusive, so that if the valid range is e.g. 0 to 63 then the height is 64.
/// \sa getWidth(), getDepth()
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
int32_t BaseVolume<VoxelType>::getHeight(void) const
{
return m_regValidRegion.getUpperY() - m_regValidRegion.getLowerY() + 1;
}
////////////////////////////////////////////////////////////////////////////////
/// \return The depth of the volume in voxels. Note that this value is inclusive, so that if the valid range is e.g. 0 to 63 then the depth is 64.
/// \sa getWidth(), getHeight()
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
int32_t BaseVolume<VoxelType>::getDepth(void) const
{
return m_regValidRegion.getUpperZ() - m_regValidRegion.getLowerZ() + 1;
}
////////////////////////////////////////////////////////////////////////////////
/// \return The length of the shortest side in voxels. For example, if a volume has
/// dimensions 256x512x1024 this function will return 256.
/// \sa getLongestSideLength(), getDiagonalLength()
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
int32_t BaseVolume<VoxelType>::getShortestSideLength(void) const
{
return m_uShortestSideLength;
}
////////////////////////////////////////////////////////////////////////////////
/// \return The length of the longest side in voxels. For example, if a volume has
/// dimensions 256x512x1024 this function will return 1024.
/// \sa getShortestSideLength(), getDiagonalLength()
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
int32_t BaseVolume<VoxelType>::getLongestSideLength(void) const
{
return m_uLongestSideLength;
}
////////////////////////////////////////////////////////////////////////////////
/// \return The length of the diagonal in voxels. For example, if a volume has
/// dimensions 256x512x1024 this function will return sqrt(256*256+512*512+1024*1024)
/// = 1173.139. This value is computed on volume creation so retrieving it is fast.
/// \sa getShortestSideLength(), getLongestSideLength()
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
float BaseVolume<VoxelType>::getDiagonalLength(void) const
{
return m_fDiagonalLength;
}
////////////////////////////////////////////////////////////////////////////////
/// This version of the function requires the wrap mode to be specified as a
/// template parameter, which can provide better performance.
/// \param uXPos The \c x position of the voxel
/// \param uYPos The \c y position of the voxel
/// \param uZPos The \c z position of the voxel
/// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume.
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
template <WrapMode eWrapMode>
VoxelType BaseVolume<VoxelType>::getVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, VoxelType /*tBorder*/) const
{
POLYVOX_ASSERT(false, "You should never call the base class version of this function.");
return VoxelType();
}
////////////////////////////////////////////////////////////////////////////////
/// This version of the function requires the wrap mode to be specified as a
/// template parameter, which can provide better performance.
/// \param uXPos The \c x position of the voxel
/// \param uYPos The \c y position of the voxel
/// \param uZPos The \c z position of the voxel
/// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume.
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
template <WrapMode eWrapMode>
VoxelType BaseVolume<VoxelType>::getVoxel(const Vector3DInt32& /*v3dPos*/, VoxelType /*tBorder*/) const
{
POLYVOX_ASSERT(false, "You should never call the base class version of this function.");
return VoxelType();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -195,12 +74,10 @@ namespace PolyVox
/// \param uXPos The \c x position of the voxel /// \param uXPos The \c x position of the voxel
/// \param uYPos The \c y position of the voxel /// \param uYPos The \c y position of the voxel
/// \param uZPos The \c z position of the voxel /// \param uZPos The \c z position of the voxel
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
/// \return The voxel value /// \return The voxel value
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const VoxelType BaseVolume<VoxelType>::getVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/) const
{ {
POLYVOX_ASSERT(false, "You should never call the base class version of this function."); POLYVOX_ASSERT(false, "You should never call the base class version of this function.");
return VoxelType(); return VoxelType();
@ -210,50 +87,15 @@ namespace PolyVox
/// This version of the function is provided so that the wrap mode does not need /// This version of the function is provided so that the wrap mode does not need
/// to be specified as a template parameter, as it may be confusing to some users. /// to be specified as a template parameter, as it may be confusing to some users.
/// \param v3dPos The 3D position of the voxel /// \param v3dPos The 3D position of the voxel
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
/// \return The voxel value /// \return The voxel value
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxel(const Vector3DInt32& /*v3dPos*/, WrapMode /*eWrapMode*/, VoxelType /*tBorder*/) const VoxelType BaseVolume<VoxelType>::getVoxel(const Vector3DInt32& /*v3dPos*/) const
{ {
POLYVOX_ASSERT(false, "You should never call the base class version of this function."); POLYVOX_ASSERT(false, "You should never call the base class version of this function.");
return VoxelType(); return VoxelType();
} }
////////////////////////////////////////////////////////////////////////////////
/// \param uXPos The \c x position of the voxel
/// \param uYPos The \c y position of the voxel
/// \param uZPos The \c z position of the voxel
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxelAt(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/) const
{
POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return VoxelType();
}
////////////////////////////////////////////////////////////////////////////////
/// \param v3dPos The 3D position of the voxel
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType BaseVolume<VoxelType>::getVoxelAt(const Vector3DInt32& /*v3dPos*/) const
{
POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return VoxelType();
}
////////////////////////////////////////////////////////////////////////////////
/// \param tBorder The value to use for voxels outside the volume.
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
void BaseVolume<VoxelType>::setBorderValue(const VoxelType& tBorder)
{
m_tBorderValue = tBorder;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// \param uXPos the \c x position of the voxel /// \param uXPos the \c x position of the voxel
/// \param uYPos the \c y position of the voxel /// \param uYPos the \c y position of the voxel
@ -261,7 +103,7 @@ namespace PolyVox
/// \param tValue the value to which the voxel will be set /// \param tValue the value to which the voxel will be set
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
void BaseVolume<VoxelType>::setVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, VoxelType /*tValue*/, WrapMode /*eWrapMode*/) void BaseVolume<VoxelType>::setVoxel(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, VoxelType /*tValue*/)
{ {
POLYVOX_THROW(not_implemented, "You should never call the base class version of this function."); POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
} }
@ -271,44 +113,19 @@ namespace PolyVox
/// \param tValue the value to which the voxel will be set /// \param tValue the value to which the voxel will be set
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
void BaseVolume<VoxelType>::setVoxel(const Vector3DInt32& /*v3dPos*/, VoxelType /*tValue*/, WrapMode /*eWrapMode*/) void BaseVolume<VoxelType>::setVoxel(const Vector3DInt32& /*v3dPos*/, VoxelType /*tValue*/)
{ {
POLYVOX_THROW(not_implemented, "You should never call the base class version of this function."); POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// \param uXPos the \c x position of the voxel ///
/// \param uYPos the \c y position of the voxel
/// \param uZPos the \c z position of the voxel
/// \param tValue the value to which the voxel will be set
/// \return whether the requested position is inside the volume
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
bool BaseVolume<VoxelType>::setVoxelAt(int32_t /*uXPos*/, int32_t /*uYPos*/, int32_t /*uZPos*/, VoxelType /*tValue*/)
{
POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// \param v3dPos the 3D position of the voxel
/// \param tValue the value to which the voxel will be set
/// \return whether the requested position is inside the volume
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
bool BaseVolume<VoxelType>::setVoxelAt(const Vector3DInt32& /*v3dPos*/, VoxelType /*tValue*/)
{
POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// Note: This function needs reviewing for accuracy...
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
uint32_t BaseVolume<VoxelType>::calculateSizeInBytes(void) uint32_t BaseVolume<VoxelType>::calculateSizeInBytes(void)
{ {
return getWidth() * getHeight() * getDepth() * sizeof(VoxelType); POLYVOX_THROW(not_implemented, "You should never call the base class version of this function.");
return 0;
} }
} }

View File

@ -1,27 +1,28 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "PolyVox/Impl/Utility.h" #include "Impl/Utility.h"
namespace PolyVox namespace PolyVox
{ {
@ -29,14 +30,9 @@ namespace PolyVox
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::Sampler(DerivedVolumeType* volume) BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::Sampler(DerivedVolumeType* volume)
:mVolume(volume) :mVolume(volume)
,mXPosInVolume(0) , mXPosInVolume(0)
,mYPosInVolume(0) , mYPosInVolume(0)
,mZPosInVolume(0) , mZPosInVolume(0)
,m_eWrapMode(WrapModes::Border)
,m_tBorder()
,m_bIsCurrentPositionValidInX(false)
,m_bIsCurrentPositionValidInY(false)
,m_bIsCurrentPositionValidInZ(false)
{ {
} }
@ -57,14 +53,7 @@ namespace PolyVox
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::getVoxel(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::getVoxel(void) const
{ {
return mVolume->getVoxel(mXPosInVolume, mYPosInVolume, mZPosInVolume, WrapModes::Validate); // FIXME - Use templatised version instead but watch for Linux compile errors. return mVolume->getVoxel(mXPosInVolume, mYPosInVolume, mZPosInVolume);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
bool inline BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::isCurrentPositionValid(void) const
{
return m_bIsCurrentPositionValidInX && m_bIsCurrentPositionValidInY && m_bIsCurrentPositionValidInZ;
} }
template <typename VoxelType> template <typename VoxelType>
@ -81,25 +70,13 @@ namespace PolyVox
mXPosInVolume = xPos; mXPosInVolume = xPos;
mYPosInVolume = yPos; mYPosInVolume = yPos;
mZPosInVolume = zPos; mZPosInVolume = zPos;
m_bIsCurrentPositionValidInX = mVolume->getEnclosingRegion().containsPointInX(xPos);
m_bIsCurrentPositionValidInY = mVolume->getEnclosingRegion().containsPointInY(yPos);
m_bIsCurrentPositionValidInZ = mVolume->getEnclosingRegion().containsPointInZ(zPos);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
bool BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::setVoxel(VoxelType tValue) bool BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::setVoxel(VoxelType tValue)
{ {
return mVolume->setVoxelAt(mXPosInVolume, mYPosInVolume, mZPosInVolume, tValue); return mVolume->setVoxel(mXPosInVolume, mYPosInVolume, mZPosInVolume, tValue);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::setWrapMode(WrapMode eWrapMode, VoxelType tBorder)
{
m_eWrapMode = eWrapMode;
m_tBorder = tBorder;
} }
template <typename VoxelType> template <typename VoxelType>
@ -107,7 +84,6 @@ namespace PolyVox
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::movePositiveX(void) void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::movePositiveX(void)
{ {
mXPosInVolume++; mXPosInVolume++;
m_bIsCurrentPositionValidInX = mVolume->getEnclosingRegion().containsPointInX(mXPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
@ -115,7 +91,6 @@ namespace PolyVox
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::movePositiveY(void) void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::movePositiveY(void)
{ {
mYPosInVolume++; mYPosInVolume++;
m_bIsCurrentPositionValidInY = mVolume->getEnclosingRegion().containsPointInY(mYPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
@ -123,7 +98,6 @@ namespace PolyVox
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::movePositiveZ(void) void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::movePositiveZ(void)
{ {
mZPosInVolume++; mZPosInVolume++;
m_bIsCurrentPositionValidInZ = mVolume->getEnclosingRegion().containsPointInZ(mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
@ -131,7 +105,6 @@ namespace PolyVox
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::moveNegativeX(void) void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::moveNegativeX(void)
{ {
mXPosInVolume--; mXPosInVolume--;
m_bIsCurrentPositionValidInX = mVolume->getEnclosingRegion().containsPointInX(mXPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
@ -139,7 +112,6 @@ namespace PolyVox
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::moveNegativeY(void) void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::moveNegativeY(void)
{ {
mYPosInVolume--; mYPosInVolume--;
m_bIsCurrentPositionValidInY = mVolume->getEnclosingRegion().containsPointInY(mYPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
@ -147,70 +119,69 @@ namespace PolyVox
void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::moveNegativeZ(void) void BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::moveNegativeZ(void)
{ {
mZPosInVolume--; mZPosInVolume--;
m_bIsCurrentPositionValidInZ = mVolume->getEnclosingRegion().containsPointInZ(mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1ny1nz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1ny1nz(void) const
{ {
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume - 1); return mVolume->getVoxel(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1ny0pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1ny0pz(void) const
{ {
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume ); return mVolume->getVoxel(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1ny1pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1ny1pz(void) const
{ {
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume + 1); return mVolume->getVoxel(mXPosInVolume - 1, mYPosInVolume - 1, mZPosInVolume + 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx0py1nz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx0py1nz(void) const
{ {
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume - 1); return mVolume->getVoxel(mXPosInVolume - 1, mYPosInVolume, mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx0py0pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx0py0pz(void) const
{ {
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume ); return mVolume->getVoxel(mXPosInVolume - 1, mYPosInVolume, mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx0py1pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx0py1pz(void) const
{ {
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume , mZPosInVolume + 1); return mVolume->getVoxel(mXPosInVolume - 1, mYPosInVolume, mZPosInVolume + 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1py1nz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1py1nz(void) const
{ {
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume - 1); return mVolume->getVoxel(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1py0pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1py0pz(void) const
{ {
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume ); return mVolume->getVoxel(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1py1pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1nx1py1pz(void) const
{ {
return getVoxelImpl(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume + 1); return mVolume->getVoxel(mXPosInVolume - 1, mYPosInVolume + 1, mZPosInVolume + 1);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -219,63 +190,63 @@ namespace PolyVox
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1ny1nz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1ny1nz(void) const
{ {
return getVoxelImpl(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume - 1); return mVolume->getVoxel(mXPosInVolume, mYPosInVolume - 1, mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1ny0pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1ny0pz(void) const
{ {
return getVoxelImpl(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume ); return mVolume->getVoxel(mXPosInVolume, mYPosInVolume - 1, mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1ny1pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1ny1pz(void) const
{ {
return getVoxelImpl(mXPosInVolume , mYPosInVolume - 1, mZPosInVolume + 1); return mVolume->getVoxel(mXPosInVolume, mYPosInVolume - 1, mZPosInVolume + 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px0py1nz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px0py1nz(void) const
{ {
return getVoxelImpl(mXPosInVolume , mYPosInVolume , mZPosInVolume - 1); return mVolume->getVoxel(mXPosInVolume, mYPosInVolume, mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px0py0pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px0py0pz(void) const
{ {
return getVoxelImpl(mXPosInVolume , mYPosInVolume , mZPosInVolume ); return mVolume->getVoxel(mXPosInVolume, mYPosInVolume, mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px0py1pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px0py1pz(void) const
{ {
return getVoxelImpl(mXPosInVolume , mYPosInVolume , mZPosInVolume + 1); return mVolume->getVoxel(mXPosInVolume, mYPosInVolume, mZPosInVolume + 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1py1nz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1py1nz(void) const
{ {
return getVoxelImpl(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume - 1); return mVolume->getVoxel(mXPosInVolume, mYPosInVolume + 1, mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1py0pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1py0pz(void) const
{ {
return getVoxelImpl(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume ); return mVolume->getVoxel(mXPosInVolume, mYPosInVolume + 1, mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1py1pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel0px1py1pz(void) const
{ {
return getVoxelImpl(mXPosInVolume , mYPosInVolume + 1, mZPosInVolume + 1); return mVolume->getVoxel(mXPosInVolume, mYPosInVolume + 1, mZPosInVolume + 1);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -284,83 +255,62 @@ namespace PolyVox
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1ny1nz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1ny1nz(void) const
{ {
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume - 1); return mVolume->getVoxel(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1ny0pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1ny0pz(void) const
{ {
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume ); return mVolume->getVoxel(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1ny1pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1ny1pz(void) const
{ {
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume + 1); return mVolume->getVoxel(mXPosInVolume + 1, mYPosInVolume - 1, mZPosInVolume + 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px0py1nz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px0py1nz(void) const
{ {
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume - 1); return mVolume->getVoxel(mXPosInVolume + 1, mYPosInVolume, mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px0py0pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px0py0pz(void) const
{ {
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume ); return mVolume->getVoxel(mXPosInVolume + 1, mYPosInVolume, mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px0py1pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px0py1pz(void) const
{ {
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume , mZPosInVolume + 1); return mVolume->getVoxel(mXPosInVolume + 1, mYPosInVolume, mZPosInVolume + 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1py1nz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1py1nz(void) const
{ {
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume - 1); return mVolume->getVoxel(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1py0pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1py0pz(void) const
{ {
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume ); return mVolume->getVoxel(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
template <typename DerivedVolumeType> template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1py1pz(void) const VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::peekVoxel1px1py1pz(void) const
{ {
return getVoxelImpl(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume + 1); return mVolume->getVoxel(mXPosInVolume + 1, mYPosInVolume + 1, mZPosInVolume + 1);
}
template <typename VoxelType>
template <typename DerivedVolumeType>
VoxelType BaseVolume<VoxelType>::Sampler<DerivedVolumeType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
{
switch(m_eWrapMode)
{
case WrapModes::Validate:
return mVolume->getVoxel(uXPos, uYPos, uZPos, WrapModes::Validate, m_tBorder);
case WrapModes::Clamp:
return mVolume->getVoxel(uXPos, uYPos, uZPos, WrapModes::Clamp, m_tBorder);
case WrapModes::Border:
return mVolume->getVoxel(uXPos, uYPos, uZPos, WrapModes::Border, m_tBorder);
case WrapModes::AssumeValid:
return mVolume->getVoxel(uXPos, uYPos, uZPos, WrapModes::AssumeValid, m_tBorder);
default:
// Should never happen
POLYVOX_ASSERT(false, "Invalid wrap mode");
return VoxelType();
}
} }
} }

38
include/PolyVox/Config.h Normal file
View File

@ -0,0 +1,38 @@
/*******************************************************************************
The MIT License (MIT)
Copyright (c) 2015 David Williams and Matthew Williams
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.
*******************************************************************************/
#ifndef __PolyVox_Config_H__
#define __PolyVox_Config_H__
//#define POLYVOX_LOG_TRACE_ENABLED
//#define POLYVOX_LOG_DEBUG_ENABLED
#define POLYVOX_LOG_INFO_ENABLED
#define POLYVOX_LOG_WARNING_ENABLED
#define POLYVOX_LOG_ERROR_ENABLED
#define POLYVOX_LOG_FATAL_ENABLED
//#define POLYVOX_ASSERTS_ENABLED
#define POLYVOX_THROW_ENABLED
#endif

View File

@ -1,55 +1,53 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_CubicSurfaceExtractor_H__ #ifndef __PolyVox_CubicSurfaceExtractor_H__
#define __PolyVox_CubicSurfaceExtractor_H__ #define __PolyVox_CubicSurfaceExtractor_H__
#include "Impl/TypeDef.h" #include "Impl/PlatformDefinitions.h"
#include "PolyVoxForwardDeclarations.h" #include "Array.h"
#include "BaseVolume.h" //For wrap modes... should move these?
#include "PolyVox/Array.h" #include "DefaultIsQuadNeeded.h"
#include "PolyVox/BaseVolume.h" //For wrap modes... should move these? #include "Mesh.h"
#include "PolyVox/DefaultIsQuadNeeded.h" #include "Vertex.h"
#include "PolyVox/Mesh.h"
#include "PolyVox/Vertex.h"
namespace PolyVox namespace PolyVox
{ {
#ifdef SWIG /// A specialised vertex format which encodes the data from the cubic extraction algorithm in a very
struct CubicVertex /// compact way. You will probably want to use the decodeVertex() function to turn it into a regular
#else /// Vertex for rendering, but advanced users should also be able to decode it on the GPU (not tested).
template<typename _DataType> template<typename _DataType>
struct POLYVOX_API CubicVertex struct CubicVertex
#endif
{ {
typedef _DataType DataType; typedef _DataType DataType;
// Each component of the position is stored as a single unsigned byte. /// Each component of the position is stored as a single unsigned byte.
// The true position is found by offseting each component by 0.5f. /// The true position is found by offseting each component by 0.5f.
Vector3DUint8 encodedPosition; Vector3DUint8 encodedPosition;
// User data /// A copy of the data which was stored in the voxel which generated this vertex.
DataType data; DataType data;
}; };
@ -59,170 +57,22 @@ namespace PolyVox
//using CubicMesh = Mesh< CubicVertex<VertexDataType>, IndexType >; //using CubicMesh = Mesh< CubicVertex<VertexDataType>, IndexType >;
/// Decodes a position from a CubicVertex /// Decodes a position from a CubicVertex
inline Vector3DFloat decodePosition(const Vector3DUint8& encodedPosition) inline Vector3DFloat decodePosition(const Vector3DUint8& encodedPosition);
{
Vector3DFloat result(encodedPosition.getX(), encodedPosition.getY(), encodedPosition.getZ());
result -= 0.5f; // Apply the required offset
return result;
}
/// Decodes a MarchingCubesVertex by converting it into a regular Vertex which can then be directly used for rendering. /// Decodes a CubicVertex by converting it into a regular Vertex which can then be directly used for rendering.
template<typename DataType> template<typename DataType>
Vertex<DataType> decodeVertex(const CubicVertex<DataType>& cubicVertex) Vertex<DataType> decodeVertex(const CubicVertex<DataType>& cubicVertex);
{
Vertex<DataType> result;
result.position = decodePosition(cubicVertex.encodedPosition);
result.normal.setElements(0.0f, 0.0f, 0.0f); // Currently not calculated
result.data = cubicVertex.data; // Data is not encoded
return result;
}
/// Do not use this class directly. Use the 'extractCubicSurface' function instead (see examples). /// Generates a cubic-style mesh from the voxel data.
template<typename VolumeType, typename MeshType, typename IsQuadNeeded>
class CubicSurfaceExtractor
{
struct IndexAndMaterial
{
int32_t iIndex;
typename VolumeType::VoxelType uMaterial;
};
enum FaceNames
{
PositiveX,
PositiveY,
PositiveZ,
NegativeX,
NegativeY,
NegativeZ,
NoOfFaces
};
struct Quad
{
Quad(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3)
{
vertices[0] = v0;
vertices[1] = v1;
vertices[2] = v2;
vertices[3] = v3;
}
uint32_t vertices[4];
};
public:
CubicSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, IsQuadNeeded isQuadNeeded = IsQuadNeeded(), WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true);
void execute();
private:
int32_t addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, typename VolumeType::VoxelType uMaterial, Array<3, IndexAndMaterial>& existingVertices);
bool performQuadMerging(std::list<Quad>& quads);
bool mergeQuads(Quad& q1, Quad& q2);
IsQuadNeeded m_funcIsQuadNeededCallback;
//The volume data and a sampler to access it.
VolumeType* m_volData;
//Information about the region we are currently processing
Region m_regSizeInVoxels;
//The surface patch we are currently filling.
MeshType* m_meshCurrent;
//Used to avoid creating duplicate vertices.
Array<3, IndexAndMaterial> m_previousSliceVertices;
Array<3, IndexAndMaterial> m_currentSliceVertices;
//During extraction we create a number of different lists of quads. All the
//quads in a given list are in the same plane and facing in the same direction.
std::vector< std::list<Quad> > m_vecQuads[NoOfFaces];
//Controls whether quad merging should be performed. This might be undesirable
//is the user needs per-vertex attributes, or to perform per vertex lighting.
bool m_bMergeQuads;
//This constant defines the maximum number of quads which can share a
//vertex in a cubic style mesh. See the initialisation for more details.
static const uint32_t MaxVerticesPerPosition;
//The wrap mode
WrapMode m_eWrapMode;
typename VolumeType::VoxelType m_tBorderValue;
};
// This version of the function performs the extraction into a user-provided mesh rather than allocating a mesh automatically.
// There are a few reasons why this might be useful to more advanced users:
//
// 1. It leaves the user in control of memory allocation and would allow them to implement e.g. a mesh pooling system.
// 2. The user-provided mesh could have a different index type (e.g. 16-bit indices) to reduce memory usage.
// 3. The user could provide a custom mesh class, e.g a thin wrapper around an openGL VBO to allow direct writing into this structure.
//
// We don't provide a default MeshType here. If the user doesn't want to provide a MeshType then it probably makes
// more sense to use the other variant of this function where the mesh is a return value rather than a parameter.
//
// Note: This function is called 'extractCubicMeshCustom' rather than 'extractCubicMesh' to avoid ambiguity when only three parameters
// are provided (would the third parameter be a controller or a mesh?). It seems this can be fixed by using enable_if/static_assert to emulate concepts,
// but this is relatively complex and I haven't done it yet. Could always add it later as another overload.
template<typename VolumeType, typename MeshType, typename IsQuadNeeded = DefaultIsQuadNeeded<typename VolumeType::VoxelType> > template<typename VolumeType, typename MeshType, typename IsQuadNeeded = DefaultIsQuadNeeded<typename VolumeType::VoxelType> >
void extractCubicMeshCustom(VolumeType* volData, Region region, MeshType* result, IsQuadNeeded isQuadNeeded = IsQuadNeeded(), WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true) void extractCubicMeshCustom(VolumeType* volData, Region region, MeshType* result, IsQuadNeeded isQuadNeeded = IsQuadNeeded(), bool bMergeQuads = true);
{
CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded> extractor(volData, region, result, isQuadNeeded, eWrapMode, tBorderValue, bMergeQuads);
extractor.execute();
}
/// The CubicSurfaceExtractor creates a mesh in which each voxel appears to be rendered as a cube /// Generates a cubic-style mesh from the voxel data, placing the result into a user-provided Mesh.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Introduction
/// ------------
/// Games such as Minecraft and Voxatron have a unique graphical style in which each voxel in the world appears to be rendered as a single cube. Actually rendering a cube for each voxel would be very expensive, but in practice the only faces which need to be drawn are those which lie on the boundary between solid and empty voxels. The CubicSurfaceExtractor can be used to create such a mesh from PolyVox volume data. As an example, images from Minecraft and Voxatron are shown below:
///
/// \image html MinecraftAndVoxatron.jpg
///
/// Before we get into the specifics of the CubicSurfaceExtractor, it is useful to understand the principles which apply to *all* PolyVox surface extractors and which are described in the Surface Extraction document (ADD LINK). From here on, it is assumed that you are familier with PolyVox regions and how they are used to limit surface extraction to a particular part of the volume. The principles of allowing dynamic terrain are also common to all surface extractors and are described here (ADD LINK).
///
/// Basic Operation
/// ---------------
/// At its core, the CubicSurfaceExtractor works by by looking at pairs of adjacent voxels and determining whether a quad should be placed between then. The most simple situation to imagine is a binary volume where every voxel is either solid or empty. In this case a quad should be generated whenever a solid voxel is next to an empty voxel as this represents part of the surface of the solid object. There is no need to generate a quad between two solid voxels (this quad would never be seen as it is inside the object) and there is no need to generate a quad between two empty voxels (there is no object here). PolyVox allows the principle to be extended far beyond such simple binary volumes but they provide a useful starting point for understanding how the algorithm works.
///
/// As an example, lets consider the part of a volume shown below. We are going to explain the principles in only two dimensions as this makes it much simpler to illustrate, so you will need to mentally extend the process into the third dimension. Hopefully you will find this intuitive. The diagram below shows a small part of a larger volume (as indicated by the voxel coordinates on the axes) which contains only solid and empty voxels represented by solid and hollow circles respectively. The region on which we are running the surface extractor is marked in pink, and for the purpose of this example it corresponds to the whole of the diagram.
///
/// \image html CubicSurfaceExtractor1.png
///
/// The output of the surface extractor is the mesh marked in red. As you can see, this forms a closed object which corrsponds to the shape of the underlying voxel data. We won't describe the rendering of such meshes here - for details of this please see (SOME LINK HERE).
///
/// Working with Regions
/// --------------------
/// So far the behaviour is easy to understand, but let's look at what happens when the extraction is limited to a particular region of the volume. The figure below shows the same data set as the previous figure, but the extraction region (still marked in pink) has been limited to 13 to 16 in x and 47 to 51 in y:
///
/// \image html CubicSurfaceExtractor2.png
///
/// As you can see, the extractor continues to generate a number of quads as indicated by the solid red lines. However, you can also see that the shape is no longer closed. This is because the solid voxels actually extend outside the region which is being processed, and so the extractor does not encounter a boundary between solid and empty voxels. Although this may initially appear problematic, the hole in the mesh does not actually matter because it will be hidden by the mesh corresponding to the region adjacent to it (see next diagram).
///
/// More interestingly, the diagram also contains a couple of dotted red lines lying on the bottom and right hand side of the extracted region. These are present to illustrate a common point of confusion, which is that *no quads are generated at this position even though it is a boundary between solid and empty voxels*. This is indeed somewhat counter intuitive but there is a rational reasaoning behind it.
/// If you consider the dashed line on the righthand side of the extracted region, then it is clear that this lies on a boundary between solid and empty voxels and so we do need to create quads here. But what is not so clear is whether these quads should be assigned to the mesh which corresponds to the region in pink, or whether they should be assigned to the region to the right of it which is marked in blue in the diagram below:
///
/// \image html CubicSurfaceExtractor3.png
///
/// We could choose to add the quads to *both* regions, but this can cause confusion when one of the region is modified (causing the face to disappear or a new one to be created) as *both* regions need to have their mesh regenerated to correctly represent the new state of the volume data. Such pairs of coplanar quads can also cause problems with physics engines, and may prevent transparent voxels from rendering correctly. Therefore we choose to instead only add the quad to one of the the regions and we always choose the one with the greater coordinate value in the direction in which they differ. In the above example the regions differ by the 'x' component of their position, and so the quad is added to the region with the greater 'x' value (the one marked in blue).
///
/// **Note:** *This behaviour has changed recently (September 2012). Earlier versions of PolyVox tried to be smart about this problem by looking beyond the region which was being processed, but this complicated the code and didn't work very well. Ultimatly we decided to simply stick with the convention outlined above.*
///
/// One of the practical implications of this is that when you modify a voxel *you may have to re-extract the mesh for regions other than region which actually contains the voxel you modified.* This happens when the voxel lies on the upper x,y or z face of a region. Assuming that you have some management code which can mark a region as needing re-extraction when a voxel changes, you should probably extend this to mark the regions of neighbouring voxels as invalid (this will have no effect when the voxel is well within a region, but will mark the neighbouring region as needing an update if the voxel lies on a region face).
///
/// Another scenario which sometimes results in confusion is when you wish to extract a region which corresponds to the whole volume, partcularly when solid voxels extend right to the edge of the volume.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename VolumeType, typename IsQuadNeeded = DefaultIsQuadNeeded<typename VolumeType::VoxelType> > template<typename VolumeType, typename IsQuadNeeded = DefaultIsQuadNeeded<typename VolumeType::VoxelType> >
Mesh<CubicVertex<typename VolumeType::VoxelType> > extractCubicMesh(VolumeType* volData, Region region, IsQuadNeeded isQuadNeeded = IsQuadNeeded(), WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true) Mesh<CubicVertex<typename VolumeType::VoxelType> > extractCubicMesh(VolumeType* volData, Region region, IsQuadNeeded isQuadNeeded = IsQuadNeeded(), bool bMergeQuads = true);
{
Mesh< CubicVertex<typename VolumeType::VoxelType> > result;
extractCubicMeshCustom(volData, region, &result, isQuadNeeded, eWrapMode, tBorderValue, bMergeQuads);
return result;
}
} }
#include "PolyVox/CubicSurfaceExtractor.inl" #include "CubicSurfaceExtractor.inl"
#endif #endif

View File

@ -1,30 +1,33 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "PolyVox/Impl/Timer.h" #include "Impl/Timer.h"
namespace PolyVox namespace PolyVox
{ {
// This constant defines the maximum number of quads which can share a vertex in a cubic style mesh.
//
// We try to avoid duplicate vertices by checking whether a vertex has already been added at a given position. // We try to avoid duplicate vertices by checking whether a vertex has already been added at a given position.
// However, it is possible that vertices have the same position but different materials. In this case, the // However, it is possible that vertices have the same position but different materials. In this case, the
// vertices are not true duplicates and both must be added to the mesh. As far as I can tell, it is possible to have // vertices are not true duplicates and both must be added to the mesh. As far as I can tell, it is possible to have
@ -32,228 +35,124 @@ namespace PolyVox
// happens when we have a 2x2x2 group of voxels, all with different materials and some/all partially transparent. // happens when we have a 2x2x2 group of voxels, all with different materials and some/all partially transparent.
// The vertex position at the center of this group is then going to be used by all eight voxels all with different // The vertex position at the center of this group is then going to be used by all eight voxels all with different
// materials. // materials.
template<typename VolumeType, typename MeshType, typename IsQuadNeeded> const uint32_t MaxVerticesPerPosition = 8;
const uint32_t CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded>::MaxVerticesPerPosition = 8;
template<typename VolumeType, typename MeshType, typename IsQuadNeeded> ////////////////////////////////////////////////////////////////////////////////
CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded>::CubicSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, IsQuadNeeded isQuadNeeded, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, bool bMergeQuads) // Data structures
:m_volData(volData) ////////////////////////////////////////////////////////////////////////////////
,m_regSizeInVoxels(region)
,m_meshCurrent(result) enum FaceNames
,m_previousSliceVertices(m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2, m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2, MaxVerticesPerPosition)
,m_currentSliceVertices(m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2, m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2, MaxVerticesPerPosition)
,m_bMergeQuads(bMergeQuads)
,m_eWrapMode(eWrapMode)
,m_tBorderValue(tBorderValue)
{ {
m_funcIsQuadNeededCallback = isQuadNeeded; PositiveX,
PositiveY,
PositiveZ,
NegativeX,
NegativeY,
NegativeZ,
NoOfFaces
};
// This extractor has a limit as to how large the extracted region can be, because the vertex positions are encoded with a single byte per component. struct Quad
int32_t maxReionDimension = 256; {
POLYVOX_THROW_IF(region.getWidthInVoxels() > maxReionDimension, std::invalid_argument, "Requested extraction region exceeds maximum dimensions"); Quad(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3)
POLYVOX_THROW_IF(region.getHeightInVoxels() > maxReionDimension, std::invalid_argument, "Requested extraction region exceeds maximum dimensions"); {
POLYVOX_THROW_IF(region.getDepthInVoxels() > maxReionDimension, std::invalid_argument, "Requested extraction region exceeds maximum dimensions"); vertices[0] = v0;
vertices[1] = v1;
vertices[2] = v2;
vertices[3] = v3;
} }
template<typename VolumeType, typename MeshType, typename IsQuadNeeded> uint32_t vertices[4];
void CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded>::execute() };
template<typename VolumeType>
struct IndexAndMaterial
{ {
Timer timer; int32_t iIndex;
m_meshCurrent->clear(); typename VolumeType::VoxelType uMaterial;
};
//uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2; ////////////////////////////////////////////////////////////////////////////////
//uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2; // Vertex encoding/decoding
////////////////////////////////////////////////////////////////////////////////
//uint32_t arraySize[3]= {uArrayWidth, uArrayHeight, MaxVerticesPerPosition}; inline Vector3DFloat decodePosition(const Vector3DUint8& encodedPosition)
//m_previousSliceVertices.resize(arraySize);
//m_currentSliceVertices.resize(arraySize);
memset(m_previousSliceVertices.getRawData(), 0xff, m_previousSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial));
memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial));
m_vecQuads[NegativeX].resize(m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2);
m_vecQuads[PositiveX].resize(m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2);
m_vecQuads[NegativeY].resize(m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2);
m_vecQuads[PositiveY].resize(m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2);
m_vecQuads[NegativeZ].resize(m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 2);
m_vecQuads[PositiveZ].resize(m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 2);
typename VolumeType::Sampler volumeSampler(m_volData);
volumeSampler.setWrapMode(m_eWrapMode, m_tBorderValue);
for(int32_t z = m_regSizeInVoxels.getLowerZ(); z <= m_regSizeInVoxels.getUpperZ(); z++)
{ {
uint32_t regZ = z - m_regSizeInVoxels.getLowerZ(); Vector3DFloat result(encodedPosition.getX(), encodedPosition.getY(), encodedPosition.getZ());
result -= 0.5f; // Apply the required offset
for(int32_t y = m_regSizeInVoxels.getLowerY(); y <= m_regSizeInVoxels.getUpperY(); y++) return result;
{
uint32_t regY = y - m_regSizeInVoxels.getLowerY();
volumeSampler.setPosition(m_regSizeInVoxels.getLowerX(),y,z);
for(int32_t x = m_regSizeInVoxels.getLowerX(); x <= m_regSizeInVoxels.getUpperX(); x++)
{
uint32_t regX = x - m_regSizeInVoxels.getLowerX();
typename VolumeType::VoxelType material; //Filled in by callback
typename VolumeType::VoxelType currentVoxel = volumeSampler.getVoxel();
typename VolumeType::VoxelType negXVoxel = volumeSampler.peekVoxel1nx0py0pz();
typename VolumeType::VoxelType negYVoxel = volumeSampler.peekVoxel0px1ny0pz();
typename VolumeType::VoxelType negZVoxel = volumeSampler.peekVoxel0px0py1nz();
// X
if(m_funcIsQuadNeededCallback(currentVoxel, negXVoxel, material))
{
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices);
uint32_t v1 = addVertex(regX , regY , regZ + 1, material, m_currentSliceVertices);
uint32_t v2 = addVertex(regX , regY + 1, regZ + 1, material, m_currentSliceVertices);
uint32_t v3 = addVertex(regX , regY + 1, regZ , material, m_previousSliceVertices);
m_vecQuads[NegativeX][regX].push_back(Quad(v0, v1, v2, v3));
} }
if(m_funcIsQuadNeededCallback(negXVoxel, currentVoxel, material)) template<typename DataType>
Vertex<DataType> decodeVertex(const CubicVertex<DataType>& cubicVertex)
{ {
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices); Vertex<DataType> result;
uint32_t v1 = addVertex(regX , regY , regZ + 1, material, m_currentSliceVertices); result.position = decodePosition(cubicVertex.encodedPosition);
uint32_t v2 = addVertex(regX , regY + 1, regZ + 1, material, m_currentSliceVertices); result.normal.setElements(0.0f, 0.0f, 0.0f); // Currently not calculated
uint32_t v3 = addVertex(regX , regY + 1, regZ , material, m_previousSliceVertices); result.data = cubicVertex.data; // Data is not encoded
return result;
m_vecQuads[PositiveX][regX].push_back(Quad(v0, v3, v2, v1));
} }
// Y ////////////////////////////////////////////////////////////////////////////////
if(m_funcIsQuadNeededCallback(currentVoxel, negYVoxel, material)) // Surface extraction
////////////////////////////////////////////////////////////////////////////////
template<typename MeshType>
bool mergeQuads(Quad& q1, Quad& q2, MeshType* m_meshCurrent)
{ {
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices); //All four vertices of a given quad have the same data,
uint32_t v1 = addVertex(regX + 1, regY , regZ , material, m_previousSliceVertices); //so just check that the first pair of vertices match.
uint32_t v2 = addVertex(regX + 1, regY , regZ + 1, material, m_currentSliceVertices); if (m_meshCurrent->getVertex(q1.vertices[0]).data == m_meshCurrent->getVertex(q2.vertices[0]).data)
uint32_t v3 = addVertex(regX , regY , regZ + 1, material, m_currentSliceVertices);
m_vecQuads[NegativeY][regY].push_back(Quad(v0, v1, v2, v3));
}
if(m_funcIsQuadNeededCallback(negYVoxel, currentVoxel, material))
{ {
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices); //Now check whether quad 2 is adjacent to quad one by comparing vertices.
uint32_t v1 = addVertex(regX + 1, regY , regZ , material, m_previousSliceVertices); //Adjacent quads must share two vertices, and the second quad could be to the
uint32_t v2 = addVertex(regX + 1, regY , regZ + 1, material, m_currentSliceVertices); //top, bottom, left, of right of the first one. This gives four combinations to test.
uint32_t v3 = addVertex(regX , regY , regZ + 1, material, m_currentSliceVertices); if ((q1.vertices[0] == q2.vertices[1]) && ((q1.vertices[3] == q2.vertices[2])))
m_vecQuads[PositiveY][regY].push_back(Quad(v0, v3, v2, v1));
}
// Z
if(m_funcIsQuadNeededCallback(currentVoxel, negZVoxel, material))
{ {
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices); q1.vertices[0] = q2.vertices[0];
uint32_t v1 = addVertex(regX , regY + 1, regZ , material, m_previousSliceVertices); q1.vertices[3] = q2.vertices[3];
uint32_t v2 = addVertex(regX + 1, regY + 1, regZ , material, m_previousSliceVertices); return true;
uint32_t v3 = addVertex(regX + 1, regY , regZ , material, m_previousSliceVertices);
m_vecQuads[NegativeZ][regZ].push_back(Quad(v0, v1, v2, v3));
} }
else if ((q1.vertices[3] == q2.vertices[0]) && ((q1.vertices[2] == q2.vertices[1])))
if(m_funcIsQuadNeededCallback(negZVoxel, currentVoxel, material))
{ {
uint32_t v0 = addVertex(regX , regY , regZ , material, m_previousSliceVertices); q1.vertices[3] = q2.vertices[3];
uint32_t v1 = addVertex(regX , regY + 1, regZ , material, m_previousSliceVertices); q1.vertices[2] = q2.vertices[2];
uint32_t v2 = addVertex(regX + 1, regY + 1, regZ , material, m_previousSliceVertices); return true;
uint32_t v3 = addVertex(regX + 1, regY , regZ , material, m_previousSliceVertices);
m_vecQuads[PositiveZ][regZ].push_back(Quad(v0, v3, v2, v1));
} }
else if ((q1.vertices[1] == q2.vertices[0]) && ((q1.vertices[2] == q2.vertices[3])))
volumeSampler.movePositiveX(); {
q1.vertices[1] = q2.vertices[1];
q1.vertices[2] = q2.vertices[2];
return true;
}
else if ((q1.vertices[0] == q2.vertices[3]) && ((q1.vertices[1] == q2.vertices[2])))
{
q1.vertices[0] = q2.vertices[0];
q1.vertices[1] = q2.vertices[1];
return true;
} }
} }
m_previousSliceVertices.swap(m_currentSliceVertices); //Quads cannot be merged.
memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial)); return false;
} }
for(uint32_t uFace = 0; uFace < NoOfFaces; uFace++) template<typename MeshType>
{ bool performQuadMerging(std::list<Quad>& quads, MeshType* m_meshCurrent)
std::vector< std::list<Quad> >& vecListQuads = m_vecQuads[uFace];
for(uint32_t slice = 0; slice < vecListQuads.size(); slice++)
{
std::list<Quad>& listQuads = vecListQuads[slice];
if(m_bMergeQuads)
{
//Repeatedly call this function until it returns
//false to indicate nothing more can be done.
while(performQuadMerging(listQuads)){}
}
typename std::list<Quad>::iterator iterEnd = listQuads.end();
for(typename std::list<Quad>::iterator quadIter = listQuads.begin(); quadIter != iterEnd; quadIter++)
{
Quad& quad = *quadIter;
m_meshCurrent->addTriangle(quad.vertices[0], quad.vertices[1],quad.vertices[2]);
m_meshCurrent->addTriangle(quad.vertices[0], quad.vertices[2],quad.vertices[3]);
}
}
}
m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner());
m_meshCurrent->removeUnusedVertices();
POLYVOX_LOG_TRACE("Cubic surface extraction took " << timer.elapsedTimeInMilliSeconds()
<< "ms (Region size = " << m_regSizeInVoxels.getWidthInVoxels() << "x" << m_regSizeInVoxels.getHeightInVoxels()
<< "x" << m_regSizeInVoxels.getDepthInVoxels() << ")");
}
template<typename VolumeType, typename MeshType, typename IsQuadNeeded>
int32_t CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded>::addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, typename VolumeType::VoxelType uMaterialIn, Array<3, IndexAndMaterial>& existingVertices)
{
for(uint32_t ct = 0; ct < MaxVerticesPerPosition; ct++)
{
IndexAndMaterial& rEntry = existingVertices(uX, uY, ct);
if(rEntry.iIndex == -1)
{
//No vertices matched and we've now hit an empty space. Fill it by creating a vertex. The 0.5f offset is because vertices set between voxels in order to build cubes around them.
CubicVertex<typename VolumeType::VoxelType> cubicVertex;
cubicVertex.encodedPosition.setElements(static_cast<uint8_t>(uX), static_cast<uint8_t>(uY), static_cast<uint8_t>(uZ));
cubicVertex.data = uMaterialIn;
rEntry.iIndex = m_meshCurrent->addVertex(cubicVertex);
rEntry.uMaterial = uMaterialIn;
return rEntry.iIndex;
}
//If we have an existing vertex and the material matches then we can return it.
if(rEntry.uMaterial == uMaterialIn)
{
return rEntry.iIndex;
}
}
// If we exit the loop here then apparently all the slots were full but none of them matched.
// This shouldn't ever happen, so if it does it is probably a bug in PolyVox. Please report it to us!
POLYVOX_THROW(std::runtime_error, "All slots full but no matches during cubic surface extraction. This is probably a bug in PolyVox");
return -1; //Should never happen.
}
template<typename VolumeType, typename MeshType, typename IsQuadNeeded>
bool CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded>::performQuadMerging(std::list<Quad>& quads)
{ {
bool bDidMerge = false; bool bDidMerge = false;
for(typename std::list<Quad>::iterator outerIter = quads.begin(); outerIter != quads.end(); outerIter++) for (typename std::list<Quad>::iterator outerIter = quads.begin(); outerIter != quads.end(); outerIter++)
{ {
typename std::list<Quad>::iterator innerIter = outerIter; typename std::list<Quad>::iterator innerIter = outerIter;
innerIter++; innerIter++;
while(innerIter != quads.end()) while (innerIter != quads.end())
{ {
Quad& q1 = *outerIter; Quad& q1 = *outerIter;
Quad& q2 = *innerIter; Quad& q2 = *innerIter;
bool result = mergeQuads(q1,q2); bool result = mergeQuads(q1, q2, m_meshCurrent);
if(result) if (result)
{ {
bDidMerge = true; bDidMerge = true;
innerIter = quads.erase(innerIter); innerIter = quads.erase(innerIter);
@ -268,43 +167,256 @@ namespace PolyVox
return bDidMerge; return bDidMerge;
} }
template<typename VolumeType, typename MeshType, typename IsQuadNeeded> template<typename VolumeType, typename MeshType>
bool CubicSurfaceExtractor<VolumeType, MeshType, IsQuadNeeded>::mergeQuads(Quad& q1, Quad& q2) int32_t addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, typename VolumeType::VoxelType uMaterialIn, Array<3, IndexAndMaterial<VolumeType> >& existingVertices, MeshType* m_meshCurrent)
{ {
//All four vertices of a given quad have the same data, for (uint32_t ct = 0; ct < MaxVerticesPerPosition; ct++)
//so just check that the first pair of vertices match.
if (m_meshCurrent->getVertices()[q1.vertices[0]].data == m_meshCurrent->getVertices()[q2.vertices[0]].data)
{ {
//Now check whether quad 2 is adjacent to quad one by comparing vertices. IndexAndMaterial<VolumeType>& rEntry = existingVertices(uX, uY, ct);
//Adjacent quads must share two vertices, and the second quad could be to the
//top, bottom, left, of right of the first one. This gives four combinations to test. if (rEntry.iIndex == -1)
if((q1.vertices[0] == q2.vertices[1]) && ((q1.vertices[3] == q2.vertices[2])))
{ {
q1.vertices[0] = q2.vertices[0]; //No vertices matched and we've now hit an empty space. Fill it by creating a vertex. The 0.5f offset is because vertices set between voxels in order to build cubes around them.
q1.vertices[3] = q2.vertices[3]; CubicVertex<typename VolumeType::VoxelType> cubicVertex;
return true; cubicVertex.encodedPosition.setElements(static_cast<uint8_t>(uX), static_cast<uint8_t>(uY), static_cast<uint8_t>(uZ));
cubicVertex.data = uMaterialIn;
rEntry.iIndex = m_meshCurrent->addVertex(cubicVertex);
rEntry.uMaterial = uMaterialIn;
return rEntry.iIndex;
} }
else if((q1.vertices[3] == q2.vertices[0]) && ((q1.vertices[2] == q2.vertices[1])))
//If we have an existing vertex and the material matches then we can return it.
if (rEntry.uMaterial == uMaterialIn)
{ {
q1.vertices[3] = q2.vertices[3]; return rEntry.iIndex;
q1.vertices[2] = q2.vertices[2];
return true;
}
else if((q1.vertices[1] == q2.vertices[0]) && ((q1.vertices[2] == q2.vertices[3])))
{
q1.vertices[1] = q2.vertices[1];
q1.vertices[2] = q2.vertices[2];
return true;
}
else if((q1.vertices[0] == q2.vertices[3]) && ((q1.vertices[1] == q2.vertices[2])))
{
q1.vertices[0] = q2.vertices[0];
q1.vertices[1] = q2.vertices[1];
return true;
} }
} }
//Quads cannot be merged. // If we exit the loop here then apparently all the slots were full but none of them matched.
return false; // This shouldn't ever happen, so if it does it is probably a bug in PolyVox. Please report it to us!
POLYVOX_THROW(std::runtime_error, "All slots full but no matches during cubic surface extraction. This is probably a bug in PolyVox");
return -1; //Should never happen.
}
/// The CubicSurfaceExtractor creates a mesh in which each voxel appears to be rendered as a cube
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Introduction
/// ------------
/// Games such as Minecraft and Voxatron have a unique graphical style in which each voxel in the world appears to be rendered as a single cube. Actually rendering a cube for each voxel would be very expensive, but in practice the only faces which need to be drawn are those which lie on the boundary between solid and empty voxels. The CubicSurfaceExtractor can be used to create such a mesh from PolyVox volume data. As an example, images from Minecraft and Voxatron are shown below:
///
/// \image html MinecraftAndVoxatron.jpg
///
/// Before we get into the specifics of the CubicSurfaceExtractor, it is useful to understand the principles which apply to *all* PolyVox surface extractors and which are described in the Surface Extraction document (ADD LINK). From here on, it is assumed that you are familier with PolyVox regions and how they are used to limit surface extraction to a particular part of the volume. The principles of allowing dynamic terrain are also common to all surface extractors and are described here (ADD LINK).
///
/// Basic Operation
/// ---------------
/// At its core, the CubicSurfaceExtractor works by by looking at pairs of adjacent voxels and determining whether a quad should be placed between then. The most simple situation to imagine is a binary volume where every voxel is either solid or empty. In this case a quad should be generated whenever a solid voxel is next to an empty voxel as this represents part of the surface of the solid object. There is no need to generate a quad between two solid voxels (this quad would never be seen as it is inside the object) and there is no need to generate a quad between two empty voxels (there is no object here). PolyVox allows the principle to be extended far beyond such simple binary volumes but they provide a useful starting point for understanding how the algorithm works.
///
/// As an example, lets consider the part of a volume shown below. We are going to explain the principles in only two dimensions as this makes it much simpler to illustrate, so you will need to mentally extend the process into the third dimension. Hopefully you will find this intuitive. The diagram below shows a small part of a larger volume (as indicated by the voxel coordinates on the axes) which contains only solid and empty voxels represented by solid and hollow circles respectively. The region on which we are running the surface extractor is marked in pink, and for the purpose of this example it corresponds to the whole of the diagram.
///
/// \image html CubicSurfaceExtractor1.png
///
/// The output of the surface extractor is the mesh marked in red. As you can see, this forms a closed object which corrsponds to the shape of the underlying voxel data. We won't describe the rendering of such meshes here - for details of this please see (SOME LINK HERE).
///
/// Working with Regions
/// --------------------
/// So far the behaviour is easy to understand, but let's look at what happens when the extraction is limited to a particular region of the volume. The figure below shows the same data set as the previous figure, but the extraction region (still marked in pink) has been limited to 13 to 16 in x and 47 to 51 in y:
///
/// \image html CubicSurfaceExtractor2.png
///
/// As you can see, the extractor continues to generate a number of quads as indicated by the solid red lines. However, you can also see that the shape is no longer closed. This is because the solid voxels actually extend outside the region which is being processed, and so the extractor does not encounter a boundary between solid and empty voxels. Although this may initially appear problematic, the hole in the mesh does not actually matter because it will be hidden by the mesh corresponding to the region adjacent to it (see next diagram).
///
/// More interestingly, the diagram also contains a couple of dotted red lines lying on the bottom and right hand side of the extracted region. These are present to illustrate a common point of confusion, which is that *no quads are generated at this position even though it is a boundary between solid and empty voxels*. This is indeed somewhat counter intuitive but there is a rational reasaoning behind it.
/// If you consider the dashed line on the righthand side of the extracted region, then it is clear that this lies on a boundary between solid and empty voxels and so we do need to create quads here. But what is not so clear is whether these quads should be assigned to the mesh which corresponds to the region in pink, or whether they should be assigned to the region to the right of it which is marked in blue in the diagram below:
///
/// \image html CubicSurfaceExtractor3.png
///
/// We could choose to add the quads to *both* regions, but this can cause confusion when one of the region is modified (causing the face to disappear or a new one to be created) as *both* regions need to have their mesh regenerated to correctly represent the new state of the volume data. Such pairs of coplanar quads can also cause problems with physics engines, and may prevent transparent voxels from rendering correctly. Therefore we choose to instead only add the quad to one of the the regions and we always choose the one with the greater coordinate value in the direction in which they differ. In the above example the regions differ by the 'x' component of their position, and so the quad is added to the region with the greater 'x' value (the one marked in blue).
///
/// **Note:** *This behaviour has changed recently (September 2012). Earlier versions of PolyVox tried to be smart about this problem by looking beyond the region which was being processed, but this complicated the code and didn't work very well. Ultimatly we decided to simply stick with the convention outlined above.*
///
/// One of the practical implications of this is that when you modify a voxel *you may have to re-extract the mesh for regions other than region which actually contains the voxel you modified.* This happens when the voxel lies on the upper x,y or z face of a region. Assuming that you have some management code which can mark a region as needing re-extraction when a voxel changes, you should probably extend this to mark the regions of neighbouring voxels as invalid (this will have no effect when the voxel is well within a region, but will mark the neighbouring region as needing an update if the voxel lies on a region face).
///
/// Another scenario which sometimes results in confusion is when you wish to extract a region which corresponds to the whole volume, partcularly when solid voxels extend right to the edge of the volume.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename VolumeType, typename IsQuadNeeded>
Mesh<CubicVertex<typename VolumeType::VoxelType> > extractCubicMesh(VolumeType* volData, Region region, IsQuadNeeded isQuadNeeded, bool bMergeQuads)
{
Mesh< CubicVertex<typename VolumeType::VoxelType> > result;
extractCubicMeshCustom(volData, region, &result, isQuadNeeded, bMergeQuads);
return result;
}
/// This version of the function performs the extraction into a user-provided mesh rather than allocating a mesh automatically.
/// There are a few reasons why this might be useful to more advanced users:
///
/// 1. It leaves the user in control of memory allocation and would allow them to implement e.g. a mesh pooling system.
/// 2. The user-provided mesh could have a different index type (e.g. 16-bit indices) to reduce memory usage.
/// 3. The user could provide a custom mesh class, e.g a thin wrapper around an openGL VBO to allow direct writing into this structure.
///
/// We don't provide a default MeshType here. If the user doesn't want to provide a MeshType then it probably makes
/// more sense to use the other variant of this function where the mesh is a return value rather than a parameter.
///
/// Note: This function is called 'extractCubicMeshCustom' rather than 'extractCubicMesh' to avoid ambiguity when only three parameters
/// are provided (would the third parameter be a controller or a mesh?). It seems this can be fixed by using enable_if/static_assert to emulate concepts,
/// but this is relatively complex and I haven't done it yet. Could always add it later as another overload.
template<typename VolumeType, typename MeshType, typename IsQuadNeeded>
void extractCubicMeshCustom(VolumeType* volData, Region region, MeshType* result, IsQuadNeeded isQuadNeeded, bool bMergeQuads)
{
// This extractor has a limit as to how large the extracted region can be, because the vertex positions are encoded with a single byte per component.
int32_t maxReionDimensionInVoxels = 255;
POLYVOX_THROW_IF(region.getWidthInVoxels() > maxReionDimensionInVoxels, std::invalid_argument, "Requested extraction region exceeds maximum dimensions");
POLYVOX_THROW_IF(region.getHeightInVoxels() > maxReionDimensionInVoxels, std::invalid_argument, "Requested extraction region exceeds maximum dimensions");
POLYVOX_THROW_IF(region.getDepthInVoxels() > maxReionDimensionInVoxels, std::invalid_argument, "Requested extraction region exceeds maximum dimensions");
Timer timer;
result->clear();
//Used to avoid creating duplicate vertices.
Array<3, IndexAndMaterial<VolumeType> > m_previousSliceVertices(region.getUpperX() - region.getLowerX() + 2, region.getUpperY() - region.getLowerY() + 2, MaxVerticesPerPosition);
Array<3, IndexAndMaterial<VolumeType> > m_currentSliceVertices(region.getUpperX() - region.getLowerX() + 2, region.getUpperY() - region.getLowerY() + 2, MaxVerticesPerPosition);
//During extraction we create a number of different lists of quads. All the
//quads in a given list are in the same plane and facing in the same direction.
std::vector< std::list<Quad> > m_vecQuads[NoOfFaces];
memset(m_previousSliceVertices.getRawData(), 0xff, m_previousSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial<VolumeType>));
memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial<VolumeType>));
m_vecQuads[NegativeX].resize(region.getUpperX() - region.getLowerX() + 2);
m_vecQuads[PositiveX].resize(region.getUpperX() - region.getLowerX() + 2);
m_vecQuads[NegativeY].resize(region.getUpperY() - region.getLowerY() + 2);
m_vecQuads[PositiveY].resize(region.getUpperY() - region.getLowerY() + 2);
m_vecQuads[NegativeZ].resize(region.getUpperZ() - region.getLowerZ() + 2);
m_vecQuads[PositiveZ].resize(region.getUpperZ() - region.getLowerZ() + 2);
typename VolumeType::Sampler volumeSampler(volData);
for (int32_t z = region.getLowerZ(); z <= region.getUpperZ(); z++)
{
uint32_t regZ = z - region.getLowerZ();
for (int32_t y = region.getLowerY(); y <= region.getUpperY(); y++)
{
uint32_t regY = y - region.getLowerY();
volumeSampler.setPosition(region.getLowerX(), y, z);
for (int32_t x = region.getLowerX(); x <= region.getUpperX(); x++)
{
uint32_t regX = x - region.getLowerX();
typename VolumeType::VoxelType material; //Filled in by callback
typename VolumeType::VoxelType currentVoxel = volumeSampler.getVoxel();
typename VolumeType::VoxelType negXVoxel = volumeSampler.peekVoxel1nx0py0pz();
typename VolumeType::VoxelType negYVoxel = volumeSampler.peekVoxel0px1ny0pz();
typename VolumeType::VoxelType negZVoxel = volumeSampler.peekVoxel0px0py1nz();
// X
if (isQuadNeeded(currentVoxel, negXVoxel, material))
{
uint32_t v0 = addVertex(regX, regY, regZ, material, m_previousSliceVertices, result);
uint32_t v1 = addVertex(regX, regY, regZ + 1, material, m_currentSliceVertices, result);
uint32_t v2 = addVertex(regX, regY + 1, regZ + 1, material, m_currentSliceVertices, result);
uint32_t v3 = addVertex(regX, regY + 1, regZ, material, m_previousSliceVertices, result);
m_vecQuads[NegativeX][regX].push_back(Quad(v0, v1, v2, v3));
}
if (isQuadNeeded(negXVoxel, currentVoxel, material))
{
uint32_t v0 = addVertex(regX, regY, regZ, material, m_previousSliceVertices, result);
uint32_t v1 = addVertex(regX, regY, regZ + 1, material, m_currentSliceVertices, result);
uint32_t v2 = addVertex(regX, regY + 1, regZ + 1, material, m_currentSliceVertices, result);
uint32_t v3 = addVertex(regX, regY + 1, regZ, material, m_previousSliceVertices, result);
m_vecQuads[PositiveX][regX].push_back(Quad(v0, v3, v2, v1));
}
// Y
if (isQuadNeeded(currentVoxel, negYVoxel, material))
{
uint32_t v0 = addVertex(regX, regY, regZ, material, m_previousSliceVertices, result);
uint32_t v1 = addVertex(regX + 1, regY, regZ, material, m_previousSliceVertices, result);
uint32_t v2 = addVertex(regX + 1, regY, regZ + 1, material, m_currentSliceVertices, result);
uint32_t v3 = addVertex(regX, regY, regZ + 1, material, m_currentSliceVertices, result);
m_vecQuads[NegativeY][regY].push_back(Quad(v0, v1, v2, v3));
}
if (isQuadNeeded(negYVoxel, currentVoxel, material))
{
uint32_t v0 = addVertex(regX, regY, regZ, material, m_previousSliceVertices, result);
uint32_t v1 = addVertex(regX + 1, regY, regZ, material, m_previousSliceVertices, result);
uint32_t v2 = addVertex(regX + 1, regY, regZ + 1, material, m_currentSliceVertices, result);
uint32_t v3 = addVertex(regX, regY, regZ + 1, material, m_currentSliceVertices, result);
m_vecQuads[PositiveY][regY].push_back(Quad(v0, v3, v2, v1));
}
// Z
if (isQuadNeeded(currentVoxel, negZVoxel, material))
{
uint32_t v0 = addVertex(regX, regY, regZ, material, m_previousSliceVertices, result);
uint32_t v1 = addVertex(regX, regY + 1, regZ, material, m_previousSliceVertices, result);
uint32_t v2 = addVertex(regX + 1, regY + 1, regZ, material, m_previousSliceVertices, result);
uint32_t v3 = addVertex(regX + 1, regY, regZ, material, m_previousSliceVertices, result);
m_vecQuads[NegativeZ][regZ].push_back(Quad(v0, v1, v2, v3));
}
if (isQuadNeeded(negZVoxel, currentVoxel, material))
{
uint32_t v0 = addVertex(regX, regY, regZ, material, m_previousSliceVertices, result);
uint32_t v1 = addVertex(regX, regY + 1, regZ, material, m_previousSliceVertices, result);
uint32_t v2 = addVertex(regX + 1, regY + 1, regZ, material, m_previousSliceVertices, result);
uint32_t v3 = addVertex(regX + 1, regY, regZ, material, m_previousSliceVertices, result);
m_vecQuads[PositiveZ][regZ].push_back(Quad(v0, v3, v2, v1));
}
volumeSampler.movePositiveX();
}
}
m_previousSliceVertices.swap(m_currentSliceVertices);
memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial<VolumeType>));
}
for (uint32_t uFace = 0; uFace < NoOfFaces; uFace++)
{
std::vector< std::list<Quad> >& vecListQuads = m_vecQuads[uFace];
for (uint32_t slice = 0; slice < vecListQuads.size(); slice++)
{
std::list<Quad>& listQuads = vecListQuads[slice];
if (bMergeQuads)
{
//Repeatedly call this function until it returns
//false to indicate nothing more can be done.
while (performQuadMerging(listQuads, result)){}
}
typename std::list<Quad>::iterator iterEnd = listQuads.end();
for (typename std::list<Quad>::iterator quadIter = listQuads.begin(); quadIter != iterEnd; quadIter++)
{
Quad& quad = *quadIter;
result->addTriangle(quad.vertices[0], quad.vertices[1], quad.vertices[2]);
result->addTriangle(quad.vertices[0], quad.vertices[2], quad.vertices[3]);
}
}
}
result->setOffset(region.getLowerCorner());
result->removeUnusedVertices();
POLYVOX_LOG_TRACE("Cubic surface extraction took ", timer.elapsedTimeInMilliSeconds(),
"ms (Region size = ", m_regSizeInVoxels.getWidthInVoxels(), "x", m_regSizeInVoxels.getHeightInVoxels(),
"x", m_regSizeInVoxels.getDepthInVoxels(), ")");
} }
} }

View File

@ -1,42 +1,52 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_DefaultIsQuadNeeded_H__ #ifndef __PolyVox_DefaultIsQuadNeeded_H__
#define __PolyVox_DefaultIsQuadNeeded_H__ #define __PolyVox_DefaultIsQuadNeeded_H__
#include "PolyVox/Impl/TypeDef.h" #include "Impl/PlatformDefinitions.h"
#include <cstdint> #include <cstdint>
namespace PolyVox namespace PolyVox
{ {
/// Default implementation of a function object for deciding when
/// the cubic surface extractor should insert a face between two voxels.
///
/// The criteria used here are that the voxel in front of the potential
/// quad should have a value of zero (which would typically indicate empty
/// space) while the voxel behind the potential quad would have a value
/// geater than zero (typically indicating it is solid). Note that for
/// different behaviour users can create their own implementation and pass
/// it to extractCubicMesh().
template<typename VoxelType> template<typename VoxelType>
class DefaultIsQuadNeeded class DefaultIsQuadNeeded
{ {
public: public:
bool operator()(VoxelType back, VoxelType front, VoxelType& materialToUse) bool operator()(VoxelType back, VoxelType front, VoxelType& materialToUse)
{ {
if((back > 0) && (front == 0)) if ((back > 0) && (front == 0))
{ {
materialToUse = static_cast<VoxelType>(back); materialToUse = static_cast<VoxelType>(back);
return true; return true;

View File

@ -1,30 +1,31 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_MarchingCubesController_H__ #ifndef __PolyVox_MarchingCubesController_H__
#define __PolyVox_MarchingCubesController_H__ #define __PolyVox_MarchingCubesController_H__
#include "PolyVox/BaseVolume.h" #include "BaseVolume.h"
#include <limits> #include <limits>
@ -55,7 +56,7 @@ namespace PolyVox
* will pass through the density value specified by the threshold, and so you should make sure that the threshold value you choose is between * will pass through the density value specified by the threshold, and so you should make sure that the threshold value you choose is between
* the minimum and maximum values found in your volume data. By default it is in the middle of the representable range of the underlying type. * the minimum and maximum values found in your volume data. By default it is in the middle of the representable range of the underlying type.
* *
* \sa MarchingCubesSurfaceExtractor * \sa extractMarchingCubesMesh
* *
*/ */
template<typename VoxelType> template<typename VoxelType>
@ -118,7 +119,7 @@ namespace PolyVox
*/ */
MaterialType blendMaterials(VoxelType a, VoxelType b, float /*weight*/) MaterialType blendMaterials(VoxelType a, VoxelType b, float /*weight*/)
{ {
if(convertToDensity(a) > convertToDensity(b)) if (convertToDensity(a) > convertToDensity(b))
{ {
return convertToMaterial(a); return convertToMaterial(a);
} }

View File

@ -1,32 +1,33 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_Density_H__ #ifndef __PolyVox_Density_H__
#define __PolyVox_Density_H__ #define __PolyVox_Density_H__
#include "PolyVox/DefaultMarchingCubesController.h" //We'll specialise the controller contained in here #include "DefaultMarchingCubesController.h" //We'll specialise the controller contained in here
#include "Impl/TypeDef.h" #include "Impl/PlatformDefinitions.h"
#include <limits> #include <limits>
@ -37,7 +38,11 @@ namespace PolyVox
{ {
/// This class represents a voxel storing only a density. /// This class represents a voxel storing only a density.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// Detailed description... /// Note that this should probably just be considered an example of how to define
/// a voxel type for the Marching Cubes algorithm. Advanced users are likely to
/// define custom voxel types and possibly custom controllers.
///
/// \sa Material, MaterialDensityPair
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename Type> template <typename Type>
class Density class Density

View File

@ -1,41 +0,0 @@
/*******************************************************************************
Copyright (c) 2014 David Williams and Matt Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#ifndef __PolyVox_DualContouringSurfaceExtractor_H__
#define __PolyVox_DualContouringSurfaceExtractor_H__
#include "Impl/TypeDef.h"
#include "PolyVoxCore/Array.h"
#include "PolyVoxCore/BaseVolume.h"
#include "PolyVoxCore/SurfaceMesh.h"
namespace PolyVox
{
template< typename VolumeType, typename ControllerType>
SurfaceMesh<PositionMaterialNormal> dualContouringSurfaceExtractor(VolumeType* volData, const Region& region, const ControllerType& controller);
}
#include "PolyVoxCore/DualContouringSurfaceExtractor.inl"
#endif

View File

@ -1,359 +0,0 @@
/*******************************************************************************
Copyright (c) 2014 David Williams and Matt Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#include "PolyVoxCore/SurfaceMesh.h"
#include "PolyVoxCore/VertexTypes.h"
#include "Impl/Timer.h"
#include "Impl/QEF.h"
#include <type_traits>
//BUG We will get duplucation of edges if the surface is along region boundaries
namespace PolyVox
{
namespace
{
template<typename VoxelType>
struct EdgeData
{
EdgeData() : intersects(false) {}
Vector3DFloat normal;
float fraction; ///<fraction (0.0-1.0) along the edge in the positive direction that the intersection happens
bool intersects;
};
template<typename VoxelType>
struct CellData
{
EdgeData<VoxelType> edges[3];
uint32_t vertexIndex;
};
template<typename VoxelType, typename ThresholdType>
EdgeData<VoxelType> calculateEdge(const VoxelType& vA, const VoxelType& vB, const Vector3DFloat& gA, const Vector3DFloat& gB, const ThresholdType& threshold)
{
EdgeData<VoxelType> edge;
edge.fraction = static_cast<float>(vA - threshold) / static_cast<float>(vA - vB);
if(std::min(vA,vB) <= threshold && std::max(vA,vB) > threshold)
{
edge.intersects = true;
}
else
{
edge.intersects = false;
return edge;
}
edge.normal = (gA * edge.fraction + gB * (1.0f-edge.fraction));
if(edge.normal.lengthSquared() != 0.0f)
{
edge.normal.normalise();
}
return edge;
}
template<typename VoxelType>
PositionMaterialNormal computeVertex(EdgeData<VoxelType>* edges[12])
{
Vector3DFloat massPoint{0,0,0}; //The average of the intersection vertices
Vector3DFloat vertices[12];
vertices[0] = {edges[0]->fraction, 0, 0};
vertices[1] = {0, edges[1]->fraction, 0};
vertices[2] = {0, 0, edges[2]->fraction};
vertices[3] = {1, edges[3]->fraction, 0};
vertices[4] = {1, 0, edges[4]->fraction};
vertices[5] = {0, 1, edges[5]->fraction};
vertices[6] = {edges[6]->fraction, 1, 0};
vertices[7] = {edges[7]->fraction, 0, 1};
vertices[8] = {0, edges[8]->fraction, 1};
vertices[9] = {1, 1, edges[9]->fraction};
vertices[10] = {1, edges[10]->fraction, 1};
vertices[11] = {edges[11]->fraction, 1, 1};
int numIntersections = 0;
for(int i = 0; i < 12; ++i)
{
if(!edges[i]->intersects)
{
continue;
}
++numIntersections;
massPoint += vertices[i];
}
massPoint /= numIntersections; //Make the average
Vector3DFloat cellVertexNormal{0,0,0};
double matrix[12][3];
double vector[12];
int rows = 0;
for(int i = 0; i < 12; ++i)
{
if(!edges[i]->intersects)
{
continue;
}
Vector3DFloat normal = edges[i]->normal;
matrix[rows][0] = normal.getX();
matrix[rows][1] = normal.getY();
matrix[rows][2] = normal.getZ();
const Vector3DFloat product = normal * (vertices[i] - massPoint);
vector[rows] = product.getX() + product.getY() + product.getZ();
cellVertexNormal += normal;
++rows;
}
const auto& vertexPosition = evaluateQEF(matrix, vector, rows) + massPoint;
POLYVOX_ASSERT(vertexPosition.getX() >= -0.01 && vertexPosition.getY() >= -0.01 && vertexPosition.getZ() >= -0.01 && vertexPosition.getX() <= 1.01 && vertexPosition.getY() <= 1.01 && vertexPosition.getZ() <= 1.01, "Vertex is outside unit cell"); //0.01 to give a little leniency
if(cellVertexNormal.lengthSquared() != 0.0f)
{
cellVertexNormal.normalise();
}
return {vertexPosition, cellVertexNormal, 0};
}
uint32_t convert(uint32_t x, uint32_t y, uint32_t z, uint32_t X, uint32_t Y)
{
return z*Y*X+y*X+x;
}
}
template<typename VolumeType, typename ControllerType>
SurfaceMesh<PositionMaterialNormal> dualContouringSurfaceExtractor(VolumeType* volData, const Region& region, const ControllerType& controller)
{
static_assert(std::is_signed<typename ControllerType::DensityType>::value, "Voxel type must be signed");
const auto threshold = controller.getThreshold();
//Timer timer;
Timer totalTimer;
const auto regionXDimension = region.getDimensionsInVoxels().getX();
const auto regionYDimension = region.getDimensionsInVoxels().getY();
const auto regionZDimension = region.getDimensionsInVoxels().getZ();
const auto gradientRegionXDimension = regionXDimension+2;
const auto gradientRegionYDimension = regionYDimension+2;
const auto gradientRegionZDimension = regionZDimension+2;
std::vector<std::pair<const typename VolumeType::VoxelType, const Vector3DFloat>> gradients;
gradients.reserve(gradientRegionXDimension * gradientRegionYDimension * gradientRegionZDimension);
typename VolumeType::Sampler volSampler{volData};
volSampler.setPosition(region.getLowerCorner() - Vector3DInt32{1,1,1});
volSampler.setWrapMode(WrapMode::Border, -100.0); // -100.0 is well below the threshold
const auto lowerCornerX = region.getLowerCorner().getX();
const auto lowerCornerY = region.getLowerCorner().getZ();
const auto lowerCornerZ = region.getLowerCorner().getX();
//logTrace() << "Setup took " << timer.elapsedTimeInMilliSeconds();
//timer.start();
for(int32_t z = 0; z < gradientRegionZDimension; z++)
{
volSampler.setPosition(lowerCornerX-1, lowerCornerY-1, lowerCornerZ+z-1); //Reset x and y and increment z
for(int32_t y = 0; y < gradientRegionYDimension; y++)
{
volSampler.setPosition(lowerCornerX-1, lowerCornerY+y-1, lowerCornerZ+z-1); //Reset x and increment y (z remains the same)
for(int32_t x = 0; x < gradientRegionXDimension; x++)
{
volSampler.movePositiveX(); //Increment x
const auto& voxel = controller.convertToDensity(volSampler.getVoxel());
const auto& voxel1px = controller.convertToDensity(volSampler.peekVoxel1px0py0pz());
const auto& voxel1py = controller.convertToDensity(volSampler.peekVoxel0px1py0pz());
const auto& voxel1pz = controller.convertToDensity(volSampler.peekVoxel0px0py1pz());
const auto& voxel1nx = controller.convertToDensity(volSampler.peekVoxel1nx0py0pz());
const auto& voxel1ny = controller.convertToDensity(volSampler.peekVoxel0px1ny0pz());
const auto& voxel1nz = controller.convertToDensity(volSampler.peekVoxel0px0py1nz());
gradients.emplace_back(voxel, Vector3DFloat(voxel1nx - voxel1px, voxel1ny - voxel1py, voxel1nz - voxel1pz));
}
}
}
//logTrace() << "Gradients took " << timer.elapsedTimeInMilliSeconds();
//timer.start();
const auto cellRegionXDimension = regionXDimension+2;
const auto cellRegionYDimension = regionYDimension+2;
const auto cellRegionZDimension = regionZDimension+2;
std::vector<CellData<typename VolumeType::VoxelType>> cells;
cells.reserve(cellRegionXDimension * cellRegionYDimension * cellRegionZDimension);
for(int32_t cellZ = 0; cellZ < cellRegionZDimension; cellZ++)
{
for(int32_t cellY = 0; cellY < cellRegionYDimension; cellY++)
{
for(int32_t cellX = 0; cellX < cellRegionXDimension; cellX++)
{
//For each cell, calculate the edge intersection points and normals
const auto& g000 = gradients[convert(cellX, cellY, cellZ, cellRegionXDimension, cellRegionYDimension)];
//For the last columns/rows, only calculate the interior edge
if(cellX < cellRegionXDimension-1 && cellY < cellRegionYDimension-1 && cellZ < cellRegionZDimension-1) //This is the main bulk
{
const auto& g100 = gradients[convert(cellX+1, cellY, cellZ, cellRegionXDimension, cellRegionYDimension)];
const auto& g010 = gradients[convert(cellX, cellY+1, cellZ, cellRegionXDimension, cellRegionYDimension)];
const auto& g001 = gradients[convert(cellX, cellY, cellZ+1, cellRegionXDimension, cellRegionYDimension)];
cells.push_back({calculateEdge(g000.first, g100.first, g000.second, g100.second, threshold), calculateEdge(g000.first, g010.first, g000.second, g010.second, threshold), calculateEdge(g000.first, g001.first, g000.second, g001.second, threshold)});
}
else if(cellX == cellRegionXDimension-1 || cellY == cellRegionYDimension-1 || cellZ == cellRegionZDimension-1) //This is the three far edges and the far corner
{
cells.push_back({}); //Default and empty
}
else if(cellX == cellRegionXDimension-1) //Far x side
{
const auto& g100 = gradients[convert(cellX+1, cellY, cellZ, cellRegionXDimension, cellRegionYDimension)];
cells.push_back({calculateEdge(g000.first, g100.first, g000.second, g100.second, threshold), EdgeData<typename VolumeType::VoxelType>(), EdgeData<typename VolumeType::VoxelType>()});
}
else if(cellY == cellRegionYDimension-1) //Far y side
{
const auto& g010 = gradients[convert(cellX+1, cellY, cellZ, cellRegionXDimension, cellRegionYDimension)];
cells.push_back({EdgeData<typename VolumeType::VoxelType>(), calculateEdge(g000.first, g010.first, g000.second, g010.second, threshold), EdgeData<typename VolumeType::VoxelType>()});
}
else if(cellZ == cellRegionZDimension-1) //Far z side
{
const auto& g001 = gradients[convert(cellX+1, cellY, cellZ, cellRegionXDimension, cellRegionYDimension)];
cells.push_back({EdgeData<typename VolumeType::VoxelType>(), EdgeData<typename VolumeType::VoxelType>(), calculateEdge(g000.first, g001.first, g000.second, g001.second, threshold)});
}
}
}
}
//logTrace() << "Edges took " << timer.elapsedTimeInMilliSeconds();
//timer.start();
EdgeData<typename VolumeType::VoxelType>* edges[12]; //Create this now but it will be overwritten for each cell
SurfaceMesh<PositionMaterialNormal> mesh;
for(int32_t cellZ = 0; cellZ < cellRegionZDimension; cellZ++)
{
for(int32_t cellY = 0; cellY < cellRegionYDimension; cellY++)
{
for(int32_t cellX = 0; cellX < cellRegionXDimension; cellX++)
{
if(cellZ >= 1 && cellY >= 1 && cellX >= 1)
{
//After the first rows and columns are done, start calculating vertex positions
const int32_t cellXVertex = cellX-1;
const int32_t cellYVertex = cellY-1;
const int32_t cellZVertex = cellZ-1;
auto& cell = cells[convert(cellXVertex, cellYVertex, cellZVertex, cellRegionXDimension, cellRegionYDimension)];
edges[0] = &cell.edges[0];
edges[1] = &cell.edges[1];
edges[2] = &cell.edges[2];
edges[3] = &cells[convert(cellXVertex+1, cellYVertex, cellZVertex, cellRegionXDimension, cellRegionYDimension)].edges[1];
edges[4] = &cells[convert(cellXVertex+1, cellYVertex, cellZVertex, cellRegionXDimension, cellRegionYDimension)].edges[2];
edges[5] = &cells[convert(cellXVertex, cellYVertex+1, cellZVertex, cellRegionXDimension, cellRegionYDimension)].edges[2];
edges[6] = &cells[convert(cellXVertex, cellYVertex+1, cellZVertex, cellRegionXDimension, cellRegionYDimension)].edges[0];
edges[7] = &cells[convert(cellXVertex, cellYVertex, cellZVertex+1, cellRegionXDimension, cellRegionYDimension)].edges[0];
edges[8] = &cells[convert(cellXVertex, cellYVertex, cellZVertex+1, cellRegionXDimension, cellRegionYDimension)].edges[1];
edges[9] = &cells[convert(cellXVertex+1, cellYVertex+1, cellZVertex, cellRegionXDimension, cellRegionYDimension)].edges[2];
edges[10] = &cells[convert(cellXVertex+1, cellYVertex, cellZVertex+1, cellRegionXDimension, cellRegionYDimension)].edges[1];
edges[11] = &cells[convert(cellXVertex, cellYVertex+1, cellZVertex+1, cellRegionXDimension, cellRegionYDimension)].edges[0];
if(edges[0]->intersects || edges[1]->intersects || edges[2]->intersects || edges[3]->intersects || edges[4]->intersects || edges[5]->intersects || edges[6]->intersects || edges[7]->intersects || edges[8]->intersects || edges[9]->intersects || edges[10]->intersects || edges[11]->intersects) //'if' Maybe not needed?
{
auto vertex = computeVertex(edges);
vertex.setPosition({vertex.getPosition().getX()+cellXVertex, vertex.getPosition().getY()+cellYVertex, vertex.getPosition().getZ()+cellZVertex});
cell.vertexIndex = mesh.addVertex(vertex);
if(cellZVertex >= 1 && cellYVertex >= 1 && cellXVertex >= 1)
{
//Once the second rows and colums are done, start connecting up edges
if(cell.edges[0].intersects)
{
const auto& v1 = cells[convert(cellXVertex, cellYVertex-1, cellZVertex, cellRegionXDimension, cellRegionYDimension)];
const auto& v2 = cells[convert(cellXVertex, cellYVertex, cellZVertex-1, cellRegionXDimension, cellRegionYDimension)];
const auto& v3 = cells[convert(cellXVertex, cellYVertex-1, cellZVertex-1, cellRegionXDimension, cellRegionYDimension)];
mesh.addTriangle(cell.vertexIndex, v1.vertexIndex, v2.vertexIndex);
mesh.addTriangle(v3.vertexIndex, v2.vertexIndex, v1.vertexIndex);
}
if(cell.edges[1].intersects)
{
const auto& v1 = cells[convert(cellXVertex-1, cellYVertex, cellZVertex, cellRegionXDimension, cellRegionYDimension)];
const auto& v2 = cells[convert(cellXVertex, cellYVertex, cellZVertex-1, cellRegionXDimension, cellRegionYDimension)];
const auto& v3 = cells[convert(cellXVertex-1, cellYVertex, cellZVertex-1, cellRegionXDimension, cellRegionYDimension)];
mesh.addTriangle(cell.vertexIndex, v1.vertexIndex, v2.vertexIndex);
mesh.addTriangle(v3.vertexIndex, v2.vertexIndex, v1.vertexIndex);
}
if(cell.edges[2].intersects)
{
const auto& v1 = cells[convert(cellXVertex-1, cellYVertex, cellZVertex, cellRegionXDimension, cellRegionYDimension)];
const auto& v2 = cells[convert(cellXVertex, cellYVertex-1, cellZVertex, cellRegionXDimension, cellRegionYDimension)];
const auto& v3 = cells[convert(cellXVertex-1, cellYVertex-1, cellZVertex, cellRegionXDimension, cellRegionYDimension)];
mesh.addTriangle(cell.vertexIndex, v1.vertexIndex, v2.vertexIndex);
mesh.addTriangle(v3.vertexIndex, v2.vertexIndex, v1.vertexIndex);
}
}
}
}
}
}
}
//logTrace() << "Vertices and quads took " << timer.elapsedTimeInMilliSeconds();
//timer.start();
logTrace() << "Dual contouring surface extraction took " << totalTimer.elapsedTimeInMilliSeconds() << "ms (Region size = " << region.getWidthInVoxels() << "x" << region.getHeightInVoxels() << "x" << region.getDepthInVoxels() << ")";
logTrace() << mesh.getNoOfVertices();
return mesh;
}
}

View File

@ -0,0 +1,62 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2015 David Williams and Matthew Williams
*
* 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.
*******************************************************************************/
#ifndef __PolyVox_Exceptions_H__
#define __PolyVox_Exceptions_H__
#include <stdexcept> // For base exception classes.
#include <string> // Exception constuctors take strings.
// These exceptions form part of the public API because client code may need to catch them.
// Note that our utility macros such as 'POLYVOX_THROW_IF' do not form part of the public API
// as they are only for our own internal use.
namespace PolyVox
{
/// A general purpose exception to indicate that an operation cannot be peformed.
class invalid_operation : public std::logic_error
{
public:
explicit invalid_operation(const std::string& message)
: logic_error(message.c_str()) {}
explicit invalid_operation(const char *message)
: logic_error(message) {}
};
/// Thrown to indicate that a function is deliberatly not implmented. For example, perhaps you called a function
/// in a base class whereas you are supposed to use a derived class which implements the function, or perhaps the
/// function is not defined for a particular template parameter. It may be that the function is required to
/// compile sucessfully but it should not be called.
class not_implemented : public std::logic_error
{
public:
explicit not_implemented(const std::string& message)
: logic_error(message.c_str()) {}
explicit not_implemented(const char *message)
: logic_error(message) {}
};
}
#endif //__PolyVox_Exceptions_H__

View File

@ -1,33 +1,34 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_FilePager_H__ #ifndef __PolyVox_FilePager_H__
#define __PolyVox_FilePager_H__ #define __PolyVox_FilePager_H__
#include "PolyVox/Impl/TypeDef.h" #include "Impl/PlatformDefinitions.h"
#include "PolyVox/PagedVolume.h" #include "PagedVolume.h"
#include "PolyVox/Region.h" #include "Region.h"
#include <cstdlib> #include <cstdlib>
#include <ctime> #include <ctime>
@ -39,7 +40,12 @@ freely, subject to the following restrictions:
namespace PolyVox namespace PolyVox
{ {
/** /**
* Provides an interface for performing paging of data. * An implementation of Pager which stores voxels to files on disk. Each chunk is written
* to a seperate file and you can specify the name of a folder where these will be stored.
*
* Note that no compression is performed (mostly to avoid dependancies) so for large
* volumes you may want to consider this class as an example and create a custom version
* with compression.
*/ */
template <typename VoxelType> template <typename VoxelType>
class FilePager : public PagedVolume<VoxelType>::Pager class FilePager : public PagedVolume<VoxelType>::Pager
@ -48,7 +54,7 @@ namespace PolyVox
/// Constructor /// Constructor
FilePager(const std::string& strFolderName = ".") FilePager(const std::string& strFolderName = ".")
:PagedVolume<VoxelType>::Pager() :PagedVolume<VoxelType>::Pager()
,m_strFolderName(strFolderName) , m_strFolderName(strFolderName)
{ {
// Add the trailing slash, assuming the user dind't already do it. // Add the trailing slash, assuming the user dind't already do it.
if ((m_strFolderName.back() != '/') && (m_strFolderName.back() != '\\')) if ((m_strFolderName.back() != '/') && (m_strFolderName.back() != '\\'))
@ -56,21 +62,20 @@ namespace PolyVox
m_strFolderName.append("/"); m_strFolderName.append("/");
} }
// Build a unique prefix to avoid multiple pagers using the same filenames. // Build a unique postfix to avoid filename conflicts between multiple pagers/runs.
srand(static_cast<unsigned int>(time(0))); // Not a very robust solution but this class is meant as an example for testing really.
int iRandomValue = rand();
std::stringstream ss; std::stringstream ss;
ss << std::hex << iRandomValue; ss << time(0) << "--"; // Avoid multiple runs using the same filenames.
m_strRandomPrefix = ss.str(); ss << this; // Avoid multiple FilePagers using the same filenames.
m_strPostfix = ss.str();
} }
/// Destructor /// Destructor
virtual ~FilePager() virtual ~FilePager()
{ {
for(std::vector<std::string>::iterator iter = m_vecCreatedFiles.begin(); iter < m_vecCreatedFiles.end(); iter++) for (std::vector<std::string>::iterator iter = m_vecCreatedFiles.begin(); iter < m_vecCreatedFiles.end(); iter++)
{ {
POLYVOX_LOG_WARNING_IF(std::remove(iter->c_str()) != 0, "Failed to delete '" << *iter << "' when destroying FilePager"); POLYVOX_LOG_WARNING_IF(std::remove(iter->c_str()) != 0, "Failed to delete '", *iter, "' when destroying FilePager");
} }
m_vecCreatedFiles.clear(); m_vecCreatedFiles.clear();
@ -82,9 +87,10 @@ namespace PolyVox
POLYVOX_ASSERT(pChunk->getData(), "Chunk must have valid data"); POLYVOX_ASSERT(pChunk->getData(), "Chunk must have valid data");
std::stringstream ssFilename; std::stringstream ssFilename;
ssFilename << m_strFolderName << "/" << m_strRandomPrefix << "-" ssFilename << m_strFolderName << "/"
<< region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_" << region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_"
<< region.getUpperX() << "_" << region.getUpperY() << "_" << region.getUpperZ(); << region.getUpperX() << "_" << region.getUpperY() << "_" << region.getUpperZ()
<< "--" << m_strPostfix;
std::string filename = ssFilename.str(); std::string filename = ssFilename.str();
@ -92,9 +98,9 @@ namespace PolyVox
// the gameplay-cubiquity integration. See: https://github.com/blackberry/GamePlay/issues/919 // the gameplay-cubiquity integration. See: https://github.com/blackberry/GamePlay/issues/919
FILE* pFile = fopen(filename.c_str(), "rb"); FILE* pFile = fopen(filename.c_str(), "rb");
if(pFile) if (pFile)
{ {
POLYVOX_LOG_TRACE("Paging in data for " << region); POLYVOX_LOG_TRACE("Paging in data for ", region);
/*fseek(pFile, 0L, SEEK_END); /*fseek(pFile, 0L, SEEK_END);
size_t fileSizeInBytes = ftell(pFile); size_t fileSizeInBytes = ftell(pFile);
@ -107,7 +113,7 @@ namespace PolyVox
fread(pChunk->getData(), sizeof(uint8_t), pChunk->getDataSizeInBytes(), pFile); fread(pChunk->getData(), sizeof(uint8_t), pChunk->getDataSizeInBytes(), pFile);
if(ferror(pFile)) if (ferror(pFile))
{ {
POLYVOX_THROW(std::runtime_error, "Error reading in chunk data, even though a file exists."); POLYVOX_THROW(std::runtime_error, "Error reading in chunk data, even though a file exists.");
} }
@ -116,7 +122,12 @@ namespace PolyVox
} }
else else
{ {
POLYVOX_LOG_TRACE("No data found for " << region << " during paging in."); POLYVOX_LOG_TRACE("No data found for ", region, " during paging in.");
// Just fill with zeros. This feels hacky... perhaps we should just throw
// an exception and let the calling code handle it and fill with zeros.
uint32_t noOfVoxels = region.getWidthInVoxels() * region.getHeightInVoxels() * region.getDepthInVoxels();
std::fill(pChunk->getData(), pChunk->getData() + noOfVoxels, VoxelType());
} }
} }
@ -125,12 +136,13 @@ namespace PolyVox
POLYVOX_ASSERT(pChunk, "Attempting to page out NULL chunk"); POLYVOX_ASSERT(pChunk, "Attempting to page out NULL chunk");
POLYVOX_ASSERT(pChunk->getData(), "Chunk must have valid data"); POLYVOX_ASSERT(pChunk->getData(), "Chunk must have valid data");
POLYVOX_LOG_TRACE("Paging out data for " << region); POLYVOX_LOG_TRACE("Paging out data for ", region);
std::stringstream ssFilename; std::stringstream ssFilename;
ssFilename << m_strFolderName << "/" << m_strRandomPrefix << "-" ssFilename << m_strFolderName << "/"
<< region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_" << region.getLowerX() << "_" << region.getLowerY() << "_" << region.getLowerZ() << "_"
<< region.getUpperX() << "_" << region.getUpperY() << "_" << region.getUpperZ(); << region.getUpperX() << "_" << region.getUpperY() << "_" << region.getUpperZ()
<< "--" << m_strPostfix;
std::string filename = ssFilename.str(); std::string filename = ssFilename.str();
@ -138,7 +150,7 @@ namespace PolyVox
// the gameplay-cubiquity integration. See: https://github.com/blackberry/GamePlay/issues/919 // the gameplay-cubiquity integration. See: https://github.com/blackberry/GamePlay/issues/919
FILE* pFile = fopen(filename.c_str(), "wb"); FILE* pFile = fopen(filename.c_str(), "wb");
if(!pFile) if (!pFile)
{ {
POLYVOX_THROW(std::runtime_error, "Unable to open file to write out chunk data."); POLYVOX_THROW(std::runtime_error, "Unable to open file to write out chunk data.");
} }
@ -148,7 +160,7 @@ namespace PolyVox
fwrite(pChunk->getData(), sizeof(uint8_t), pChunk->getDataSizeInBytes(), pFile); fwrite(pChunk->getData(), sizeof(uint8_t), pChunk->getDataSizeInBytes(), pFile);
if(ferror(pFile)) if (ferror(pFile))
{ {
POLYVOX_THROW(std::runtime_error, "Error writing out chunk data."); POLYVOX_THROW(std::runtime_error, "Error writing out chunk data.");
} }
@ -158,7 +170,7 @@ namespace PolyVox
protected: protected:
std::string m_strFolderName; std::string m_strFolderName;
std::string m_strRandomPrefix; std::string m_strPostfix;
std::vector<std::string> m_vecCreatedFiles; std::vector<std::string> m_vecCreatedFiles;
}; };

View File

@ -1,64 +0,0 @@
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#ifndef __PolyVox_GradientEstimators_H__
#define __PolyVox_GradientEstimators_H__
#include "PolyVox/Vector.h"
#include "PolyVox/VoxelFilters.h"
#include <vector>
namespace PolyVox
{
enum NormalGenerationMethod
{
SIMPLE, ///<Fastest
CENTRAL_DIFFERENCE,
SOBEL,
CENTRAL_DIFFERENCE_SMOOTHED,
SOBEL_SMOOTHED ///<Smoothest
};
template<typename VolumeType>
Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter);
template<typename VolumeType>
Vector3DFloat computeSmoothCentralDifferenceGradient(typename VolumeType::Sampler& volIter);
template<typename VolumeType>
Vector3DFloat computeDecimatedCentralDifferenceGradient(typename VolumeType::Sampler& volIter);
template<typename VolumeType>
Vector3DFloat computeSobelGradient(const typename VolumeType::Sampler& volIter);
template<typename VolumeType>
Vector3DFloat computeSmoothSobelGradient(typename VolumeType::Sampler& volIter);
//POLYVOX_API void computeNormalsForVertices(VolumeType<uint8_t>* volumeData, Mesh<PositionMaterialNormal>& mesh, NormalGenerationMethod normalGenerationMethod);
//POLYVOX_API Vector3DFloat computeNormal(VolumeType<uint8_t>* volumeData, const Vector3DFloat& v3dPos, NormalGenerationMethod normalGenerationMethod);
}
#include "PolyVox/GradientEstimators.inl"
#endif //__PolyVox_GradientEstimators_H__

View File

@ -1,302 +0,0 @@
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
namespace PolyVox
{
template<typename VolumeType>
Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter)
{
//FIXME - bitwise way of doing this?
typename VolumeType::VoxelType voxel1nx = volIter.peekVoxel1nx0py0pz() > 0 ? 1: 0;
typename VolumeType::VoxelType voxel1px = volIter.peekVoxel1px0py0pz() > 0 ? 1: 0;
typename VolumeType::VoxelType voxel1ny = volIter.peekVoxel0px1ny0pz() > 0 ? 1: 0;
typename VolumeType::VoxelType voxel1py = volIter.peekVoxel0px1py0pz() > 0 ? 1: 0;
typename VolumeType::VoxelType voxel1nz = volIter.peekVoxel0px0py1nz() > 0 ? 1: 0;
typename VolumeType::VoxelType voxel1pz = volIter.peekVoxel0px0py1pz() > 0 ? 1: 0;
return Vector3DFloat
(
static_cast<float>(voxel1nx) - static_cast<float>(voxel1px),
static_cast<float>(voxel1ny) - static_cast<float>(voxel1py),
static_cast<float>(voxel1nz) - static_cast<float>(voxel1pz)
);
}
template<typename VolumeType>
Vector3DFloat computeDecimatedCentralDifferenceGradient(const typename VolumeType::Sampler& volIter)
{
const int32_t x = volIter.getPosition().getX();
const int32_t y = volIter.getPosition().getY();
const int32_t z = volIter.getPosition().getZ();
//FIXME - bitwise way of doing this?
typename VolumeType::VoxelType voxel1nx = volIter.getVoxel(x-2, y ,z ) > 0 ? 1: 0;
typename VolumeType::VoxelType voxel1px = volIter.getVoxel(x-2, y ,z ) > 0 ? 1: 0;
typename VolumeType::VoxelType voxel1ny = volIter.getVoxel(x , y-2,z ) > 0 ? 1: 0;
typename VolumeType::VoxelType voxel1py = volIter.getVoxel(x , y-2,z ) > 0 ? 1: 0;
typename VolumeType::VoxelType voxel1nz = volIter.getVoxel(x , y ,z-2) > 0 ? 1: 0;
typename VolumeType::VoxelType voxel1pz = volIter.getVoxel(x , y ,z-2) > 0 ? 1: 0;
return Vector3DFloat
(
static_cast<float>(voxel1nx) - static_cast<float>(voxel1px),
static_cast<float>(voxel1ny) - static_cast<float>(voxel1py),
static_cast<float>(voxel1nz) - static_cast<float>(voxel1pz)
);
}
template<typename VolumeType>
Vector3DFloat computeSmoothCentralDifferenceGradient(typename VolumeType::Sampler& volIter)
{
int32_t initialX = volIter.getPosition().getX();
int32_t initialY = volIter.getPosition().getY();
int32_t initialZ = volIter.getPosition().getZ();
//FIXME - bitwise way of doing this?
volIter.setPosition(initialX-1, initialY, initialZ);
float voxel1nx = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX+1, initialY, initialZ);
float voxel1px = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX, initialY-1, initialZ);
float voxel1ny = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX, initialY+1, initialZ);
float voxel1py = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX, initialY, initialZ-1);
float voxel1nz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX, initialY, initialZ+1);
float voxel1pz = computeSmoothedVoxel(volIter);
return Vector3DFloat
(
voxel1nx - voxel1px,
voxel1ny - voxel1py,
voxel1nz - voxel1pz
);
}
template<typename VolumeType>
Vector3DFloat computeSobelGradient(const typename VolumeType::Sampler& volIter)
{
static const int weights[3][3][3] = { { {2,3,2}, {3,6,3}, {2,3,2} }, {
{3,6,3}, {6,0,6}, {3,6,3} }, { {2,3,2}, {3,6,3}, {2,3,2} } };
const typename VolumeType::VoxelType pVoxel1nx1ny1nz = volIter.peekVoxel1nx1ny1nz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1nx1ny0pz = volIter.peekVoxel1nx1ny0pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1nx1ny1pz = volIter.peekVoxel1nx1ny1pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1nx0py1nz = volIter.peekVoxel1nx0py1nz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1nx0py0pz = volIter.peekVoxel1nx0py0pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1nx0py1pz = volIter.peekVoxel1nx0py1pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1nx1py1nz = volIter.peekVoxel1nx1py1nz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1nx1py0pz = volIter.peekVoxel1nx1py0pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1nx1py1pz = volIter.peekVoxel1nx1py1pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel0px1ny1nz = volIter.peekVoxel0px1ny1nz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel0px1ny0pz = volIter.peekVoxel0px1ny0pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel0px1ny1pz = volIter.peekVoxel0px1ny1pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel0px0py1nz = volIter.peekVoxel0px0py1nz() > 0 ? 1: 0;
//const VolumeType::VoxelType pVoxel0px0py0pz = volIter.peekVoxel0px0py0pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel0px0py1pz = volIter.peekVoxel0px0py1pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel0px1py1nz = volIter.peekVoxel0px1py1nz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel0px1py0pz = volIter.peekVoxel0px1py0pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel0px1py1pz = volIter.peekVoxel0px1py1pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1px1ny1nz = volIter.peekVoxel1px1ny1nz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1px1ny0pz = volIter.peekVoxel1px1ny0pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1px1ny1pz = volIter.peekVoxel1px1ny1pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1px0py1nz = volIter.peekVoxel1px0py1nz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1px0py0pz = volIter.peekVoxel1px0py0pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1px0py1pz = volIter.peekVoxel1px0py1pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1px1py1nz = volIter.peekVoxel1px1py1nz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1px1py0pz = volIter.peekVoxel1px1py0pz() > 0 ? 1: 0;
const typename VolumeType::VoxelType pVoxel1px1py1pz = volIter.peekVoxel1px1py1pz() > 0 ? 1: 0;
const int xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz -
weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] *
pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz -
weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] *
pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz +
weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] *
pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz +
weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] *
pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz +
weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
pVoxel1px1py1pz);
const int yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz +
weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] *
pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz -
weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] *
pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz +
weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] *
pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz -
weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] *
pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz +
weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
pVoxel1px1py1pz);
const int zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz +
weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] *
pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz -
weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] *
pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz +
weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] *
pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz -
weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] *
pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz +
weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] *
pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz -
weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] *
pVoxel1px1py1pz);
//Note: The above actually give gradients going from low density to high density.
//For our normals we want the the other way around, so we switch the components as we return them.
return Vector3DFloat(static_cast<float>(-xGrad),static_cast<float>(-yGrad),static_cast<float>(-zGrad));
}
template<typename VolumeType>
Vector3DFloat computeSmoothSobelGradient(typename VolumeType::Sampler& volIter)
{
static const int weights[3][3][3] = { { {2,3,2}, {3,6,3}, {2,3,2} }, {
{3,6,3}, {6,0,6}, {3,6,3} }, { {2,3,2}, {3,6,3}, {2,3,2} } };
int32_t initialX = volIter.getPosition().getX();
int32_t initialY = volIter.getPosition().getY();
int32_t initialZ = volIter.getPosition().getZ();
volIter.setPosition(initialX-1, initialY-1, initialZ-1); const float pVoxel1nx1ny1nz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX-1, initialY-1, initialZ ); const float pVoxel1nx1ny0pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX-1, initialY-1, initialZ+1); const float pVoxel1nx1ny1pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX-1, initialY , initialZ-1); const float pVoxel1nx0py1nz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX-1, initialY , initialZ ); const float pVoxel1nx0py0pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX-1, initialY , initialZ+1); const float pVoxel1nx0py1pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX-1, initialY+1, initialZ-1); const float pVoxel1nx1py1nz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX-1, initialY+1, initialZ ); const float pVoxel1nx1py0pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX-1, initialY+1, initialZ+1); const float pVoxel1nx1py1pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX , initialY-1, initialZ-1); const float pVoxel0px1ny1nz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX , initialY-1, initialZ ); const float pVoxel0px1ny0pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX , initialY-1, initialZ+1); const float pVoxel0px1ny1pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX , initialY , initialZ-1); const float pVoxel0px0py1nz = computeSmoothedVoxel(volIter);
//volIter.setPosition(initialX , initialY , initialZ ); const float pVoxel0px0py0pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX , initialY , initialZ+1); const float pVoxel0px0py1pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX , initialY+1, initialZ-1); const float pVoxel0px1py1nz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX , initialY+1, initialZ ); const float pVoxel0px1py0pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX , initialY+1, initialZ+1); const float pVoxel0px1py1pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX+1, initialY-1, initialZ-1); const float pVoxel1px1ny1nz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX+1, initialY-1, initialZ ); const float pVoxel1px1ny0pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX+1, initialY-1, initialZ+1); const float pVoxel1px1ny1pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX+1, initialY , initialZ-1); const float pVoxel1px0py1nz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX+1, initialY , initialZ ); const float pVoxel1px0py0pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX+1, initialY , initialZ+1); const float pVoxel1px0py1pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX+1, initialY+1, initialZ-1); const float pVoxel1px1py1nz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX+1, initialY+1, initialZ ); const float pVoxel1px1py0pz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX+1, initialY+1, initialZ+1); const float pVoxel1px1py1pz = computeSmoothedVoxel(volIter);
/*const VoxelType pVoxel1nx1ny1nz = volIter.peekVoxel1nx1ny1nz() > 0 ? 1: 0;
const VoxelType pVoxel1nx1ny0pz = volIter.peekVoxel1nx1ny0pz() > 0 ? 1: 0;
const VoxelType pVoxel1nx1ny1pz = volIter.peekVoxel1nx1ny1pz() > 0 ? 1: 0;
const VoxelType pVoxel1nx0py1nz = volIter.peekVoxel1nx0py1nz() > 0 ? 1: 0;
const VoxelType pVoxel1nx0py0pz = volIter.peekVoxel1nx0py0pz() > 0 ? 1: 0;
const VoxelType pVoxel1nx0py1pz = volIter.peekVoxel1nx0py1pz() > 0 ? 1: 0;
const VoxelType pVoxel1nx1py1nz = volIter.peekVoxel1nx1py1nz() > 0 ? 1: 0;
const VoxelType pVoxel1nx1py0pz = volIter.peekVoxel1nx1py0pz() > 0 ? 1: 0;
const VoxelType pVoxel1nx1py1pz = volIter.peekVoxel1nx1py1pz() > 0 ? 1: 0;
const VoxelType pVoxel0px1ny1nz = volIter.peekVoxel0px1ny1nz() > 0 ? 1: 0;
const VoxelType pVoxel0px1ny0pz = volIter.peekVoxel0px1ny0pz() > 0 ? 1: 0;
const VoxelType pVoxel0px1ny1pz = volIter.peekVoxel0px1ny1pz() > 0 ? 1: 0;
const VoxelType pVoxel0px0py1nz = volIter.peekVoxel0px0py1nz() > 0 ? 1: 0;
//const VoxelType pVoxel0px0py0pz = volIter.peekVoxel0px0py0pz() > 0 ? 1: 0;
const VoxelType pVoxel0px0py1pz = volIter.peekVoxel0px0py1pz() > 0 ? 1: 0;
const VoxelType pVoxel0px1py1nz = volIter.peekVoxel0px1py1nz() > 0 ? 1: 0;
const VoxelType pVoxel0px1py0pz = volIter.peekVoxel0px1py0pz() > 0 ? 1: 0;
const VoxelType pVoxel0px1py1pz = volIter.peekVoxel0px1py1pz() > 0 ? 1: 0;
const VoxelType pVoxel1px1ny1nz = volIter.peekVoxel1px1ny1nz() > 0 ? 1: 0;
const VoxelType pVoxel1px1ny0pz = volIter.peekVoxel1px1ny0pz() > 0 ? 1: 0;
const VoxelType pVoxel1px1ny1pz = volIter.peekVoxel1px1ny1pz() > 0 ? 1: 0;
const VoxelType pVoxel1px0py1nz = volIter.peekVoxel1px0py1nz() > 0 ? 1: 0;
const VoxelType pVoxel1px0py0pz = volIter.peekVoxel1px0py0pz() > 0 ? 1: 0;
const VoxelType pVoxel1px0py1pz = volIter.peekVoxel1px0py1pz() > 0 ? 1: 0;
const VoxelType pVoxel1px1py1nz = volIter.peekVoxel1px1py1nz() > 0 ? 1: 0;
const VoxelType pVoxel1px1py0pz = volIter.peekVoxel1px1py0pz() > 0 ? 1: 0;
const VoxelType pVoxel1px1py1pz = volIter.peekVoxel1px1py1pz() > 0 ? 1: 0;*/
const float xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz -
weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] *
pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz -
weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] *
pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz +
weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] *
pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz +
weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] *
pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz +
weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
pVoxel1px1py1pz);
const float yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz +
weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] *
pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz -
weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] *
pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz +
weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] *
pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz -
weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] *
pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz +
weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
pVoxel1px1py1pz);
const float zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz +
weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] *
pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz -
weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] *
pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz +
weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] *
pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz -
weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] *
pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz +
weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] *
pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz -
weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] *
pVoxel1px1py1pz);
//Note: The above actually give gradients going from low density to high density.
//For our normals we want the the other way around, so we switch the components as we return them.
return Vector3DFloat(-xGrad,-yGrad,-zGrad);
}
}

View File

@ -1,30 +1,31 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_AStarPathfinderImpl_H__ #ifndef __PolyVox_AStarPathfinderImpl_H__
#define __PolyVox_AStarPathfinderImpl_H__ #define __PolyVox_AStarPathfinderImpl_H__
#include "PolyVox/Vector.h" #include "../Vector.h"
#include <algorithm> #include <algorithm>
#include <limits> //For numeric_limits #include <limits> //For numeric_limits
@ -35,7 +36,6 @@ namespace PolyVox
{ {
class OpenNodesContainer; class OpenNodesContainer;
class ClosedNodesContainer; class ClosedNodesContainer;
class ThermiteGameLogic;
/// The Connectivity of a voxel determines how many neighbours it has. /// The Connectivity of a voxel determines how many neighbours it has.
enum Connectivity enum Connectivity
@ -52,8 +52,8 @@ namespace PolyVox
{ {
Node(int x, int y, int z) Node(int x, int y, int z)
:gVal(std::numeric_limits<float>::quiet_NaN()) //Initilise with NaNs so that we will :gVal(std::numeric_limits<float>::quiet_NaN()) //Initilise with NaNs so that we will
,hVal(std::numeric_limits<float>::quiet_NaN()) //know if we forget to set these properly. , hVal(std::numeric_limits<float>::quiet_NaN()) //know if we forget to set these properly.
,parent(0) , parent(0)
{ {
position.setX(x); position.setX(x);
position.setY(y); position.setY(y);

View File

@ -0,0 +1,76 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2015 David Williams and Matthew Williams
*
* 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.
*******************************************************************************/
#ifndef __PolyVox_Assertions_H__
#define __PolyVox_Assertions_H__
#include "../Config.h"
#include "LoggingImpl.h" // Asserts can log when they fire.
#include "PlatformDefinitions.h"
// The code below implements a custom assert function called POLYVOX_ASSERT which has a number of advantages compared
// to the standard C/C++ assert(). It is inspired by http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
// which provides code under the MIT license.
#ifdef POLYVOX_ASSERTS_ENABLED
#define POLYVOX_ASSERT(condition, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if (!(condition)) \
{ \
std::stringstream ss; \
ss << "\n"; \
ss << " PolyVox Assertion Failed!"; \
ss << " ========================="; \
ss << " Condition: " << #condition; \
ss << " Message: " << (message); \
ss << " Location: " << "Line " << __LINE__ << " of " << __FILE__; \
ss << "\n"; \
PolyVox::getLoggerInstance()->logFatalMessage(ss.str()); \
POLYVOX_HALT(); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#else
#define POLYVOX_ASSERT(condition, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do { POLYVOX_UNUSED(condition); POLYVOX_UNUSED(message); } while(0) \
POLYVOX_MSC_WARNING_POP
#endif
#endif //__PolyVox_Assertions_H__

View File

@ -1,37 +0,0 @@
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#ifndef __PolyVox_Config_H__
#define __PolyVox_Config_H__
//#define POLYVOX_LOG_TRACE_ENABLED
#define POLYVOX_LOG_DEBUG_ENABLED
#define POLYVOX_LOG_INFO_ENABLED
#define POLYVOX_LOG_WARNING_ENABLED
#define POLYVOX_LOG_ERROR_ENABLED
#define POLYVOX_LOG_FATAL_ENABLED
#define POLYVOX_ASSERTS_ENABLED
#define POLYVOX_THROW_ENABLED
#endif

View File

@ -1,268 +1,33 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
// This file provides a simple way to include all error-handling functionality.
#ifndef __PolyVox_ErrorHandling_H__ #ifndef __PolyVox_ErrorHandling_H__
#define __PolyVox_ErrorHandling_H__ #define __PolyVox_ErrorHandling_H__
#include "PolyVox/Impl/Config.h" #include "Assertions.h"
#include "ExceptionsImpl.h"
#include "PolyVox/Impl/Logging.h" #include "LoggingImpl.h"
#include <cstdlib> // For std::exit
#include <iostream> // For std::cerr
#include <stdexcept>
#include <sstream>
#include <string.h> // Exception constuctors take strings.
#include <csignal>
#if defined(_MSC_VER)
// In Visual Studio we can use this function to go into the debugger.
#define POLYVOX_HALT() __debugbreak()
#else
// On other platforms we just halt by forcing a crash.
// Hopefully this puts us in the debugger if one is running
#if defined(__linux__) || defined(__APPLE__)
#define POLYVOX_HALT() raise(SIGTRAP)
#else
#define POLYVOX_HALT() *((unsigned int*)0) = 0xDEAD
#endif
#endif
// Macros cannot contain #ifdefs, but some of our macros need to disable warnings and such warning supression is
// platform specific. But macros can contain other macros, so we create macros to control the warnings and use
// those instead. This set of warning supression macros can be extended to GCC/Clang when required.
#if defined(_MSC_VER)
#define POLYVOX_MSC_WARNING_PUSH __pragma(warning(push))
#define POLYVOX_DISABLE_MSC_WARNING(x) __pragma(warning(disable:x))
#define POLYVOX_MSC_WARNING_POP __pragma(warning(pop))
#else
#define POLYVOX_MSC_WARNING_PUSH
#define POLYVOX_DISABLE_MSC_WARNING(x)
#define POLYVOX_MSC_WARNING_POP
#endif
#define POLYVOX_UNUSED(x) do { (void)sizeof(x); } while(0)
/*
* Assertions
* ----------
* The code below implements a custom assert function called POLYVOX_ASSERT which has a number of advantages compared
* to the standard C/C++ assert(). It is inspired by http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
* which provides code under the MIT license.
*/
#ifdef POLYVOX_ASSERTS_ENABLED
#define POLYVOX_ASSERT(condition, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if (!(condition)) \
{ \
std::stringstream ss; \
ss << "\n"; \
ss << " PolyVox Assertion Failed!"; \
ss << " ========================="; \
ss << " Condition: " << #condition; \
ss << " Message: " << (message); \
ss << " Location: " << "Line " << __LINE__ << " of " << __FILE__; \
ss << "\n"; \
PolyVox::Impl::getLoggerInstance()->logFatalMessage(ss.str()); \
POLYVOX_HALT(); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#else
#define POLYVOX_ASSERT(condition, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do { POLYVOX_UNUSED(condition); POLYVOX_UNUSED(message); } while(0) \
POLYVOX_MSC_WARNING_POP
#endif
/*
* Exceptions
* ----------
* ...
*/
#ifdef POLYVOX_THROW_ENABLED
#define POLYVOX_THROW_IF(condition, type, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if ((condition)) \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
throw type(ss.str()); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#define POLYVOX_THROW(type, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
throw type(ss.str()); \
} while(0) \
POLYVOX_MSC_WARNING_POP
#else
namespace PolyVox
{
typedef void (*ThrowHandler)(std::exception& e, const char* file, int line);
inline void defaultThrowHandler(std::exception& e, const char* file, int line)
{
std::stringstream ss; \
ss << "\n"; \
ss << " PolyVox exception thrown!"; \
ss << " ========================="; \
ss << " PolyVox has tried to throw an exception but it was built without support"; \
ss << " for exceptions. In this scenario PolyVox will call a 'throw handler'"; \
ss << " and this message is being printed by the default throw handler."; \
ss << "\n"; \
ss << " If you don't want to enable exceptions then you should try to determine why"; \
ss << " this exception was thrown and make sure it doesn't happen again. If it was"; \
ss << " due to something like an invalid argument to a function then you should be"; \
ss << " able to fix it quite easily by validating parameters as appropriate. More"; \
ss << " complex exception scenarios (out of memory, etc) might be harder to fix and"; \
ss << " you should replace this default handler with something which is more"; \
ss << " meaningful to your users."; \
ss << "\n"; \
ss << " Exception details"; \
ss << " -----------------"; \
ss << " Line: " << line; \
ss << " File: " << file; \
ss << " Message: " << e.what(); \
ss << "\n"; \
PolyVox::Impl::getLoggerInstance()->logFatalMessage(ss.str()); \
POLYVOX_HALT(); \
}
inline ThrowHandler& getThrowHandlerInstance()
{
static ThrowHandler s_fThrowHandler = &defaultThrowHandler;
return s_fThrowHandler;
}
inline ThrowHandler getThrowHandler()
{
return getThrowHandlerInstance();
}
inline void setThrowHandler(ThrowHandler fNewHandler)
{
getThrowHandlerInstance() = fNewHandler;
}
}
#define POLYVOX_THROW_IF(condition, type, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if ((condition)) \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
type except = (type)(ss.str()); \
getThrowHandler()((except), __FILE__, __LINE__); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#define POLYVOX_THROW(type, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
type except = (type)(ss.str()); \
getThrowHandler()((except), __FILE__, __LINE__); \
} while(0) \
POLYVOX_MSC_WARNING_POP
#endif
namespace PolyVox
{
/// A general purpose exception to indicate that an operation cannot be peformed.
class invalid_operation : public std::logic_error
{
public:
explicit invalid_operation(const std::string& message)
: logic_error(message.c_str()) {}
explicit invalid_operation(const char *message)
: logic_error(message) {}
};
/// Thrown to indicate that a function is deliberatly not implmented. For example, perhaps you called a function
/// in a base class whereas you are supposed to use a derived class which implements the function, or perhaps the
/// function is not defined for a particular template parameter. It may be that the function is required to
/// compile sucessfully but it should not be called.
class not_implemented : public std::logic_error
{
public:
explicit not_implemented(const std::string& message)
: logic_error(message.c_str()) {}
explicit not_implemented(const char *message)
: logic_error(message) {}
};
}
#endif //__PolyVox_ErrorHandling_H__ #endif //__PolyVox_ErrorHandling_H__

View File

@ -0,0 +1,155 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2015 David Williams and Matthew Williams
*
* 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.
*******************************************************************************/
#ifndef __PolyVox_ExceptionsImpl_H__
#define __PolyVox_ExceptionsImpl_H__
#include "../Config.h"
#include "../Exceptions.h"
#include "LoggingImpl.h" // Exceptions can log when they are thrown.
#include <cstdlib> // For std::exit
#include <iostream> // For std::cerr
#include <sstream>
#include <csignal>
#ifdef POLYVOX_THROW_ENABLED
namespace PolyVox
{
namespace Impl
{
template< typename ExceptionType, typename ... Args >
void polyvox_throw(Args const& ... messageArgs)
{
std::string message = argListToString(messageArgs...);
#ifdef POLYVOX_LOG_ERROR_ENABLED
getLoggerInstance()->logErrorMessage(message);
#endif
throw ExceptionType(message);
}
template< typename ExceptionType, typename ... Args >
void polyvox_throw_if(bool condition, Args const& ... messageArgs)
{
if (condition) { polyvox_throw<ExceptionType>(messageArgs...); }
}
}
}
#define POLYVOX_THROW(type, ...) PolyVox::Impl::polyvox_throw<type>(__VA_ARGS__)
#define POLYVOX_THROW_IF(condition, type, ...) PolyVox::Impl::polyvox_throw_if<type>(condition, __VA_ARGS__)
#else
// This stuff should possibly be in the 'Impl' namespace, but it may be complex and it's not
// clear if this ability to disable throwing of exceptions is useful in the long term anyway.
namespace PolyVox
{
typedef void(*ThrowHandler)(std::exception& e, const char* file, int line);
inline void defaultThrowHandler(std::exception& e, const char* file, int line)
{
std::stringstream ss; \
ss << "\n"; \
ss << " PolyVox exception thrown!"; \
ss << " ========================="; \
ss << " PolyVox has tried to throw an exception but it was built without support"; \
ss << " for exceptions. In this scenario PolyVox will call a 'throw handler'"; \
ss << " and this message is being printed by the default throw handler."; \
ss << "\n"; \
ss << " If you don't want to enable exceptions then you should try to determine why"; \
ss << " this exception was thrown and make sure it doesn't happen again. If it was"; \
ss << " due to something like an invalid argument to a function then you should be"; \
ss << " able to fix it quite easily by validating parameters as appropriate. More"; \
ss << " complex exception scenarios (out of memory, etc) might be harder to fix and"; \
ss << " you should replace this default handler with something which is more"; \
ss << " meaningful to your users."; \
ss << "\n"; \
ss << " Exception details"; \
ss << " -----------------"; \
ss << " Line: " << line; \
ss << " File: " << file; \
ss << " Message: " << e.what(); \
ss << "\n"; \
PolyVox::Impl::getLoggerInstance()->logFatalMessage(ss.str()); \
POLYVOX_HALT(); \
}
inline ThrowHandler& getThrowHandlerInstance()
{
static ThrowHandler s_fThrowHandler = &defaultThrowHandler;
return s_fThrowHandler;
}
inline ThrowHandler getThrowHandler()
{
return getThrowHandlerInstance();
}
inline void setThrowHandler(ThrowHandler fNewHandler)
{
getThrowHandlerInstance() = fNewHandler;
}
}
#define POLYVOX_THROW_IF(condition, type, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if ((condition)) \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
type except = (type)(ss.str()); \
getThrowHandler()((except), __FILE__, __LINE__); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#define POLYVOX_THROW(type, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
type except = (type)(ss.str()); \
getThrowHandler()((except), __FILE__, __LINE__); \
} while(0) \
POLYVOX_MSC_WARNING_POP
#endif
#endif //__PolyVox_ExceptionsImpl_H__

View File

@ -0,0 +1,73 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2015 David Williams and Matthew Williams
*
* 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.
*******************************************************************************/
#ifndef __PolyVox_Interpolation_H__
#define __PolyVox_Interpolation_H__
namespace PolyVox
{
template <typename Type>
Type lerp(
const Type& v0, const Type& v1,
const float x)
{
//Interpolate along X
Type v0_1 = (v1 - v0) * x + v0;
return v0_1;
}
template <typename Type>
Type bilerp(
const Type& v00, const Type& v10, const Type& v01, const Type& v11,
const float x, const float y)
{
// Linearly interpolate along x
Type v00_10 = lerp(v00, v10, x);
Type v01_11 = lerp(v01, v11, x);
// And linearly interpolate the results along y
Type v00_10__v01_11 = lerp(v00_10, v01_11, y);
return v00_10__v01_11;
}
template <typename Type>
Type trilerp(
const Type& v000, const Type& v100, const Type& v010, const Type& v110,
const Type& v001, const Type& v101, const Type& v011, const Type& v111,
const float x, const float y, const float z)
{
// Bilinearly interpolate along Y
Type v000_v100__v010_v110 = bilerp(v000, v100, v010, v110, x, y);
Type v001_v101__v011_v111 = bilerp(v001, v101, v011, v111, x, y);
// And linearly interpolate the results along z
Type v000_v100__v010_v110____v001_v101__v011_v111 = lerp(v000_v100__v010_v110, v001_v101__v011_v111, z);
return v000_v100__v010_v110____v001_v101__v011_v111;
}
}
#endif //__PolyVox_Interpolation_H__

View File

@ -0,0 +1,48 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2015 David Williams and Matthew Williams
*
* 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.
*******************************************************************************/
#ifndef __PolyVox_IteratorController_H__
#define __PolyVox_IteratorController_H__
#include "../Region.h"
namespace PolyVox
{
/// Unfinished class/feature, not appropriate for end user at the moment.
template <typename IteratorType>
class IteratorController
{
public:
void reset(void);
bool moveForward(void);
public:
Region m_regValid;
IteratorType* m_Iter;
};
}
#include "IteratorController.inl"
#endif //__PolyVox_IteratorController_H__

View File

@ -0,0 +1,64 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2015 David Williams and Matthew Williams
*
* 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.
*******************************************************************************/
namespace PolyVox
{
template <typename IteratorType>
void IteratorController<IteratorType>::reset(void)
{
m_Iter->setPosition(m_regValid.getLowerCorner());
}
template <typename IteratorType>
bool IteratorController<IteratorType>::moveForward(void)
{
Vector3DInt32 v3dInitialPosition(m_Iter->getPosition().getX(), m_Iter->getPosition().getY(), m_Iter->getPosition().getZ());
if (v3dInitialPosition.getX() < m_regValid.getUpperX())
{
m_Iter->movePositiveX();
return true;
}
v3dInitialPosition.setX(m_regValid.getLowerX());
if (v3dInitialPosition.getY() < m_regValid.getUpperY())
{
v3dInitialPosition.setY(v3dInitialPosition.getY() + 1);
m_Iter->setPosition(v3dInitialPosition);
return true;
}
v3dInitialPosition.setY(m_regValid.getLowerY());
if (v3dInitialPosition.getZ() < m_regValid.getUpperZ())
{
v3dInitialPosition.setZ(v3dInitialPosition.getZ() + 1);
m_Iter->setPosition(v3dInitialPosition);
return true;
}
return false;
}
}

View File

@ -1,350 +0,0 @@
/*******************************************************************************
Copyright (c) 2005-2009 David Williams and Matthew Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#ifndef __PolyVox_Logging_H__
#define __PolyVox_Logging_H__
#include "PolyVox/Impl/Config.h"
#include <iostream>
#include <sstream>
/*
* Logging
* --------
* PolyVox provides basic logging facilities which can be redirected by your application.
*/
namespace PolyVox
{
class Logger
{
public:
// Passing zero to the null stream constructor guarentees it will discard all input. See
// here http://stackoverflow.com/a/8244052 and here http://stackoverflow.com/a/6240980
Logger() {};
virtual ~Logger() {};
virtual void logTraceMessage(const std::string& message) = 0;
virtual void logDebugMessage(const std::string& message) = 0;
virtual void logInfoMessage(const std::string& message) = 0;
virtual void logWarningMessage(const std::string& message) = 0;
virtual void logErrorMessage(const std::string& message) = 0;
virtual void logFatalMessage(const std::string& message) = 0;
};
class DefaultLogger : public Logger
{
public:
DefaultLogger() : Logger() {}
virtual ~DefaultLogger() {}
// Appending the 'std::endl' forces the stream to be flushed.
void logTraceMessage(const std::string& /*message*/) { }
void logDebugMessage(const std::string& /*message*/) { }
void logInfoMessage(const std::string& message) { std::cout << message << std::endl; }
void logWarningMessage(const std::string& message) { std::cerr << message << std::endl; }
void logErrorMessage(const std::string& message) { std::cerr << message << std::endl; }
void logFatalMessage(const std::string& message) { std::cerr << message << std::endl; }
};
namespace Impl
{
inline Logger*& getLoggerInstance()
{
static Logger* s_pLogger = new DefaultLogger;
return s_pLogger;
}
}
inline void setLogger(Logger* pLogger)
{
Impl::getLoggerInstance() = pLogger;
}
}
#ifdef POLYVOX_LOG_TRACE_ENABLED
#define POLYVOX_LOG_TRACE(message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logTraceMessage(ss.str()); \
} while(0) \
POLYVOX_MSC_WARNING_POP
#define POLYVOX_LOG_TRACE_IF(condition, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if ((condition)) \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logTraceMessage(ss.str()); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#else
// We don't bother with the do...while(0) construct here as we're not executing multiple statements
// We also don't bother with forcing variables to be 'used'. If this causes a problem then calling
// code can just force them to be used itself in addition to calling the logging macro. Basically
// we just want to reduce the chance of extra code being generated.
#define POLYVOX_LOG_TRACE(message)
#define POLYVOX_LOG_TRACE_IF(condition, message)
#endif
#ifdef POLYVOX_LOG_DEBUG_ENABLED
#define POLYVOX_LOG_DEBUG(message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logDebugMessage(ss.str()); \
} while(0) \
POLYVOX_MSC_WARNING_POP
#define POLYVOX_LOG_DEBUG_IF(condition, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if ((condition)) \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logDebugMessage(ss.str()); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#else
// We don't bother with the do...while(0) construct here as we're not executing multiple statements
// We also don't bother with forcing variables to be 'used'. If this causes a problem then calling
// code can just force them to be used itself in addition to calling the logging macro. Basically
// we just want to reduce the chance of extra code being generated.
#define POLYVOX_LOG_DEBUG(message)
#define POLYVOX_LOG_DEBUG_IF(condition, message)
#endif
#ifdef POLYVOX_LOG_INFO_ENABLED
#define POLYVOX_LOG_INFO(message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logInfoMessage(ss.str()); \
} while(0) \
POLYVOX_MSC_WARNING_POP
#define POLYVOX_LOG_INFO_IF(condition, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if ((condition)) \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logInfoMessage(ss.str()); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#else
// We don't bother with the do...while(0) construct here as we're not executing multiple statements
// We also don't bother with forcing variables to be 'used'. If this causes a problem then calling
// code can just force them to be used itself in addition to calling the logging macro. Basically
// we just want to reduce the chance of extra code being generated.
#define POLYVOX_LOG_INFO(message)
#define POLYVOX_LOG_INFO_IF(condition, message)
#endif
#ifdef POLYVOX_LOG_WARNING_ENABLED
#define POLYVOX_LOG_WARNING(message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logWarningMessage(ss.str()); \
} while(0) \
POLYVOX_MSC_WARNING_POP
#define POLYVOX_LOG_WARNING_IF(condition, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if ((condition)) \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logWarningMessage(ss.str()); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#else
// We don't bother with the do...while(0) construct here as we're not executing multiple statements
// We also don't bother with forcing variables to be 'used'. If this causes a problem then calling
// code can just force them to be used itself in addition to calling the logging macro. Basically
// we just want to reduce the chance of extra code being generated.
#define POLYVOX_LOG_WARNING(message)
#define POLYVOX_LOG_WARNING_IF(condition, message)
#endif
#ifdef POLYVOX_LOG_ERROR_ENABLED
#define POLYVOX_LOG_ERROR(message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
} while(0) \
POLYVOX_MSC_WARNING_POP
#define POLYVOX_LOG_ERROR_IF(condition, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if ((condition)) \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logErrorMessage(ss.str()); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#else
// We don't bother with the do...while(0) construct here as we're not executing multiple statements
// We also don't bother with forcing variables to be 'used'. If this causes a problem then calling
// code can just force them to be used itself in addition to calling the logging macro. Basically
// we just want to reduce the chance of extra code being generated.
#define POLYVOX_LOG_ERROR(message)
#define POLYVOX_LOG_ERROR_IF(condition, message)
#endif
#ifdef POLYVOX_LOG_FATAL_ENABLED
#define POLYVOX_LOG_FATAL(message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logFatalMessage(ss.str()); \
} while(0) \
POLYVOX_MSC_WARNING_POP
#define POLYVOX_LOG_FATAL_IF(condition, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if ((condition)) \
{ \
std::stringstream ss; \
ss << message; \
PolyVox::Impl::getLoggerInstance()->logFatalMessage(ss.str()); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#else
// We don't bother with the do...while(0) construct here as we're not executing multiple statements
// We also don't bother with forcing variables to be 'used'. If this causes a problem then calling
// code can just force them to be used itself in addition to calling the logging macro. Basically
// we just want to reduce the chance of extra code being generated.
#define POLYVOX_LOG_FATAL(message)
#define POLYVOX_LOG_FATAL_IF(condition, message)
#endif
#endif //__PolyVox_Logging_H__

View File

@ -0,0 +1,182 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2015 David Williams and Matthew Williams
*
* 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.
*******************************************************************************/
#ifndef __PolyVox_LoggingImpl_H__
#define __PolyVox_LoggingImpl_H__
#include "../Config.h"
#include "../Logging.h"
#include <sstream>
namespace PolyVox
{
namespace Impl
{
// Used for building the log messages - convert a list of variables into a string.
// Based on second approach here: http://stackoverflow.com/a/25386444/2337254
template< typename ... Args >
std::string argListToString(const Args& ... args)
{
std::ostringstream oss;
int a[] = { 0, ((void)(oss << args), 0) ... };
(void)a; // POLYVOX_UNUSED() doesn't seem to work here?
return oss.str();
}
// Log trace message
template< typename ... Args >
void logTraceMessage(Args const& ... messageArgs)
{
std::string message = argListToString(messageArgs...);
getLoggerInstance()->logTraceMessage(message);
}
template< typename ... Args >
void logTraceMessageIf(bool condition, Args const& ... messageArgs)
{
if (condition) { logTraceMessage(messageArgs...); }
}
// Log debug message
template< typename ... Args >
void logDebugMessage(Args const& ... messageArgs)
{
std::string message = argListToString(messageArgs...);
getLoggerInstance()->logDebugMessage(message);
}
template< typename ... Args >
void logDebugMessageIf(bool condition, Args const& ... messageArgs)
{
if (condition) { logDebugMessage(messageArgs...); }
}
// Log info message
template< typename ... Args >
void logInfoMessage(Args const& ... messageArgs)
{
std::string message = argListToString(messageArgs...);
getLoggerInstance()->logInfoMessage(message);
}
template< typename ... Args >
void logInfoMessageIf(bool condition, Args const& ... messageArgs)
{
if (condition) { logInfoMessage(messageArgs...); }
}
// Log warning message
template< typename ... Args >
void logWarningMessage(Args const& ... messageArgs)
{
std::string message = argListToString(messageArgs...);
getLoggerInstance()->logWarningMessage(message);
}
template< typename ... Args >
void logWarningMessageIf(bool condition, Args const& ... messageArgs)
{
if (condition) { logWarningMessage(messageArgs...); }
}
// Log error message
template< typename ... Args >
void logErrorMessage(Args const& ... messageArgs)
{
std::string message = argListToString(messageArgs...);
getLoggerInstance()->logErrorMessage(message);
}
template< typename ... Args >
void logErrorMessageIf(bool condition, Args const& ... messageArgs)
{
if (condition) { logErrorMessage(messageArgs...); }
}
// Log fatal message
template< typename ... Args >
void logFatalMessage(Args const& ... messageArgs)
{
std::string message = argListToString(messageArgs...);
getLoggerInstance()->logFatalMessage(message);
}
template< typename ... Args >
void logFatalMessageIf(bool condition, Args const& ... messageArgs)
{
if (condition) { logFatalMessage(messageArgs...); }
}
}
}
#ifdef POLYVOX_LOG_TRACE_ENABLED
#define POLYVOX_LOG_TRACE(...) PolyVox::Impl::logTraceMessage(__VA_ARGS__)
#define POLYVOX_LOG_TRACE_IF(condition, ...) PolyVox::Impl::logTraceMessageIf(condition, __VA_ARGS__)
#else
#define POLYVOX_LOG_TRACE(...)
#define POLYVOX_LOG_TRACE_IF(condition, ...)
#endif
#ifdef POLYVOX_LOG_DEBUG_ENABLED
#define POLYVOX_LOG_DEBUG(...) PolyVox::Impl::logDebugMessage(__VA_ARGS__)
#define POLYVOX_LOG_DEBUG_IF(condition, ...) PolyVox::Impl::logDebugMessageIf(condition, __VA_ARGS__)
#else
#define POLYVOX_LOG_DEBUG(...)
#define POLYVOX_LOG_DEBUG_IF(condition, ...)
#endif
#ifdef POLYVOX_LOG_INFO_ENABLED
#define POLYVOX_LOG_INFO(...) PolyVox::Impl::logInfoMessage(__VA_ARGS__)
#define POLYVOX_LOG_INFO_IF(condition, ...) PolyVox::Impl::logInfoMessageIf(condition, __VA_ARGS__)
#else
#define POLYVOX_LOG_INFO(...)
#define POLYVOX_LOG_INFO_IF(condition, ...)
#endif
#ifdef POLYVOX_LOG_WARNING_ENABLED
#define POLYVOX_LOG_WARNING(...) PolyVox::Impl::logWarningMessage(__VA_ARGS__)
#define POLYVOX_LOG_WARNING_IF(condition, ...) PolyVox::Impl::logWarningMessageIf(condition, __VA_ARGS__)
#else
#define POLYVOX_LOG_WARNING(...)
#define POLYVOX_LOG_WARNING_IF(condition, ...)
#endif
#ifdef POLYVOX_LOG_ERROR_ENABLED
#define POLYVOX_LOG_ERROR(...) PolyVox::Impl::logErrorMessage(__VA_ARGS__)
#define POLYVOX_LOG_ERROR_IF(condition, ...) PolyVox::Impl::logErrorMessageIf(condition, __VA_ARGS__)
#else
#define POLYVOX_LOG_ERROR(...)
#define POLYVOX_LOG_ERROR_IF(condition, ...)
#endif
#ifdef POLYVOX_LOG_FATAL_ENABLED
#define POLYVOX_LOG_FATAL(...) PolyVox::Impl::logFatalMessage(__VA_ARGS__)
#define POLYVOX_LOG_FATAL_IF(condition, ...) PolyVox::Impl::logFatalMessageIf(condition, __VA_ARGS__)
#else
#define POLYVOX_LOG_FATAL(...)
#define POLYVOX_LOG_FATAL_IF(condition, ...)
#endif
#endif //__PolyVox_LoggingImpl_H__

View File

@ -1,30 +1,31 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_MarchingCubeTables_H__ #ifndef __PolyVox_MarchingCubeTables_H__
#define __PolyVox_MarchingCubeTables_H__ #define __PolyVox_MarchingCubeTables_H__
#include "PolyVox/Impl/TypeDef.h" #include "PlatformDefinitions.h"
#include <cstdint> #include <cstdint>

View File

@ -0,0 +1,160 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2015 David Williams and Matthew Williams
*
* 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.
*******************************************************************************/
#ifndef __PolyVox_Morton_H__
#define __PolyVox_Morton_H__
namespace PolyVox
{
// Based on: http://www.forceflow.be/2013/10/07/morton-encodingdecoding-through-bit-interleaving-implementations/
static const uint32_t morton256_x[256] =
{
0x00000000,
0x00000001, 0x00000008, 0x00000009, 0x00000040, 0x00000041, 0x00000048, 0x00000049, 0x00000200,
0x00000201, 0x00000208, 0x00000209, 0x00000240, 0x00000241, 0x00000248, 0x00000249, 0x00001000,
0x00001001, 0x00001008, 0x00001009, 0x00001040, 0x00001041, 0x00001048, 0x00001049, 0x00001200,
0x00001201, 0x00001208, 0x00001209, 0x00001240, 0x00001241, 0x00001248, 0x00001249, 0x00008000,
0x00008001, 0x00008008, 0x00008009, 0x00008040, 0x00008041, 0x00008048, 0x00008049, 0x00008200,
0x00008201, 0x00008208, 0x00008209, 0x00008240, 0x00008241, 0x00008248, 0x00008249, 0x00009000,
0x00009001, 0x00009008, 0x00009009, 0x00009040, 0x00009041, 0x00009048, 0x00009049, 0x00009200,
0x00009201, 0x00009208, 0x00009209, 0x00009240, 0x00009241, 0x00009248, 0x00009249, 0x00040000,
0x00040001, 0x00040008, 0x00040009, 0x00040040, 0x00040041, 0x00040048, 0x00040049, 0x00040200,
0x00040201, 0x00040208, 0x00040209, 0x00040240, 0x00040241, 0x00040248, 0x00040249, 0x00041000,
0x00041001, 0x00041008, 0x00041009, 0x00041040, 0x00041041, 0x00041048, 0x00041049, 0x00041200,
0x00041201, 0x00041208, 0x00041209, 0x00041240, 0x00041241, 0x00041248, 0x00041249, 0x00048000,
0x00048001, 0x00048008, 0x00048009, 0x00048040, 0x00048041, 0x00048048, 0x00048049, 0x00048200,
0x00048201, 0x00048208, 0x00048209, 0x00048240, 0x00048241, 0x00048248, 0x00048249, 0x00049000,
0x00049001, 0x00049008, 0x00049009, 0x00049040, 0x00049041, 0x00049048, 0x00049049, 0x00049200,
0x00049201, 0x00049208, 0x00049209, 0x00049240, 0x00049241, 0x00049248, 0x00049249, 0x00200000,
0x00200001, 0x00200008, 0x00200009, 0x00200040, 0x00200041, 0x00200048, 0x00200049, 0x00200200,
0x00200201, 0x00200208, 0x00200209, 0x00200240, 0x00200241, 0x00200248, 0x00200249, 0x00201000,
0x00201001, 0x00201008, 0x00201009, 0x00201040, 0x00201041, 0x00201048, 0x00201049, 0x00201200,
0x00201201, 0x00201208, 0x00201209, 0x00201240, 0x00201241, 0x00201248, 0x00201249, 0x00208000,
0x00208001, 0x00208008, 0x00208009, 0x00208040, 0x00208041, 0x00208048, 0x00208049, 0x00208200,
0x00208201, 0x00208208, 0x00208209, 0x00208240, 0x00208241, 0x00208248, 0x00208249, 0x00209000,
0x00209001, 0x00209008, 0x00209009, 0x00209040, 0x00209041, 0x00209048, 0x00209049, 0x00209200,
0x00209201, 0x00209208, 0x00209209, 0x00209240, 0x00209241, 0x00209248, 0x00209249, 0x00240000,
0x00240001, 0x00240008, 0x00240009, 0x00240040, 0x00240041, 0x00240048, 0x00240049, 0x00240200,
0x00240201, 0x00240208, 0x00240209, 0x00240240, 0x00240241, 0x00240248, 0x00240249, 0x00241000,
0x00241001, 0x00241008, 0x00241009, 0x00241040, 0x00241041, 0x00241048, 0x00241049, 0x00241200,
0x00241201, 0x00241208, 0x00241209, 0x00241240, 0x00241241, 0x00241248, 0x00241249, 0x00248000,
0x00248001, 0x00248008, 0x00248009, 0x00248040, 0x00248041, 0x00248048, 0x00248049, 0x00248200,
0x00248201, 0x00248208, 0x00248209, 0x00248240, 0x00248241, 0x00248248, 0x00248249, 0x00249000,
0x00249001, 0x00249008, 0x00249009, 0x00249040, 0x00249041, 0x00249048, 0x00249049, 0x00249200,
0x00249201, 0x00249208, 0x00249209, 0x00249240, 0x00249241, 0x00249248, 0x00249249
};
// pre-shifted table for Y coordinates (1 bit to the left)
static const uint32_t morton256_y[256] = {
0x00000000,
0x00000002, 0x00000010, 0x00000012, 0x00000080, 0x00000082, 0x00000090, 0x00000092, 0x00000400,
0x00000402, 0x00000410, 0x00000412, 0x00000480, 0x00000482, 0x00000490, 0x00000492, 0x00002000,
0x00002002, 0x00002010, 0x00002012, 0x00002080, 0x00002082, 0x00002090, 0x00002092, 0x00002400,
0x00002402, 0x00002410, 0x00002412, 0x00002480, 0x00002482, 0x00002490, 0x00002492, 0x00010000,
0x00010002, 0x00010010, 0x00010012, 0x00010080, 0x00010082, 0x00010090, 0x00010092, 0x00010400,
0x00010402, 0x00010410, 0x00010412, 0x00010480, 0x00010482, 0x00010490, 0x00010492, 0x00012000,
0x00012002, 0x00012010, 0x00012012, 0x00012080, 0x00012082, 0x00012090, 0x00012092, 0x00012400,
0x00012402, 0x00012410, 0x00012412, 0x00012480, 0x00012482, 0x00012490, 0x00012492, 0x00080000,
0x00080002, 0x00080010, 0x00080012, 0x00080080, 0x00080082, 0x00080090, 0x00080092, 0x00080400,
0x00080402, 0x00080410, 0x00080412, 0x00080480, 0x00080482, 0x00080490, 0x00080492, 0x00082000,
0x00082002, 0x00082010, 0x00082012, 0x00082080, 0x00082082, 0x00082090, 0x00082092, 0x00082400,
0x00082402, 0x00082410, 0x00082412, 0x00082480, 0x00082482, 0x00082490, 0x00082492, 0x00090000,
0x00090002, 0x00090010, 0x00090012, 0x00090080, 0x00090082, 0x00090090, 0x00090092, 0x00090400,
0x00090402, 0x00090410, 0x00090412, 0x00090480, 0x00090482, 0x00090490, 0x00090492, 0x00092000,
0x00092002, 0x00092010, 0x00092012, 0x00092080, 0x00092082, 0x00092090, 0x00092092, 0x00092400,
0x00092402, 0x00092410, 0x00092412, 0x00092480, 0x00092482, 0x00092490, 0x00092492, 0x00400000,
0x00400002, 0x00400010, 0x00400012, 0x00400080, 0x00400082, 0x00400090, 0x00400092, 0x00400400,
0x00400402, 0x00400410, 0x00400412, 0x00400480, 0x00400482, 0x00400490, 0x00400492, 0x00402000,
0x00402002, 0x00402010, 0x00402012, 0x00402080, 0x00402082, 0x00402090, 0x00402092, 0x00402400,
0x00402402, 0x00402410, 0x00402412, 0x00402480, 0x00402482, 0x00402490, 0x00402492, 0x00410000,
0x00410002, 0x00410010, 0x00410012, 0x00410080, 0x00410082, 0x00410090, 0x00410092, 0x00410400,
0x00410402, 0x00410410, 0x00410412, 0x00410480, 0x00410482, 0x00410490, 0x00410492, 0x00412000,
0x00412002, 0x00412010, 0x00412012, 0x00412080, 0x00412082, 0x00412090, 0x00412092, 0x00412400,
0x00412402, 0x00412410, 0x00412412, 0x00412480, 0x00412482, 0x00412490, 0x00412492, 0x00480000,
0x00480002, 0x00480010, 0x00480012, 0x00480080, 0x00480082, 0x00480090, 0x00480092, 0x00480400,
0x00480402, 0x00480410, 0x00480412, 0x00480480, 0x00480482, 0x00480490, 0x00480492, 0x00482000,
0x00482002, 0x00482010, 0x00482012, 0x00482080, 0x00482082, 0x00482090, 0x00482092, 0x00482400,
0x00482402, 0x00482410, 0x00482412, 0x00482480, 0x00482482, 0x00482490, 0x00482492, 0x00490000,
0x00490002, 0x00490010, 0x00490012, 0x00490080, 0x00490082, 0x00490090, 0x00490092, 0x00490400,
0x00490402, 0x00490410, 0x00490412, 0x00490480, 0x00490482, 0x00490490, 0x00490492, 0x00492000,
0x00492002, 0x00492010, 0x00492012, 0x00492080, 0x00492082, 0x00492090, 0x00492092, 0x00492400,
0x00492402, 0x00492410, 0x00492412, 0x00492480, 0x00492482, 0x00492490, 0x00492492
};
// Pre-shifted table for z (2 bits to the left)
static const uint32_t morton256_z[256] = {
0x00000000,
0x00000004, 0x00000020, 0x00000024, 0x00000100, 0x00000104, 0x00000120, 0x00000124, 0x00000800,
0x00000804, 0x00000820, 0x00000824, 0x00000900, 0x00000904, 0x00000920, 0x00000924, 0x00004000,
0x00004004, 0x00004020, 0x00004024, 0x00004100, 0x00004104, 0x00004120, 0x00004124, 0x00004800,
0x00004804, 0x00004820, 0x00004824, 0x00004900, 0x00004904, 0x00004920, 0x00004924, 0x00020000,
0x00020004, 0x00020020, 0x00020024, 0x00020100, 0x00020104, 0x00020120, 0x00020124, 0x00020800,
0x00020804, 0x00020820, 0x00020824, 0x00020900, 0x00020904, 0x00020920, 0x00020924, 0x00024000,
0x00024004, 0x00024020, 0x00024024, 0x00024100, 0x00024104, 0x00024120, 0x00024124, 0x00024800,
0x00024804, 0x00024820, 0x00024824, 0x00024900, 0x00024904, 0x00024920, 0x00024924, 0x00100000,
0x00100004, 0x00100020, 0x00100024, 0x00100100, 0x00100104, 0x00100120, 0x00100124, 0x00100800,
0x00100804, 0x00100820, 0x00100824, 0x00100900, 0x00100904, 0x00100920, 0x00100924, 0x00104000,
0x00104004, 0x00104020, 0x00104024, 0x00104100, 0x00104104, 0x00104120, 0x00104124, 0x00104800,
0x00104804, 0x00104820, 0x00104824, 0x00104900, 0x00104904, 0x00104920, 0x00104924, 0x00120000,
0x00120004, 0x00120020, 0x00120024, 0x00120100, 0x00120104, 0x00120120, 0x00120124, 0x00120800,
0x00120804, 0x00120820, 0x00120824, 0x00120900, 0x00120904, 0x00120920, 0x00120924, 0x00124000,
0x00124004, 0x00124020, 0x00124024, 0x00124100, 0x00124104, 0x00124120, 0x00124124, 0x00124800,
0x00124804, 0x00124820, 0x00124824, 0x00124900, 0x00124904, 0x00124920, 0x00124924, 0x00800000,
0x00800004, 0x00800020, 0x00800024, 0x00800100, 0x00800104, 0x00800120, 0x00800124, 0x00800800,
0x00800804, 0x00800820, 0x00800824, 0x00800900, 0x00800904, 0x00800920, 0x00800924, 0x00804000,
0x00804004, 0x00804020, 0x00804024, 0x00804100, 0x00804104, 0x00804120, 0x00804124, 0x00804800,
0x00804804, 0x00804820, 0x00804824, 0x00804900, 0x00804904, 0x00804920, 0x00804924, 0x00820000,
0x00820004, 0x00820020, 0x00820024, 0x00820100, 0x00820104, 0x00820120, 0x00820124, 0x00820800,
0x00820804, 0x00820820, 0x00820824, 0x00820900, 0x00820904, 0x00820920, 0x00820924, 0x00824000,
0x00824004, 0x00824020, 0x00824024, 0x00824100, 0x00824104, 0x00824120, 0x00824124, 0x00824800,
0x00824804, 0x00824820, 0x00824824, 0x00824900, 0x00824904, 0x00824920, 0x00824924, 0x00900000,
0x00900004, 0x00900020, 0x00900024, 0x00900100, 0x00900104, 0x00900120, 0x00900124, 0x00900800,
0x00900804, 0x00900820, 0x00900824, 0x00900900, 0x00900904, 0x00900920, 0x00900924, 0x00904000,
0x00904004, 0x00904020, 0x00904024, 0x00904100, 0x00904104, 0x00904120, 0x00904124, 0x00904800,
0x00904804, 0x00904820, 0x00904824, 0x00904900, 0x00904904, 0x00904920, 0x00904924, 0x00920000,
0x00920004, 0x00920020, 0x00920024, 0x00920100, 0x00920104, 0x00920120, 0x00920124, 0x00920800,
0x00920804, 0x00920820, 0x00920824, 0x00920900, 0x00920904, 0x00920920, 0x00920924, 0x00924000,
0x00924004, 0x00924020, 0x00924024, 0x00924100, 0x00924104, 0x00924120, 0x00924124, 0x00924800,
0x00924804, 0x00924820, 0x00924824, 0x00924900, 0x00924904, 0x00924920, 0x00924924
};
/*inline uint32_t convertCoordinates(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos)
{
uint64_t answer = 0;
answer = morton256_z[(uZPos >> 16) & 0xFF] | // we start by shifting the third byte, since we only look at the first 21 bits
morton256_y[(uYPos >> 16) & 0xFF] |
morton256_x[(uXPos >> 16) & 0xFF];
answer = answer << 48 |
morton256_z[(uZPos >> 8) & 0xFF] | // shifting second byte
morton256_y[(uYPos >> 8) & 0xFF] |
morton256_x[(uXPos >> 8) & 0xFF];
answer = answer << 24 |
morton256_z[(uZPos)& 0xFF] | // first byte
morton256_y[(uYPos)& 0xFF] |
morton256_x[(uXPos)& 0xFF];
return answer;
}*/
}
#endif //__PolyVox_Morton_H__

View File

@ -0,0 +1,85 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2015 David Williams and Matthew Williams
*
* 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.
*******************************************************************************/
// This file contains definitions for various macros, etc, which need to be different
// for each platform. It helps keep per-platform logic outside the rest of PolyVox.
#ifndef __PolyVox_PlatformDefinitions_H__
#define __PolyVox_PlatformDefinitions_H__
// An error message like the one below makes it much clearer to the user that they are using
// an unsupported compiler, rather than them wondering if they are using PolyVox incorrectly.
#if defined(_MSC_VER) && (_MSC_VER < 1800)
#error "Your version of Visual Studio is too old to build PolyVox. You need at least version Visual Stusio 2013"
#endif
// Macros cannot contain #ifdefs, but some of our macros need to disable warnings and such warning supression is
// platform specific. But macros can contain other macros, so we create macros to control the warnings and use
// those instead. This set of warning supression macros can be extended to GCC/Clang when required.
#if defined(_MSC_VER)
#define POLYVOX_MSC_WARNING_PUSH __pragma(warning(push))
#define POLYVOX_DISABLE_MSC_WARNING(x) __pragma(warning(disable:x))
#define POLYVOX_MSC_WARNING_POP __pragma(warning(pop))
#else
#define POLYVOX_MSC_WARNING_PUSH
#define POLYVOX_DISABLE_MSC_WARNING(x)
#define POLYVOX_MSC_WARNING_POP
#endif
// Used to mark functions as deprecated prior to us removing them.
#if defined _WIN32 || defined __CYGWIN__
#define POLYVOX_DEPRECATED __declspec(deprecated)
#else
#define POLYVOX_DEPRECATED __attribute__((deprecated))
#endif
// The depreacated macro (and possibly others?) cause confusion for SWIG, so we undefine them if SWIG is running.
#if defined SWIG
//Do nothing in this case
#else
#undef POLYVOX_DEPRECATED
#define POLYVOX_DEPRECATED //Define it to nothing to avoid warnings
#endif
// Halts the application is the most elegant way possible (dropping into a debugger if we can).
#if defined(_MSC_VER)
// In Visual Studio we can use this function to go into the debugger.
#define POLYVOX_HALT() __debugbreak()
#else
// On other platforms we just halt by forcing a crash.
// Hopefully this puts us in the debugger if one is running
#if defined(__linux__) || defined(__APPLE__)
#define POLYVOX_HALT() raise(SIGTRAP)
#else
#define POLYVOX_HALT() *((unsigned int*)0) = 0xDEAD
#endif
#endif
// Used to prevent the compiler complaining about unused varuables, particularly useful when
// e.g. asserts are disabled and the parameter it was checking isn't used anywhere else.
// Note that this implementation doesn't seem to work everywhere, for some reason I have
// seen it give compile errors when combined with variadic template functions (to be confirmed)?
// Implementation from here: http://stackoverflow.com/a/4851173/2337254
#define POLYVOX_UNUSED(x) do { (void)sizeof(x); } while(0)
#endif //__PolyVox_PlatformDefinitions_H__

View File

@ -1,123 +0,0 @@
//----------------------------------------------------------------------------
// ThreeD Quadric Error Function
//----------------------------------------------------------------------------
#ifndef _THREED_QEF_H
#define _THREED_QEF_H
#include <PolyVoxCore/Vector.h>
namespace PolyVox {
/**
* QEF, implementing the quadric error function
* E[x] = P - Ni . Pi
*
* Given at least three points Pi, each with its respective
* normal vector Ni, that describe at least two planes,
* the QEF evalulates to the point x.
*/
Vector3DFloat evaluateQEF(
double mat[][3], double *vec, int rows); //TODO make these STL containers
// compute svd
void computeSVD(
double mat[][3], // matrix (rows x 3)
double u[][3], // matrix (rows x 3)
double v[3][3], // matrix (3x3)
double d[3], // vector (1x3)
int rows);
// factorize
void factorize(
double mat[][3], // matrix (rows x 3)
double tau_u[3], // vector (1x3)
double tau_v[2], // vectors, (1x2)
int rows);
double factorize_hh(double *ptrs[], int n);
// unpack
void unpack(
double u[][3], // matrix (rows x 3)
double v[3][3], // matrix (3x3)
double tau_u[3], // vector, (1x3)
double tau_v[2], // vector, (1x2)
int rows);
// diagonalize
void diagonalize(
double u[][3], // matrix (rows x 3)
double v[3][3], // matrix (3x3)
double tau_u[3], // vector, (1x3)
double tau_v[2], // vector, (1x2)
int rows);
void chop(double *a, double *b, int n);
void qrstep(
double u[][3], // matrix (rows x cols)
double v[][3], // matrix (3 x cols)
double tau_u[], // vector (1 x cols)
double tau_v[], // vector (1 x cols - 1)
int rows, int cols);
void qrstep_middle(
double u[][3], // matrix (rows x cols)
double tau_u[], // vector (1 x cols)
double tau_v[], // vector (1 x cols - 1)
int rows, int cols, int col);
void qrstep_end(
double v[][3], // matrix (3 x 3)
double tau_u[], // vector (1 x 3)
double tau_v[], // vector (1 x 2)
int cols);
double qrstep_eigenvalue(
double tau_u[], // vector (1 x 3)
double tau_v[], // vector (1 x 2)
int cols);
void qrstep_cols2(
double u[][3], // matrix (rows x 2)
double v[][3], // matrix (3 x 2)
double tau_u[], // vector (1 x 2)
double tau_v[], // vector (1 x 1)
int rows);
void computeGivens(
double a, double b, double *c, double *s);
void computeSchur(
double a1, double a2, double a3,
double *c, double *s);
// singularize
void singularize(
double u[][3], // matrix (rows x 3)
double v[3][3], // matrix (3x3)
double d[3], // vector, (1x3)
int rows);
// solve svd
void solveSVD(
double u[][3], // matrix (rows x 3)
double v[3][3], // matrix (3x3)
double d[3], // vector (1x3)
double b[], // vector (1 x rows)
double x[3], // vector (1x3)
int rows);
} // namespace ThreeD
#include "PolyVoxCore/Impl/QEF.inl"
#endif // _THREED_QEF_H

View File

@ -1,829 +0,0 @@
//----------------------------------------------------------------------------
// ThreeD Quadric Error Function
//----------------------------------------------------------------------------
#include <cmath>
#include <string>
namespace PolyVox {
//----------------------------------------------------------------------------
#define MAXROWS 12
#define EPSILON 1e-5
//----------------------------------------------------------------------------
Vector3DFloat evaluateQEF(
double mat[][3], double *vec, int rows)
{
// perform singular value decomposition on matrix mat
// into u, v and d.
// u is a matrix of rows x 3 (same as mat);
// v is a square matrix 3 x 3 (for 3 columns in mat);
// d is vector of 3 values representing the diagonal
// matrix 3 x 3 (for 3 colums in mat).
double u[MAXROWS][3], v[3][3], d[3];
computeSVD(mat, u, v, d, rows);
// solve linear system given by mat and vec using the
// singular value decomposition of mat into u, v and d.
if (d[2] < 0.1)
d[2] = 0.0;
if (d[1] < 0.1)
d[1] = 0.0;
if (d[0] < 0.1)
d[0] = 0.0;
double x[3];
solveSVD(u, v, d, vec, x, rows);
return {static_cast<float>(x[0]), static_cast<float>(x[1]), static_cast<float>(x[2])};
}
//----------------------------------------------------------------------------
void computeSVD(
double mat[][3], // matrix (rows x 3)
double u[][3], // matrix (rows x 3)
double v[3][3], // matrix (3x3)
double d[3], // vector (1x3)
int rows)
{
std::memcpy(u, mat, rows * 3 * sizeof(double));
double *tau_u = d;
double tau_v[2];
factorize(u, tau_u, tau_v, rows);
unpack(u, v, tau_u, tau_v, rows);
diagonalize(u, v, tau_u, tau_v, rows);
singularize(u, v, tau_u, rows);
}
//----------------------------------------------------------------------------
void factorize(
double mat[][3], // matrix (rows x 3)
double tau_u[3], // vector, (1x3)
double tau_v[2], // vector, (1x2)
int rows)
{
int y;
// bidiagonal factorization of (rows x 3) matrix into :-
// tau_u, a vector of 1x3 (for 3 columns in the matrix)
// tau_v, a vector of 1x2 (one less column than the matrix)
for (int i = 0; i < 3; ++i) {
// set up a vector to reference into the matrix
// from mat(i,i) to mat(m,i), that is, from the
// i'th column of the i'th row and down all the way
// through that column
double *ptrs[MAXROWS];
int num_ptrs = rows - i;
for (int q = 0; q < num_ptrs; ++q)
ptrs[q] = &mat[q + i][i];
// perform householder transformation on this vector
double tau = factorize_hh(ptrs, num_ptrs);
tau_u[i] = tau;
// all computations below this point are performed
// only for the first two columns: i=0 or i=1
if (i + 1 < 3) {
// perform householder transformation on the matrix
// mat(i,i+1) to mat(m,n), that is, on the sub-matrix
// that begins in the (i+1)'th column of the i'th
// row and extends to the end of the matrix at (m,n)
if (tau != 0.0) {
for (int x = i + 1; x < 3; ++x) {
double wx = mat[i][x];
for (y = i + 1; y < rows; ++y)
wx += mat[y][x] * (*ptrs[y - i]);
double tau_wx = tau * wx;
mat[i][x] -= tau_wx;
for (y = i + 1; y < rows; ++y)
mat[y][x] -= tau_wx * (*ptrs[y - i]);
}
}
// perform householder transformation on i'th row
// (remember at this point, i is either 0 or 1)
// set up a vector to reference into the matrix
// from mat(i,i+1) to mat(i,n), that is, from the
// (i+1)'th column of the i'th row and all the way
// through to the end of that row
ptrs[0] = &mat[i][i + 1];
if (i == 0) {
ptrs[1] = &mat[i][i + 2];
num_ptrs = 2;
} else // i == 1
num_ptrs = 1;
// perform householder transformation on this vector
tau = factorize_hh(ptrs, num_ptrs);
tau_v[i] = tau;
// perform householder transformation on the sub-matrix
// mat(i+1,i+1) to mat(m,n), that is, on the sub-matrix
// that begins in the (i+1)'th column of the (i+1)'th
// row and extends to the end of the matrix at (m,n)
if (tau != 0.0) {
for (y = i + 1; y < rows; ++y) {
double wy = mat[y][i + 1];
if (i == 0)
wy += mat[y][i + 2] * (*ptrs[1]);
double tau_wy = tau * wy;
mat[y][i + 1] -= tau_wy;
if (i == 0)
mat[y][i + 2] -= tau_wy * (*ptrs[1]);
}
}
} // if (i + 1 < 3)
}
}
//----------------------------------------------------------------------------
double factorize_hh(double *ptrs[], int n)
{
double tau = 0.0;
if (n > 1) {
double xnorm;
if (n == 2)
xnorm = std::abs(*ptrs[1]);
else {
double scl = 0.0;
double ssq = 1.0;
for (int i = 1; i < n; ++i) {
double x = std::abs(*ptrs[i]);
if (x != 0.0) {
if (scl < x) {
ssq = 1.0 + ssq * (scl / x) * (scl / x);
scl = x;
} else
ssq += (x / scl) * (x / scl);
}
}
xnorm = scl * sqrt(ssq);
}
if (xnorm != 0.0) {
double alpha = *ptrs[0];
double beta = sqrt(alpha * alpha + xnorm * xnorm);
if (alpha >= 0.0)
beta = -beta;
tau = (beta - alpha) / beta;
double scl = 1.0 / (alpha - beta);
*ptrs[0] = beta;
for (int i = 1; i < n; ++i)
*ptrs[i] *= scl;
}
}
return tau;
}
//----------------------------------------------------------------------------
void unpack(
double u[][3], // matrix (rows x 3)
double v[3][3], // matrix (3x3)
double tau_u[3], // vector, (1x3)
double tau_v[2], // vector, (1x2)
int rows)
{
int i, y;
// reset v to the identity matrix
v[0][0] = v[1][1] = v[2][2] = 1.0;
v[0][1] = v[0][2] = v[1][0] = v[1][2] = v[2][0] = v[2][1] = 0.0;
for (i = 1; i >= 0; --i) {
double tau = tau_v[i];
// perform householder transformation on the sub-matrix
// v(i+1,i+1) to v(m,n), that is, on the sub-matrix of v
// that begins in the (i+1)'th column of the (i+1)'th row
// and extends to the end of the matrix at (m,n). the
// householder vector used to perform this is the vector
// from u(i,i+1) to u(i,n)
if (tau != 0.0) {
for (int x = i + 1; x < 3; ++x) {
double wx = v[i + 1][x];
for (y = i + 1 + 1; y < 3; ++y)
wx += v[y][x] * u[i][y];
double tau_wx = tau * wx;
v[i + 1][x] -= tau_wx;
for (y = i + 1 + 1; y < 3; ++y)
v[y][x] -= tau_wx * u[i][y];
}
}
}
// copy superdiagonal of u into tau_v
for (i = 0; i < 2; ++i)
tau_v[i] = u[i][i + 1];
// below, same idea for u: householder transformations
// and the superdiagonal copy
for (i = 2; i >= 0; --i) {
// copy superdiagonal of u into tau_u
double tau = tau_u[i];
tau_u[i] = u[i][i];
// perform householder transformation on the sub-matrix
// u(i,i) to u(m,n), that is, on the sub-matrix of u that
// begins in the i'th column of the i'th row and extends
// to the end of the matrix at (m,n). the householder
// vector used to perform this is the i'th column of u,
// that is, u(0,i) to u(m,i)
if (tau == 0.0) {
u[i][i] = 1.0;
if (i < 2) {
u[i][2] = 0.0;
if (i < 1)
u[i][1] = 0.0;
}
for (y = i + 1; y < rows; ++y)
u[y][i] = 0.0;
} else {
for (int x = i + 1; x < 3; ++x) {
double wx = 0.0;
for (y = i + 1; y < rows; ++y)
wx += u[y][x] * u[y][i];
double tau_wx = tau * wx;
u[i][x] = -tau_wx;
for (y = i + 1; y < rows; ++y)
u[y][x] -= tau_wx * u[y][i];
}
for (y = i + 1; y < rows; ++y)
u[y][i] = u[y][i] * -tau;
u[i][i] = 1.0 - tau;
}
}
}
//----------------------------------------------------------------------------
void diagonalize(
double u[][3], // matrix (rows x 3)
double v[3][3], // matrix (3x3)
double tau_u[3], // vector, (1x3)
double tau_v[2], // vector, (1x2)
int rows)
{
int i, j;
chop(tau_u, tau_v, 3);
// progressively reduce the matrices into diagonal form
int b = 3 - 1;
while (b > 0) {
if (tau_v[b - 1] == 0.0)
--b;
else {
int a = b - 1;
while (a > 0 && tau_v[a - 1] != 0.0)
--a;
int n = b - a + 1;
double u1[MAXROWS][3];
double v1[3][3];
for (j = a; j <= b; ++j) {
for (i = 0; i < rows; ++i)
u1[i][j - a] = u[i][j];
for (i = 0; i < 3; ++i)
v1[i][j - a] = v[i][j];
}
qrstep(u1, v1, &tau_u[a], &tau_v[a], rows, n);
for (j = a; j <= b; ++j) {
for (i = 0; i < rows; ++i)
u[i][j] = u1[i][j - a];
for (i = 0; i < 3; ++i)
v[i][j] = v1[i][j - a];
}
chop(&tau_u[a], &tau_v[a], n);
}
}
}
//----------------------------------------------------------------------------
void chop(double *a, double *b, int n)
{
double ai = a[0];
for (int i = 0; i < n - 1; ++i) {
double bi = b[i];
double ai1 = a[i + 1];
if (std::abs(bi) < EPSILON * (std::abs(ai) + std::abs(ai1)))
b[i] = 0.0;
ai = ai1;
}
}
//----------------------------------------------------------------------------
void qrstep(
double u[][3], // matrix (rows x cols)
double v[][3], // matrix (3 x cols)
double tau_u[], // vector (1 x cols)
double tau_v[], // vector (1 x cols - 1)
int rows, int cols)
{
int i;
if (cols == 2) {
qrstep_cols2(u, v, tau_u, tau_v, rows);
return;
}
// handle zeros on the diagonal or at its end
for (i = 0; i < cols - 1; ++i)
if (tau_u[i] == 0.0) {
qrstep_middle(u, tau_u, tau_v, rows, cols, i);
return;
}
if (tau_u[cols - 1] == 0.0) {
qrstep_end(v, tau_u, tau_v, cols);
return;
}
// perform qr reduction on the diagonal and off-diagonal
double mu = qrstep_eigenvalue(tau_u, tau_v, cols);
double y = tau_u[0] * tau_u[0] - mu;
double z = tau_u[0] * tau_v[0];
double ak = 0.0;
double bk = 0.0;
double zk;
double ap = tau_u[0];
double bp = tau_v[0];
double aq = tau_u[1];
double bq = tau_v[1];
for (int k = 0; k < cols - 1; ++k) {
double c, s;
// perform Givens rotation on V
computeGivens(y, z, &c, &s);
for (i = 0; i < 3; ++i) {
double vip = v[i][k];
double viq = v[i][k + 1];
v[i][k] = vip * c - viq * s;
v[i][k + 1] = vip * s + viq * c;
}
// perform Givens rotation on B
double bk1 = bk * c - z * s;
double ap1 = ap * c - bp * s;
double bp1 = ap * s + bp * c;
double zp1 = aq * -s;
double aq1 = aq * c;
if (k > 0)
tau_v[k - 1] = bk1;
ak = ap1;
bk = bp1;
zk = zp1;
ap = aq1;
if (k < cols - 2)
bp = tau_v[k + 1];
else
bp = 0.0;
y = ak;
z = zk;
// perform Givens rotation on U
computeGivens(y, z, &c, &s);
for (i = 0; i < rows; ++i) {
double uip = u[i][k];
double uiq = u[i][k + 1];
u[i][k] = uip * c - uiq * s;
u[i][k + 1] = uip * s + uiq * c;
}
// perform Givens rotation on B
double ak1 = ak * c - zk * s;
bk1 = bk * c - ap * s;
double zk1 = bp * -s;
ap1 = bk * s + ap * c;
bp1 = bp * c;
tau_u[k] = ak1;
ak = ak1;
bk = bk1;
zk = zk1;
ap = ap1;
bp = bp1;
if (k < cols - 2)
aq = tau_u[k + 2];
else
aq = 0.0;
y = bk;
z = zk;
}
tau_v[cols - 2] = bk;
tau_u[cols - 1] = ap;
}
//----------------------------------------------------------------------------
void qrstep_middle(
double u[][3], // matrix (rows x cols)
double tau_u[], // vector (1 x cols)
double tau_v[], // vector (1 x cols - 1)
int rows, int cols, int col)
{
double x = tau_v[col];
double y = tau_u[col + 1];
for (int j = col; j < cols - 1; ++j) {
double c, s;
// perform Givens rotation on U
computeGivens(y, -x, &c, &s);
for (int i = 0; i < rows; ++i) {
double uip = u[i][col];
double uiq = u[i][j + 1];
u[i][col] = uip * c - uiq * s;
u[i][j + 1] = uip * s + uiq * c;
}
// perform transposed Givens rotation on B
tau_u[j + 1] = x * s + y * c;
if (j == col)
tau_v[j] = x * c - y * s;
if (j < cols - 2) {
double z = tau_v[j + 1];
tau_v[j + 1] *= c;
x = z * -s;
y = tau_u[j + 2];
}
}
}
//----------------------------------------------------------------------------
void qrstep_end(
double v[][3], // matrix (3 x 3)
double tau_u[], // vector (1 x 3)
double tau_v[], // vector (1 x 2)
int cols)
{
double x = tau_u[1];
double y = tau_v[1];
for (int k = 1; k >= 0; --k) {
double c, s;
// perform Givens rotation on V
computeGivens(x, y, &c, &s);
for (int i = 0; i < 3; ++i) {
double vip = v[i][k];
double viq = v[i][2];
v[i][k] = vip * c - viq * s;
v[i][2] = vip * s + viq * c;
}
// perform Givens rotation on B
tau_u[k] = x * c - y * s;
if (k == 1)
tau_v[k] = x * s + y * c;
if (k > 0) {
double z = tau_v[k - 1];
tau_v[k - 1] *= c;
x = tau_u[k - 1];
y = z * s;
}
}
}
//----------------------------------------------------------------------------
double qrstep_eigenvalue(
double tau_u[], // vector (1 x 3)
double tau_v[], // vector (1 x 2)
int cols)
{
double ta = tau_u[1] * tau_u[1] + tau_v[0] * tau_v[0];
double tb = tau_u[2] * tau_u[2] + tau_v[1] * tau_v[1];
double tab = tau_u[1] * tau_v[1];
double dt = (ta - tb) / 2.0;
double mu;
if (dt >= 0.0)
mu = tb - (tab * tab) / (dt + sqrt(dt * dt + tab * tab));
else
mu = tb + (tab * tab) / (sqrt(dt * dt + tab * tab) - dt);
return mu;
}
//----------------------------------------------------------------------------
void qrstep_cols2(
double u[][3], // matrix (rows x 2)
double v[][3], // matrix (3 x 2)
double tau_u[], // vector (1 x 2)
double tau_v[], // vector (1 x 1)
int rows)
{
int i;
double tmp;
// eliminate off-diagonal element in [ 0 tau_v0 ]
// [ 0 tau_u1 ]
// to make [ tau_u[0] 0 ]
// [ 0 0 ]
if (tau_u[0] == 0.0) {
double c, s;
// perform transposed Givens rotation on B
// multiplied by X = [ 0 1 ]
// [ 1 0 ]
computeGivens(tau_v[0], tau_u[1], &c, &s);
tau_u[0] = tau_v[0] * c - tau_u[1] * s;
tau_v[0] = tau_v[0] * s + tau_u[1] * c;
tau_u[1] = 0.0;
// perform Givens rotation on U
for (i = 0; i < rows; ++i) {
double uip = u[i][0];
double uiq = u[i][1];
u[i][0] = uip * c - uiq * s;
u[i][1] = uip * s + uiq * c;
}
// multiply V by X, effectively swapping first two columns
for (i = 0; i < 3; ++i) {
tmp = v[i][0];
v[i][0] = v[i][1];
v[i][1] = tmp;
}
}
// eliminate off-diagonal element in [ tau_u0 tau_v0 ]
// [ 0 0 ]
else if (tau_u[1] == 0.0) {
double c, s;
// perform Givens rotation on B
computeGivens(tau_u[0], tau_v[0], &c, &s);
tau_u[0] = tau_u[0] * c - tau_v[0] * s;
tau_v[0] = 0.0;
// perform Givens rotation on V
for (i = 0; i < 3; ++i) {
double vip = v[i][0];
double viq = v[i][1];
v[i][0] = vip * c - viq * s;
v[i][1] = vip * s + viq * c;
}
}
// make colums orthogonal,
else {
double c, s;
// perform Schur rotation on B
computeSchur(tau_u[0], tau_v[0], tau_u[1], &c, &s);
double a11 = tau_u[0] * c - tau_v[0] * s;
double a21 = - tau_u[1] * s;
double a12 = tau_u[0] * s + tau_v[0] * c;
double a22 = tau_u[1] * c;
// perform Schur rotation on V
for (i = 0; i < 3; ++i) {
double vip = v[i][0];
double viq = v[i][1];
v[i][0] = vip * c - viq * s;
v[i][1] = vip * s + viq * c;
}
// eliminate off diagonal elements
if ((a11 * a11 + a21 * a21) < (a12 * a12 + a22 * a22)) {
// multiply B by X
tmp = a11;
a11 = a12;
a12 = tmp;
tmp = a21;
a21 = a22;
a22 = tmp;
// multiply V by X, effectively swapping first
// two columns
for (i = 0; i < 3; ++i) {
tmp = v[i][0];
v[i][0] = v[i][1];
v[i][1] = tmp;
}
}
// perform transposed Givens rotation on B
computeGivens(a11, a21, &c, &s);
tau_u[0] = a11 * c - a21 * s;
tau_v[0] = a12 * c - a22 * s;
tau_u[1] = a12 * s + a22 * c;
// perform Givens rotation on U
for (i = 0; i < rows; ++i) {
double uip = u[i][0];
double uiq = u[i][1];
u[i][0] = uip * c - uiq * s;
u[i][1] = uip * s + uiq * c;
}
}
}
//----------------------------------------------------------------------------
void computeGivens(
double a, double b, double *c, double *s)
{
if (b == 0.0) {
*c = 1.0;
*s = 0.0;
} else if (std::abs(b) > std::abs(a)) {
double t = -a / b;
double s1 = 1.0 / sqrt(1 + t * t);
*s = s1;
*c = s1 * t;
} else {
double t = -b / a;
double c1 = 1.0 / sqrt(1 + t * t);
*c = c1;
*s = c1 * t;
}
}
//----------------------------------------------------------------------------
void computeSchur(
double a1, double a2, double a3,
double *c, double *s)
{
double apq = a1 * a2 * 2.0;
if (apq == 0.0) {
*c = 1.0;
*s = 0.0;
} else {
double t;
double tau = (a2 * a2 + (a3 + a1) * (a3 - a1)) / apq;
if (tau >= 0.0)
t = 1.0 / (tau + sqrt(1.0 + tau * tau));
else
t = - 1.0 / (sqrt(1.0 + tau * tau) - tau);
*c = 1.0 / sqrt(1.0 + t * t);
*s = t * (*c);
}
}
//----------------------------------------------------------------------------
void singularize(
double u[][3], // matrix (rows x 3)
double v[3][3], // matrix (3x3)
double d[3], // vector, (1x3)
int rows)
{
int i, j, y;
// make singularize values positive
for (j = 0; j < 3; ++j)
if (d[j] < 0.0) {
for (i = 0; i < 3; ++i)
v[i][j] = -v[i][j];
d[j] = -d[j];
}
// sort singular values in decreasing order
for (i = 0; i < 3; ++i) {
double d_max = d[i];
int i_max = i;
for (j = i + 1; j < 3; ++j)
if (d[j] > d_max) {
d_max = d[j];
i_max = j;
}
if (i_max != i) {
// swap eigenvalues
double tmp = d[i];
d[i] = d[i_max];
d[i_max] = tmp;
// swap eigenvectors
for (y = 0; y < rows; ++y) {
tmp = u[y][i];
u[y][i] = u[y][i_max];
u[y][i_max] = tmp;
}
for (y = 0; y < 3; ++y) {
tmp = v[y][i];
v[y][i] = v[y][i_max];
v[y][i_max] = tmp;
}
}
}
}
//----------------------------------------------------------------------------
void solveSVD(
double u[][3], // matrix (rows x 3)
double v[3][3], // matrix (3x3)
double d[3], // vector (1x3)
double b[], // vector (1 x rows)
double x[3], // vector (1x3)
int rows)
{
static double zeroes[3] = { 0.0, 0.0, 0.0 };
int i, j;
// compute vector w = U^T * b
double w[3];
std::memcpy(w, zeroes, sizeof(w));
for (i = 0; i < rows; ++i) {
if (b[i] != 0.0)
for (j = 0; j < 3; ++j)
w[j] += b[i] * u[i][j];
}
// introduce non-zero singular values in d into w
for (i = 0; i < 3; ++i) {
if (d[i] != 0.0)
w[i] /= d[i];
}
// compute result vector x = V * w
for (i = 0; i < 3; ++i) {
double tmp = 0.0;
for (j = 0; j < 3; ++j)
tmp += w[j] * v[i][j];
x[i] = tmp;
}
}
}

View File

@ -1,32 +1,33 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_RandomUnitVectors_H__ #ifndef __PolyVox_RandomUnitVectors_H__
#define __PolyVox_RandomUnitVectors_H__ #define __PolyVox_RandomUnitVectors_H__
#include "PolyVox/Impl/TypeDef.h" #include "PlatformDefinitions.h"
#include "PolyVox/Vector.h" #include "../Vector.h"
namespace PolyVox namespace PolyVox
{ {

View File

@ -1,32 +1,33 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_RandomVectors_H__ #ifndef __PolyVox_RandomVectors_H__
#define __PolyVox_RandomVectors_H__ #define __PolyVox_RandomVectors_H__
#include "PolyVox/Impl/TypeDef.h" #include "PlatformDefinitions.h"
#include "PolyVox/Vector.h" #include "../Vector.h"
namespace PolyVox namespace PolyVox
{ {

View File

@ -1,32 +1,32 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-20013 David Williams and Matthew Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_Timer_H__ #ifndef __PolyVox_Timer_H__
#define __PolyVox_Timer_H__ #define __PolyVox_Timer_H__
#include <cstdint>
#include <chrono> #include <chrono>
#include <cstdint>
namespace PolyVox namespace PolyVox
{ {
@ -52,13 +52,13 @@ namespace PolyVox
return elapsed_seconds.count(); return elapsed_seconds.count();
} }
uint32_t elapsedTimeInMilliSeconds(void) float elapsedTimeInMilliSeconds(void)
{ {
std::chrono::duration<float, std::milli> elapsed_milliseconds = clock::now() - m_start; std::chrono::duration<float, std::milli> elapsed_milliseconds = clock::now() - m_start;
return elapsed_milliseconds.count(); return elapsed_milliseconds.count();
} }
uint32_t elapsedTimeInMicroSeconds(void) float elapsedTimeInMicroSeconds(void)
{ {
std::chrono::duration<float, std::micro> elapsed_microseconds = clock::now() - m_start; std::chrono::duration<float, std::micro> elapsed_microseconds = clock::now() - m_start;
return elapsed_microseconds.count(); return elapsed_microseconds.count();

View File

@ -1,74 +0,0 @@
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#ifndef __PolyVox_TypeDef_H__
#define __PolyVox_TypeDef_H__
#if defined(_MSC_VER) && (_MSC_VER < 1800)
#error "Your version of Visual Studio is too old to build PolyVox. You need at least version Visual Stusio 2013"
#endif
//Definitions needed to make library functions accessable
// See http://gcc.gnu.org/wiki/Visibility for more info.
#if defined _WIN32 || defined __CYGWIN__
#define POLYVOX_HELPER_IMPORT __declspec(dllimport)
#define POLYVOX_HELPER_EXPORT __declspec(dllexport)
#define POLYVOX_HELPER_LOCAL
#define POLYVOX_DEPRECATED __declspec(deprecated)
#else
#define POLYVOX_DEPRECATED __attribute__((deprecated))
#if __GNUC__ >= 4
#define POLYVOX_HELPER_IMPORT __attribute__ ((visibility("default")))
#define POLYVOX_HELPER_EXPORT __attribute__ ((visibility("default")))
#define POLYVOX_HELPER_LOCAL __attribute__ ((visibility("hidden")))
#else
#define POLYVOX_HELPER_IMPORT
#define POLYVOX_HELPER_EXPORT
#define POLYVOX_HELPER_LOCAL
#endif
#endif
#if defined SWIG
//Do nothing in this case
#else
#undef POLYVOX_DEPRECATED
#define POLYVOX_DEPRECATED //Define it to nothing to avoid warnings
#endif
// Now we use the generic helper definitions above to define POLYVOX_API and POLYVOX_LOCAL.
// POLYVOX_API is used for the public API symbols. It either imports or exports (or does nothing for static build)
// POLYVOX_LOCAL is used for non-api symbols.
#ifdef POLYVOX_SHARED // defined if PolyVox is compiled as a shared library
#ifdef POLYVOX_SHARED_EXPORTS // defined if we are building the PolyVox shared library (instead of using it)
#define POLYVOX_API POLYVOX_HELPER_EXPORT
#else
#define POLYVOX_API POLYVOX_HELPER_IMPORT
#endif // POLYVOX_SHARED_EXPORTS
#define POLYVOX_LOCAL POLYVOX_HELPER_LOCAL
#else // POLYVOX_SHARED is not defined: this means PolyVox is a static library.
#define POLYVOX_API
#define POLYVOX_LOCAL
#endif // POLYVOX_SHARED
#endif

View File

@ -1,30 +1,31 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_Utility_H__ #ifndef __PolyVox_Utility_H__
#define __PolyVox_Utility_H__ #define __PolyVox_Utility_H__
#include "PolyVox/Impl/TypeDef.h" #include "PlatformDefinitions.h"
#include <cstdint> #include <cstdint>

View File

@ -1,72 +0,0 @@
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#ifndef __PolyVox_Interpolation_H__
#define __PolyVox_Interpolation_H__
namespace PolyVox
{
template <typename Type>
Type lerp(
const Type& v0,const Type& v1,
const float x)
{
//Interpolate along X
Type v0_1 = (v1 - v0) * x + v0;
return v0_1;
}
template <typename Type>
Type bilerp(
const Type& v00,const Type& v10,const Type& v01,const Type& v11,
const float x, const float y)
{
// Linearly interpolate along x
Type v00_10 = lerp(v00, v10, x);
Type v01_11 = lerp(v01, v11, x);
// And linearly interpolate the results along y
Type v00_10__v01_11 = lerp(v00_10, v01_11, y);
return v00_10__v01_11;
}
template <typename Type>
Type trilerp(
const Type& v000,const Type& v100,const Type& v010,const Type& v110,
const Type& v001,const Type& v101,const Type& v011,const Type& v111,
const float x, const float y, const float z)
{
// Bilinearly interpolate along Y
Type v000_v100__v010_v110 = bilerp(v000, v100, v010, v110, x, y);
Type v001_v101__v011_v111 = bilerp(v001, v101, v011, v111, x, y);
// And linearly interpolate the results along z
Type v000_v100__v010_v110____v001_v101__v011_v111 = lerp(v000_v100__v010_v110, v001_v101__v011_v111, z);
return v000_v100__v010_v110____v001_v101__v011_v111;
}
}
#endif //__PolyVox_Interpolation_H__

View File

@ -1,46 +0,0 @@
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#ifndef __PolyVox_IteratorController_H__
#define __PolyVox_IteratorController_H__
#include "PolyVox/Region.h"
namespace PolyVox
{
template <typename IteratorType>
class IteratorController
{
public:
void reset(void);
bool moveForward(void);
public:
Region m_regValid;
IteratorType* m_Iter;
};
}
#include "PolyVox/IteratorController.inl"
#endif //__PolyVox_IteratorController_H__

View File

@ -1,63 +0,0 @@
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
namespace PolyVox
{
template <typename IteratorType>
void IteratorController<IteratorType>::reset(void)
{
m_Iter->setPosition(m_regValid.getLowerCorner());
}
template <typename IteratorType>
bool IteratorController<IteratorType>::moveForward(void)
{
Vector3DInt32 v3dInitialPosition(m_Iter->getPosition().getX(), m_Iter->getPosition().getY(), m_Iter->getPosition().getZ());
if(v3dInitialPosition.getX() < m_regValid.getUpperX())
{
m_Iter->movePositiveX();
return true;
}
v3dInitialPosition.setX(m_regValid.getLowerX());
if(v3dInitialPosition.getY() < m_regValid.getUpperY())
{
v3dInitialPosition.setY(v3dInitialPosition.getY() + 1);
m_Iter->setPosition(v3dInitialPosition);
return true;
}
v3dInitialPosition.setY(m_regValid.getLowerY());
if(v3dInitialPosition.getZ() < m_regValid.getUpperZ())
{
v3dInitialPosition.setZ(v3dInitialPosition.getZ() + 1);
m_Iter->setPosition(v3dInitialPosition);
return true;
}
return false;
}
}

View File

@ -1,9 +0,0 @@
#ifndef __PolyVox_LargeVolume_H__
#define __PolyVox_LargeVolume_H__
#pragma message("WARNING - The LargeVolume class has been replaced by PagedVolume. Please use that instead.")
#include "PagedVolume.h"
#include "PolyVoxForwardDeclarations.h"
#endif //__PolyVox_LargeVolume_H__

77
include/PolyVox/Logging.h Normal file
View File

@ -0,0 +1,77 @@
/*******************************************************************************
The MIT License (MIT)
Copyright (c) 2015 David Williams and Matthew Williams
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.
*******************************************************************************/
#ifndef __PolyVox_Logging_H__
#define __PolyVox_Logging_H__
#include <iostream>
#include <string>
// We expose the logger class to the user so that they can provide custom implementations
// to redirect PolyVox's log messages. However, it is not expected that user code will make
// use of PolyVox's logging macros s these are part of the private implementation.
namespace PolyVox
{
class Logger
{
public:
Logger() {};
virtual ~Logger() {};
virtual void logTraceMessage(const std::string& message) = 0;
virtual void logDebugMessage(const std::string& message) = 0;
virtual void logInfoMessage(const std::string& message) = 0;
virtual void logWarningMessage(const std::string& message) = 0;
virtual void logErrorMessage(const std::string& message) = 0;
virtual void logFatalMessage(const std::string& message) = 0;
};
class DefaultLogger : public Logger
{
public:
DefaultLogger() : Logger() {}
virtual ~DefaultLogger() {}
// Appending the 'std::endl' forces the stream to be flushed.
void logTraceMessage(const std::string& /*message*/) { }
void logDebugMessage(const std::string& /*message*/) { }
void logInfoMessage(const std::string& message) { std::cout << message << std::endl; }
void logWarningMessage(const std::string& message) { std::cerr << message << std::endl; }
void logErrorMessage(const std::string& message) { std::cerr << message << std::endl; }
void logFatalMessage(const std::string& message) { std::cerr << message << std::endl; }
};
inline Logger*& getLoggerInstance()
{
static Logger* s_pLogger = new DefaultLogger;
return s_pLogger;
}
inline void setLoggerInstance(Logger* pLogger)
{
getLoggerInstance() = pLogger;
}
}
#endif //__PolyVox_Logging_H__

View File

@ -1,42 +1,46 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_LowPassFilter_H__ #ifndef __PolyVox_LowPassFilter_H__
#define __PolyVox_LowPassFilter_H__ #define __PolyVox_LowPassFilter_H__
#include "PolyVox/IteratorController.h" #include "Impl/IteratorController.h"
#include "PolyVox/RawVolume.h" //Is this desirable?
#include "PolyVox/Region.h" #include "Region.h"
namespace PolyVox namespace PolyVox
{ {
/// This class is able to copy volume data from a source volume to a destination volume while performing low-pass filtering (blurring).
template< typename SrcVolumeType, typename DstVolumeType, typename AccumulationType> template< typename SrcVolumeType, typename DstVolumeType, typename AccumulationType>
class LowPassFilter class LowPassFilter
{ {
public: public:
LowPassFilter(SrcVolumeType* pVolSrc, Region regSrc, DstVolumeType* pVolDst, Region regDst, uint32_t uKernelSize); LowPassFilter(SrcVolumeType* pVolSrc, Region regSrc, DstVolumeType* pVolDst, Region regDst, uint32_t uKernelSize);
/// Execute a standard approach to filtering which performs a number of neighbourhood look-ups per voxel.
void execute(); void execute();
/// Execute a version with 'Summed Area Tables'. This should be faster for large kernel sizes but this hasn't really been confirmed yet.
void executeSAT(); void executeSAT();
private: private:
@ -54,7 +58,7 @@ namespace PolyVox
}//namespace PolyVox }//namespace PolyVox
#include "PolyVox/LowPassFilter.inl" #include "LowPassFilter.inl"
#endif //__PolyVox_LowPassFilter_H__ #endif //__PolyVox_LowPassFilter_H__

View File

@ -1,26 +1,29 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "PolyVox/RawVolume.h" // Currently used by exectureSAT() method - should be replaced by PagedVolume or a template parameter?
namespace PolyVox namespace PolyVox
{ {
/** /**
@ -33,19 +36,19 @@ namespace PolyVox
template< typename SrcVolumeType, typename DstVolumeType, typename AccumulationType> template< typename SrcVolumeType, typename DstVolumeType, typename AccumulationType>
LowPassFilter<SrcVolumeType, DstVolumeType, AccumulationType>::LowPassFilter(SrcVolumeType* pVolSrc, Region regSrc, DstVolumeType* pVolDst, Region regDst, uint32_t uKernelSize) LowPassFilter<SrcVolumeType, DstVolumeType, AccumulationType>::LowPassFilter(SrcVolumeType* pVolSrc, Region regSrc, DstVolumeType* pVolDst, Region regDst, uint32_t uKernelSize)
:m_pVolSrc(pVolSrc) :m_pVolSrc(pVolSrc)
,m_regSrc(regSrc) , m_regSrc(regSrc)
,m_pVolDst(pVolDst) , m_pVolDst(pVolDst)
,m_regDst(regDst) , m_regDst(regDst)
,m_uKernelSize(uKernelSize) , m_uKernelSize(uKernelSize)
{ {
//Kernel size must be at least three //Kernel size must be at least three
if(m_uKernelSize < 3) if (m_uKernelSize < 3)
{ {
POLYVOX_THROW(std::invalid_argument, "Kernel size must be at least three"); POLYVOX_THROW(std::invalid_argument, "Kernel size must be at least three");
} }
//Kernel size must be odd //Kernel size must be odd
if(m_uKernelSize % 2 == 0) if (m_uKernelSize % 2 == 0)
{ {
POLYVOX_THROW(std::invalid_argument, "Kernel size must be odd"); POLYVOX_THROW(std::invalid_argument, "Kernel size must be odd");
} }
@ -72,11 +75,11 @@ namespace PolyVox
typename SrcVolumeType::Sampler srcSampler(m_pVolSrc); typename SrcVolumeType::Sampler srcSampler(m_pVolSrc);
for(int32_t iSrcZ = iSrcMinZ, iDstZ = iDstMinZ; iSrcZ <= iSrcMaxZ; iSrcZ++, iDstZ++) for (int32_t iSrcZ = iSrcMinZ, iDstZ = iDstMinZ; iSrcZ <= iSrcMaxZ; iSrcZ++, iDstZ++)
{ {
for(int32_t iSrcY = iSrcMinY, iDstY = iDstMinY; iSrcY <= iSrcMaxY; iSrcY++, iDstY++) for (int32_t iSrcY = iSrcMinY, iDstY = iDstMinY; iSrcY <= iSrcMaxY; iSrcY++, iDstY++)
{ {
for(int32_t iSrcX = iSrcMinX, iDstX = iDstMinX; iSrcX <= iSrcMaxX; iSrcX++, iDstX++) for (int32_t iSrcX = iSrcMinX, iDstX = iDstMinX; iSrcX <= iSrcMaxX; iSrcX++, iDstX++)
{ {
AccumulationType tSrcVoxel(0); AccumulationType tSrcVoxel(0);
srcSampler.setPosition(iSrcX, iSrcY, iSrcZ); srcSampler.setPosition(iSrcX, iSrcY, iSrcZ);
@ -114,7 +117,7 @@ namespace PolyVox
tSrcVoxel /= 27; tSrcVoxel /= 27;
//tSrcVoxel.setDensity(uDensity); //tSrcVoxel.setDensity(uDensity);
m_pVolDst->setVoxelAt(iSrcX, iSrcY, iSrcZ, static_cast<typename DstVolumeType::VoxelType>(tSrcVoxel)); m_pVolDst->setVoxel(iSrcX, iSrcY, iSrcZ, static_cast<typename DstVolumeType::VoxelType>(tSrcVoxel));
} }
} }
} }
@ -135,13 +138,13 @@ namespace PolyVox
//Clear to zeros (necessary?) //Clear to zeros (necessary?)
//FIXME - use Volume::fill() method. Implemented in base class as below //FIXME - use Volume::fill() method. Implemented in base class as below
//but with optimised implementations in subclasses? //but with optimised implementations in subclasses?
for(int32_t z = satLowerCorner.getZ(); z <= satUpperCorner.getZ(); z++) for (int32_t z = satLowerCorner.getZ(); z <= satUpperCorner.getZ(); z++)
{ {
for(int32_t y = satLowerCorner.getY(); y <= satUpperCorner.getY(); y++) for (int32_t y = satLowerCorner.getY(); y <= satUpperCorner.getY(); y++)
{ {
for(int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++) for (int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++)
{ {
satVolume.setVoxelAt(x,y,z,0); satVolume.setVoxel(x, y, z, 0);
} }
} }
} }
@ -169,7 +172,7 @@ namespace PolyVox
srcIterCont.moveForward(); srcIterCont.moveForward();
}while(satIterCont.moveForward()); } while (satIterCont.moveForward());
//Build SAT in three passes //Build SAT in three passes
/*for(int32_t z = satLowerCorner.getZ(); z <= satUpperCorner.getZ(); z++) /*for(int32_t z = satLowerCorner.getZ(); z <= satUpperCorner.getZ(); z++)
@ -178,38 +181,38 @@ namespace PolyVox
{ {
for(int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++) for(int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++)
{ {
AccumulationType previousSum = static_cast<AccumulationType>(satVolume.getVoxelAt(x-1,y,z)); AccumulationType previousSum = static_cast<AccumulationType>(satVolume.getVoxel(x-1,y,z));
AccumulationType currentVal = static_cast<AccumulationType>(m_pVolSrc->getVoxelAt(x,y,z)); AccumulationType currentVal = static_cast<AccumulationType>(m_pVolSrc->getVoxel(x,y,z));
satVolume.setVoxelAt(x,y,z,previousSum + currentVal); satVolume.setVoxel(x,y,z,previousSum + currentVal);
} }
} }
}*/ }*/
for(int32_t z = satLowerCorner.getZ(); z <= satUpperCorner.getZ(); z++) for (int32_t z = satLowerCorner.getZ(); z <= satUpperCorner.getZ(); z++)
{ {
for(int32_t y = satLowerCorner.getY(); y <= satUpperCorner.getY(); y++) for (int32_t y = satLowerCorner.getY(); y <= satUpperCorner.getY(); y++)
{ {
for(int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++) for (int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++)
{ {
AccumulationType previousSum = static_cast<AccumulationType>(satVolume.getVoxel(x,y-1,z, WrapModes::Border)); AccumulationType previousSum = static_cast<AccumulationType>(satVolume.getVoxel(x, y - 1, z));
AccumulationType currentSum = static_cast<AccumulationType>(satVolume.getVoxel(x,y,z, WrapModes::Border)); AccumulationType currentSum = static_cast<AccumulationType>(satVolume.getVoxel(x, y, z));
satVolume.setVoxelAt(x,y,z,previousSum + currentSum); satVolume.setVoxel(x, y, z, previousSum + currentSum);
} }
} }
} }
for(int32_t z = satLowerCorner.getZ(); z <= satUpperCorner.getZ(); z++) for (int32_t z = satLowerCorner.getZ(); z <= satUpperCorner.getZ(); z++)
{ {
for(int32_t y = satLowerCorner.getY(); y <= satUpperCorner.getY(); y++) for (int32_t y = satLowerCorner.getY(); y <= satUpperCorner.getY(); y++)
{ {
for(int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++) for (int32_t x = satLowerCorner.getX(); x <= satUpperCorner.getX(); x++)
{ {
AccumulationType previousSum = static_cast<AccumulationType>(satVolume.getVoxel(x,y,z-1, WrapModes::Border)); AccumulationType previousSum = static_cast<AccumulationType>(satVolume.getVoxel(x, y, z - 1));
AccumulationType currentSum = static_cast<AccumulationType>(satVolume.getVoxel(x,y,z, WrapModes::Border)); AccumulationType currentSum = static_cast<AccumulationType>(satVolume.getVoxel(x, y, z));
satVolume.setVoxelAt(x,y,z,previousSum + currentSum); satVolume.setVoxel(x, y, z, previousSum + currentSum);
} }
} }
} }
@ -220,11 +223,11 @@ namespace PolyVox
const Vector3DInt32& v3dSrcLowerCorner = m_regSrc.getLowerCorner(); const Vector3DInt32& v3dSrcLowerCorner = m_regSrc.getLowerCorner();
for(int32_t iDstZ = v3dDstLowerCorner.getZ(), iSrcZ = v3dSrcLowerCorner.getZ(); iDstZ <= v3dDstUpperCorner.getZ(); iDstZ++, iSrcZ++) for (int32_t iDstZ = v3dDstLowerCorner.getZ(), iSrcZ = v3dSrcLowerCorner.getZ(); iDstZ <= v3dDstUpperCorner.getZ(); iDstZ++, iSrcZ++)
{ {
for(int32_t iDstY = v3dDstLowerCorner.getY(), iSrcY = v3dSrcLowerCorner.getY(); iDstY <= v3dDstUpperCorner.getY(); iDstY++, iSrcY++) for (int32_t iDstY = v3dDstLowerCorner.getY(), iSrcY = v3dSrcLowerCorner.getY(); iDstY <= v3dDstUpperCorner.getY(); iDstY++, iSrcY++)
{ {
for(int32_t iDstX = v3dDstLowerCorner.getX(), iSrcX = v3dSrcLowerCorner.getX(); iDstX <= v3dDstUpperCorner.getX(); iDstX++, iSrcX++) for (int32_t iDstX = v3dDstLowerCorner.getX(), iSrcX = v3dSrcLowerCorner.getX(); iDstX <= v3dDstUpperCorner.getX(); iDstX++, iSrcX++)
{ {
int32_t satLowerX = iSrcX - border - 1; int32_t satLowerX = iSrcX - border - 1;
int32_t satLowerY = iSrcY - border - 1; int32_t satLowerY = iSrcY - border - 1;
@ -234,20 +237,20 @@ namespace PolyVox
int32_t satUpperY = iSrcY + border; int32_t satUpperY = iSrcY + border;
int32_t satUpperZ = iSrcZ + border; int32_t satUpperZ = iSrcZ + border;
AccumulationType a = satVolume.getVoxel(satLowerX,satLowerY,satLowerZ, WrapModes::Border); AccumulationType a = satVolume.getVoxel(satLowerX, satLowerY, satLowerZ);
AccumulationType b = satVolume.getVoxel(satUpperX,satLowerY,satLowerZ, WrapModes::Border); AccumulationType b = satVolume.getVoxel(satUpperX, satLowerY, satLowerZ);
AccumulationType c = satVolume.getVoxel(satLowerX,satUpperY,satLowerZ, WrapModes::Border); AccumulationType c = satVolume.getVoxel(satLowerX, satUpperY, satLowerZ);
AccumulationType d = satVolume.getVoxel(satUpperX,satUpperY,satLowerZ, WrapModes::Border); AccumulationType d = satVolume.getVoxel(satUpperX, satUpperY, satLowerZ);
AccumulationType e = satVolume.getVoxel(satLowerX,satLowerY,satUpperZ, WrapModes::Border); AccumulationType e = satVolume.getVoxel(satLowerX, satLowerY, satUpperZ);
AccumulationType f = satVolume.getVoxel(satUpperX,satLowerY,satUpperZ, WrapModes::Border); AccumulationType f = satVolume.getVoxel(satUpperX, satLowerY, satUpperZ);
AccumulationType g = satVolume.getVoxel(satLowerX,satUpperY,satUpperZ, WrapModes::Border); AccumulationType g = satVolume.getVoxel(satLowerX, satUpperY, satUpperZ);
AccumulationType h = satVolume.getVoxel(satUpperX,satUpperY,satUpperZ, WrapModes::Border); AccumulationType h = satVolume.getVoxel(satUpperX, satUpperY, satUpperZ);
AccumulationType sum = h+c-d-g-f-a+b+e; AccumulationType sum = h + c - d - g - f - a + b + e;
uint32_t sideLength = border * 2 + 1; uint32_t sideLength = border * 2 + 1;
AccumulationType average = sum / (sideLength*sideLength*sideLength); AccumulationType average = sum / (sideLength*sideLength*sideLength);
m_pVolDst->setVoxelAt(iDstX, iDstY, iDstZ, static_cast<typename DstVolumeType::VoxelType>(average)); m_pVolDst->setVoxel(iDstX, iDstY, iDstZ, static_cast<typename DstVolumeType::VoxelType>(average));
} }
} }
} }

View File

@ -1,57 +1,57 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_SurfaceExtractor_H__ #ifndef __PolyVox_SurfaceExtractor_H__
#define __PolyVox_SurfaceExtractor_H__ #define __PolyVox_SurfaceExtractor_H__
#include "Impl/MarchingCubesTables.h" #include "Impl/MarchingCubesTables.h"
#include "Impl/TypeDef.h" #include "Impl/PlatformDefinitions.h"
#include "PolyVox/Array.h" #include "Array.h"
#include "PolyVox/BaseVolume.h" //For wrap modes... should move these? #include "DefaultMarchingCubesController.h"
#include "PolyVox/Mesh.h" #include "Mesh.h"
#include "PolyVox/DefaultMarchingCubesController.h" #include "Vertex.h"
#include "PolyVox/Vertex.h"
namespace PolyVox namespace PolyVox
{ {
#ifdef SWIG /// A specialised vertex format which encodes the data from the Marching Cubes algorithm in a very
struct MarchingCubesVertex /// compact way. You will probably want to use the decodeVertex() function to turn it into a regular
#else /// Vertex for rendering, but advanced users can also decode it on the GPU (see PolyVox examples).
template<typename _DataType> template<typename _DataType>
struct POLYVOX_API MarchingCubesVertex struct MarchingCubesVertex
#endif
{ {
typedef _DataType DataType; typedef _DataType DataType;
// Each component of the position is stored using 8.8 fixed-point encoding. /// Each component of the position is stored using 8.8 fixed-point encoding.
Vector3DUint16 encodedPosition; Vector3DUint16 encodedPosition;
// The normal is encoded as a 16-bit unsigned integer using the 'oct16' /// The normal is encoded as a 16-bit unsigned integer using the 'oct16'
// encoding described here: http://jcgt.org/published/0003/02/01/ /// encoding described here: http://jcgt.org/published/0003/02/01/
uint16_t encodedNormal; uint16_t encodedNormal;
// User data /// The interpolated voxel data from the neighbouring voxels which generated this
/// vertex (every vertex is placed between two voxels by the MArching Cubes algorithm)
DataType data; DataType data;
}; };
@ -60,299 +60,19 @@ namespace PolyVox
//template <typename VertexDataType, typename IndexType = DefaultIndexType> //template <typename VertexDataType, typename IndexType = DefaultIndexType>
//using MarchingCubesMesh = Mesh< MarchingCubesVertex<VertexDataType>, IndexType >; //using MarchingCubesMesh = Mesh< MarchingCubesVertex<VertexDataType>, IndexType >;
/// Decodes a position from a MarchingCubesVertex
inline Vector3DFloat decodePosition(const Vector3DUint16& encodedPosition)
{
Vector3DFloat result(encodedPosition.getX(), encodedPosition.getY(), encodedPosition.getZ());
result *= (1.0f / 256.0f); // Division is compile-time constant
return result;
}
inline uint16_t encodeNormal(const Vector3DFloat& normal)
{
// The first part of this function is based off the code in Listing 1 of http://jcgt.org/published/0003/02/01/
// It was rewritten in C++ and is restructued for the CPU rather than the GPU.
// Get the input components
float vx = normal.getX();
float vy = normal.getY();
float vz = normal.getZ();
// Project the sphere onto the octahedron, and then onto the xy plane
float px = vx * (1.0f / (std::abs(vx) + std::abs(vy) + std::abs(vz)));
float py = vy * (1.0f / (std::abs(vx) + std::abs(vy) + std::abs(vz)));
// Reflect the folds of the lower hemisphere over the diagonals.
if (vz <= 0.0f)
{
float refx = ((1.0f - std::abs(py)) * (px >= 0.0f ? +1.0f : -1.0f));
float refy = ((1.0f - std::abs(px)) * (py >= 0.0f ? +1.0f : -1.0f));
px = refx;
py = refy;
}
// The next part was not given in the paper. We map our two
// floats into two bytes and store them in a single uint16_t
// Move from range [-1.0f, 1.0f] to [0.0f, 255.0f]
px = (px + 1.0f) * 127.5f;
py = (py + 1.0f) * 127.5f;
// Convert to uints
uint16_t resultX = static_cast<uint16_t>(px + 0.5f);
uint16_t resultY = static_cast<uint16_t>(py + 0.5f);
// Make sure only the lower bits are set. Probably
// not necessary but we're just being careful really.
resultX &= 0xFF;
resultY &= 0xFF;
// Contatenate the bytes and return the result.
return (resultX << 8) | resultY;
}
inline Vector3DFloat decodeNormal(const uint16_t& encodedNormal)
{
// Extract the two bytes from the uint16_t.
uint16_t ux = (encodedNormal >> 8) & 0xFF;
uint16_t uy = (encodedNormal ) & 0xFF;
// Convert to floats in the range [-1.0f, +1.0f].
float ex = ux / 127.5f - 1.0f;
float ey = uy / 127.5f - 1.0f;
// Reconstruct the origninal vector. This is a C++ implementation
// of Listing 2 of http://jcgt.org/published/0003/02/01/
float vx = ex;
float vy = ey;
float vz = 1.0f - std::abs(ex) - std::abs(ey);
if (vz < 0.0f)
{
float refX = ((1.0f - std::abs(vy)) * (vx >= 0.0f ? +1.0f : -1.0f));
float refY = ((1.0f - std::abs(vx)) * (vy >= 0.0f ? +1.0f : -1.0f));
vx = refX;
vy = refY;
}
// Normalise and return the result.
Vector3DFloat v(vx, vy, vz);
v.normalise();
return v;
}
/// Decodes a MarchingCubesVertex by converting it into a regular Vertex which can then be directly used for rendering. /// Decodes a MarchingCubesVertex by converting it into a regular Vertex which can then be directly used for rendering.
template<typename DataType> template<typename DataType>
Vertex<DataType> decodeVertex(const MarchingCubesVertex<DataType>& marchingCubesVertex) Vertex<DataType> decodeVertex(const MarchingCubesVertex<DataType>& marchingCubesVertex);
{
Vertex<DataType> result;
result.position = decodePosition(marchingCubesVertex.encodedPosition);
result.normal = decodeNormal(marchingCubesVertex.encodedNormal);
result.data = marchingCubesVertex.data; // Data is not encoded
return result;
}
/// Do not use this class directly. Use the 'extractMarchingCubesSurface' function instead (see examples).
template< typename VolumeType, typename MeshType, typename ControllerType>
class MarchingCubesSurfaceExtractor
{
public:
MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, ControllerType controller, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType());
void execute();
private:
//Compute the cell bitmask for a particular slice in z.
template<bool isPrevZAvail>
uint32_t computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask);
//Compute the cell bitmask for a given cell.
template<bool isPrevXAvail, bool isPrevYAvail, bool isPrevZAvail>
void computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask, uint32_t uXRegSpace, uint32_t uYRegSpace);
//Use the cell bitmasks to generate all the vertices needed for that slice
void generateVerticesForSlice(const Array2DUint8& pCurrentBitmask,
Array2DInt32& m_pCurrentVertexIndicesX,
Array2DInt32& m_pCurrentVertexIndicesY,
Array2DInt32& m_pCurrentVertexIndicesZ);
////////////////////////////////////////////////////////////////////////////////
// NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010.
//See http://stackoverflow.com/questions/1484885/strange-vc-compile-error-c2244 for details.
////////////////////////////////////////////////////////////////////////////////
Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter)
{
//FIXME - Should actually use DensityType here, both in principle and because the maths may be
//faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel.
//But watch out for when the DensityType is unsigned and the difference could be negative.
float voxel1nx = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx0py0pz()));
float voxel1px = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px0py0pz()));
float voxel1ny = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1ny0pz()));
float voxel1py = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1py0pz()));
float voxel1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py1nz()));
float voxel1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py1pz()));
return Vector3DFloat
(
voxel1nx - voxel1px,
voxel1ny - voxel1py,
voxel1nz - voxel1pz
);
}
Vector3DFloat computeSobelGradient(const typename VolumeType::Sampler& volIter)
{
static const int weights[3][3][3] = { { {2,3,2}, {3,6,3}, {2,3,2} }, {
{3,6,3}, {6,0,6}, {3,6,3} }, { {2,3,2}, {3,6,3}, {2,3,2} } };
//FIXME - Should actually use DensityType here, both in principle and because the maths may be
//faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel.
//But watch out for when the DensityType is unsigned and the difference could be negative.
const float pVoxel1nx1ny1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1ny1nz()));
const float pVoxel1nx1ny0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1ny0pz()));
const float pVoxel1nx1ny1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1ny1pz()));
const float pVoxel1nx0py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx0py1nz()));
const float pVoxel1nx0py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx0py0pz()));
const float pVoxel1nx0py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx0py1pz()));
const float pVoxel1nx1py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1py1nz()));
const float pVoxel1nx1py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1py0pz()));
const float pVoxel1nx1py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1py1pz()));
const float pVoxel0px1ny1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1ny1nz()));
const float pVoxel0px1ny0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1ny0pz()));
const float pVoxel0px1ny1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1ny1pz()));
const float pVoxel0px0py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py1nz()));
//const float pVoxel0px0py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py0pz()));
const float pVoxel0px0py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py1pz()));
const float pVoxel0px1py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1py1nz()));
const float pVoxel0px1py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1py0pz()));
const float pVoxel0px1py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1py1pz()));
const float pVoxel1px1ny1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1ny1nz()));
const float pVoxel1px1ny0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1ny0pz()));
const float pVoxel1px1ny1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1ny1pz()));
const float pVoxel1px0py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px0py1nz()));
const float pVoxel1px0py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px0py0pz()));
const float pVoxel1px0py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px0py1pz()));
const float pVoxel1px1py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1py1nz()));
const float pVoxel1px1py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1py0pz()));
const float pVoxel1px1py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1py1pz()));
const float xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz -
weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] *
pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz -
weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] *
pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz +
weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] *
pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz +
weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] *
pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz +
weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
pVoxel1px1py1pz);
const float yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz +
weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] *
pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz -
weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] *
pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz +
weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] *
pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz -
weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] *
pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz +
weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
pVoxel1px1py1pz);
const float zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz +
weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] *
pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz -
weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] *
pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz +
weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] *
pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz -
weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] *
pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz +
weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] *
pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz -
weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] *
pVoxel1px1py1pz);
//Note: The above actually give gradients going from low density to high density.
//For our normals we want the the other way around, so we switch the components as we return them.
return Vector3DFloat(-xGrad,-yGrad,-zGrad);
}
////////////////////////////////////////////////////////////////////////////////
// End of compiler bug workaroumd.
////////////////////////////////////////////////////////////////////////////////
//Use the cell bitmasks to generate all the indices needed for that slice
void generateIndicesForSlice(const Array2DUint8& pPreviousBitmask,
const Array2DInt32& m_pPreviousVertexIndicesX,
const Array2DInt32& m_pPreviousVertexIndicesY,
const Array2DInt32& m_pPreviousVertexIndicesZ,
const Array2DInt32& m_pCurrentVertexIndicesX,
const Array2DInt32& m_pCurrentVertexIndicesY);
//The volume data and a sampler to access it.
VolumeType* m_volData;
typename VolumeType::Sampler m_sampVolume;
//Used to return the number of cells in a slice which contain triangles.
uint32_t m_uNoOfOccupiedCells;
//The surface patch we are currently filling.
MeshType* m_meshCurrent;
//Information about the region we are currently processing
Region m_regSizeInVoxels;
Region m_regSizeInCells;
/*Region m_regSizeInVoxelsCropped;
Region m_regSizeInVoxelsUncropped;
Region m_regVolumeCropped;*/
Region m_regSlicePrevious;
Region m_regSliceCurrent;
//Used to convert arbitrary voxel types in densities and materials.
ControllerType m_controller;
//Our threshold value
typename ControllerType::DensityType m_tThreshold;
};
// This version of the function performs the extraction into a user-provided mesh rather than allocating a mesh automatically.
// There are a few reasons why this might be useful to more advanced users:
//
// 1. It leaves the user in control of memory allocation and would allow them to implement e.g. a mesh pooling system.
// 2. The user-provided mesh could have a different index type (e.g. 16-bit indices) to reduce memory usage.
// 3. The user could provide a custom mesh class, e.g a thin wrapper around an openGL VBO to allow direct writing into this structure.
//
// We don't provide a default MeshType here. If the user doesn't want to provide a MeshType then it probably makes
// more sense to use the other variant of this function where the mesh is a return value rather than a parameter.
//
// Note: This function is called 'extractMarchingCubesMeshCustom' rather than 'extractMarchingCubesMesh' to avoid ambiguity when only three parameters
// are provided (would the third parameter be a controller or a mesh?). It seems this can be fixed by using enable_if/static_assert to emulate concepts,
// but this is relatively complex and I haven't done it yet. Could always add it later as another overload.
template< typename VolumeType, typename MeshType, typename ControllerType = DefaultMarchingCubesController<typename VolumeType::VoxelType> >
void extractMarchingCubesMeshCustom(VolumeType* volData, Region region, MeshType* result, ControllerType controller = ControllerType(), WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType())
{
MarchingCubesSurfaceExtractor<VolumeType, MeshType, ControllerType> extractor(volData, region, result, controller, eWrapMode, tBorderValue);
extractor.execute();
}
/// Generates a mesh from the voxel data using the Marching Cubes algorithm.
template< typename VolumeType, typename ControllerType = DefaultMarchingCubesController<typename VolumeType::VoxelType> > template< typename VolumeType, typename ControllerType = DefaultMarchingCubesController<typename VolumeType::VoxelType> >
Mesh<MarchingCubesVertex<typename VolumeType::VoxelType> > extractMarchingCubesMesh(VolumeType* volData, Region region, ControllerType controller = ControllerType(), WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType()) Mesh<MarchingCubesVertex<typename VolumeType::VoxelType> > extractMarchingCubesMesh(VolumeType* volData, Region region, ControllerType controller = ControllerType());
{
Mesh<MarchingCubesVertex<typename VolumeType::VoxelType> > result; /// Generates a mesh from the voxel data using the Marching Cubes algorithm, placing the result into a user-provided Mesh.
extractMarchingCubesMeshCustom<VolumeType, Mesh<MarchingCubesVertex<typename VolumeType::VoxelType>, DefaultIndexType > >(volData, region, &result, controller, eWrapMode, tBorderValue); template< typename VolumeType, typename MeshType, typename ControllerType = DefaultMarchingCubesController<typename VolumeType::VoxelType> >
return result; void extractMarchingCubesMeshCustom(VolumeType* volData, Region region, MeshType* result, ControllerType controller = ControllerType());
}
} }
#include "PolyVox/MarchingCubesSurfaceExtractor.inl" #include "MarchingCubesSurfaceExtractor.inl"
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +1,41 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_Material_H__ #ifndef __PolyVox_Material_H__
#define __PolyVox_Material_H__ #define __PolyVox_Material_H__
#include "Impl/TypeDef.h" #include "Impl/PlatformDefinitions.h"
#include "PolyVox/DefaultIsQuadNeeded.h" //we'll specialise this function for this voxel type #include "DefaultIsQuadNeeded.h" //we'll specialise this function for this voxel type
namespace PolyVox namespace PolyVox
{ {
///This class represents a voxel storing only a material. ///This class represents a voxel storing only a material.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// Detailed description... /// Note that this should probably just be considered an example of how to define
/// a voxel type for the Marching Cubes algorithm. Advanced users are likely to
/// define custom voxel types and possibly custom controllers.
/// ///
/// \sa Density, MaterialDensityPair /// \sa Density, MaterialDensityPair
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -75,7 +78,7 @@ namespace PolyVox
public: public:
bool operator()(Material<Type> back, Material<Type> front, Material<Type>& materialToUse) bool operator()(Material<Type> back, Material<Type> front, Material<Type>& materialToUse)
{ {
if((back.getMaterial() > 0) && (front.getMaterial() == 0)) if ((back.getMaterial() > 0) && (front.getMaterial() == 0))
{ {
materialToUse = back; materialToUse = back;
return true; return true;

View File

@ -1,39 +1,42 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_MaterialDensityPair_H__ #ifndef __PolyVox_MaterialDensityPair_H__
#define __PolyVox_MaterialDensityPair_H__ #define __PolyVox_MaterialDensityPair_H__
#include "PolyVox/DefaultIsQuadNeeded.h" //we'll specialise this function for this voxel type #include "DefaultIsQuadNeeded.h" //we'll specialise this function for this voxel type
#include "PolyVox/DefaultMarchingCubesController.h" //We'll specialise the controller contained in here #include "DefaultMarchingCubesController.h" //We'll specialise the controller contained in here
#include "Impl/TypeDef.h" #include "Impl/PlatformDefinitions.h"
namespace PolyVox namespace PolyVox
{ {
/// This class represents a voxel storing only a density. /// This class represents a voxel storing only a density.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// Detailed description... /// Note that this should probably just be considered an example of how to define
/// a voxel type for the Marching Cubes algorithm. Advanced users are likely to
/// define custom voxel types and possibly custom controllers.
/// ///
/// \sa Density, Material /// \sa Density, Material
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -92,7 +95,7 @@ namespace PolyVox
public: public:
bool operator()(MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> back, MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> front, MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>& materialToUse) bool operator()(MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> back, MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> front, MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits>& materialToUse)
{ {
if((back.getMaterial() > 0) && (front.getMaterial() == 0)) if ((back.getMaterial() > 0) && (front.getMaterial() == 0))
{ {
materialToUse = back; materialToUse = back;
return true; return true;
@ -134,7 +137,7 @@ namespace PolyVox
MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> blendMaterials(MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> a, MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> b, float /*weight*/) MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> blendMaterials(MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> a, MaterialDensityPair<Type, NoOfMaterialBits, NoOfDensityBits> b, float /*weight*/)
{ {
if(convertToDensity(a) > convertToDensity(b)) if (convertToDensity(a) > convertToDensity(b))
{ {
return a; return a;
} }

View File

@ -1,34 +1,34 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_Mesh_H__ #ifndef __PolyVox_Mesh_H__
#define __PolyVox_Mesh_H__ #define __PolyVox_Mesh_H__
#include "Impl/TypeDef.h" #include "Impl/PlatformDefinitions.h"
#include "PolyVox/PolyVoxForwardDeclarations.h" #include "Region.h"
#include "PolyVox/Region.h" #include "Vertex.h" //Should probably do away with this one in the future...
#include "PolyVox/Vertex.h" //Should probably do away with this on in the future...
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
@ -39,7 +39,11 @@ freely, subject to the following restrictions:
namespace PolyVox namespace PolyVox
{ {
template <typename _VertexType, typename _IndexType> /// A simple and general-purpose mesh class to represent the data returned by the surface extraction functions.
/// It supports different vertex types (which will vary depending on the surface extractor used and the contents
/// of the volume) and both 16-bit and 32 bit indices.
typedef uint32_t DefaultIndexType;
template <typename _VertexType, typename _IndexType = DefaultIndexType>
class Mesh class Mesh
{ {
public: public:
@ -53,12 +57,10 @@ namespace PolyVox
IndexType getNoOfVertices(void) const; IndexType getNoOfVertices(void) const;
const VertexType& getVertex(IndexType index) const; const VertexType& getVertex(IndexType index) const;
const VertexType* getRawVertexData(void) const; const VertexType* getRawVertexData(void) const;
POLYVOX_DEPRECATED const std::vector<VertexType>& getVertices(void) const;
uint32_t getNoOfIndices(void) const; size_t getNoOfIndices(void) const;
IndexType getIndex(uint32_t index) const; IndexType getIndex(uint32_t index) const;
const IndexType* getRawIndexData(void); const IndexType* getRawIndexData(void) const;
POLYVOX_DEPRECATED const std::vector<IndexType>& getIndices(void) const;
const Vector3DInt32& getOffset(void) const; const Vector3DInt32& getOffset(void) const;
void setOffset(const Vector3DInt32& offset); void setOffset(const Vector3DInt32& offset);
@ -76,6 +78,9 @@ namespace PolyVox
Vector3DInt32 m_offset; Vector3DInt32 m_offset;
}; };
/// Meshes returned by the surface extractors often have vertices with efficient compressed
/// formats which are hard to interpret directly (see CubicVertex and MarchingCubesVertex).
/// This function creates a new uncompressed mesh containing the much simpler Vertex objects.
template <typename MeshType> template <typename MeshType>
Mesh< Vertex< typename MeshType::VertexType::DataType >, typename MeshType::IndexType > decodeMesh(const MeshType& encodedMesh) Mesh< Vertex< typename MeshType::VertexType::DataType >, typename MeshType::IndexType > decodeMesh(const MeshType& encodedMesh)
{ {
@ -98,6 +103,6 @@ namespace PolyVox
} }
} }
#include "PolyVox/Mesh.inl" #include "Mesh.inl"
#endif /* __Mesh_H__ */ #endif /* __Mesh_H__ */

View File

@ -1,24 +1,25 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
namespace PolyVox namespace PolyVox
@ -36,7 +37,7 @@ namespace PolyVox
template <typename VertexType, typename IndexType> template <typename VertexType, typename IndexType>
IndexType Mesh<VertexType, IndexType>::getNoOfVertices(void) const IndexType Mesh<VertexType, IndexType>::getNoOfVertices(void) const
{ {
return m_vecVertices.size(); return static_cast<IndexType>(m_vecVertices.size());
} }
template <typename VertexType, typename IndexType> template <typename VertexType, typename IndexType>
@ -48,17 +49,11 @@ namespace PolyVox
template <typename VertexType, typename IndexType> template <typename VertexType, typename IndexType>
const VertexType* Mesh<VertexType, IndexType>::getRawVertexData(void) const const VertexType* Mesh<VertexType, IndexType>::getRawVertexData(void) const
{ {
return &(m_vecVertices[0]); return m_vecVertices.data();
} }
template <typename VertexType, typename IndexType> template <typename VertexType, typename IndexType>
const std::vector<VertexType>& Mesh<VertexType, IndexType>::getVertices(void) const size_t Mesh<VertexType, IndexType>::getNoOfIndices(void) const
{
return m_vecVertices;
}
template <typename VertexType, typename IndexType>
uint32_t Mesh<VertexType, IndexType>::getNoOfIndices(void) const
{ {
return m_vecIndices.size(); return m_vecIndices.size();
} }
@ -70,15 +65,9 @@ namespace PolyVox
} }
template <typename VertexType, typename IndexType> template <typename VertexType, typename IndexType>
const IndexType* Mesh<VertexType, IndexType>::getRawIndexData(void) const IndexType* Mesh<VertexType, IndexType>::getRawIndexData(void) const
{ {
return &(m_vecIndices[0]); return m_vecIndices.data();
}
template <typename VertexType, typename IndexType>
const std::vector<IndexType>& Mesh<VertexType, IndexType>::getIndices(void) const
{
return m_vecIndices;
} }
template <typename VertexType, typename IndexType> template <typename VertexType, typename IndexType>
@ -135,7 +124,7 @@ namespace PolyVox
std::vector<bool> isVertexUsed(m_vecVertices.size()); std::vector<bool> isVertexUsed(m_vecVertices.size());
std::fill(isVertexUsed.begin(), isVertexUsed.end(), false); std::fill(isVertexUsed.begin(), isVertexUsed.end(), false);
for(uint32_t triCt = 0; triCt < m_vecIndices.size(); triCt++) for (uint32_t triCt = 0; triCt < m_vecIndices.size(); triCt++)
{ {
int v = m_vecIndices[triCt]; int v = m_vecIndices[triCt];
isVertexUsed[v] = true; isVertexUsed[v] = true;
@ -143,9 +132,9 @@ namespace PolyVox
int noOfUsedVertices = 0; int noOfUsedVertices = 0;
std::vector<uint32_t> newPos(m_vecVertices.size()); std::vector<uint32_t> newPos(m_vecVertices.size());
for(IndexType vertCt = 0; vertCt < m_vecVertices.size(); vertCt++) for (IndexType vertCt = 0; vertCt < m_vecVertices.size(); vertCt++)
{ {
if(isVertexUsed[vertCt]) if (isVertexUsed[vertCt])
{ {
m_vecVertices[noOfUsedVertices] = m_vecVertices[vertCt]; m_vecVertices[noOfUsedVertices] = m_vecVertices[vertCt];
newPos[vertCt] = noOfUsedVertices; newPos[vertCt] = noOfUsedVertices;
@ -155,7 +144,7 @@ namespace PolyVox
m_vecVertices.resize(noOfUsedVertices); m_vecVertices.resize(noOfUsedVertices);
for(uint32_t triCt = 0; triCt < m_vecIndices.size(); triCt++) for (uint32_t triCt = 0; triCt < m_vecIndices.size(); triCt++)
{ {
m_vecIndices[triCt] = newPos[m_vecIndices[triCt]]; m_vecIndices[triCt] = newPos[m_vecIndices[triCt]];
} }

View File

@ -1,32 +1,33 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_PagedVolume_H__ #ifndef __PolyVox_PagedVolume_H__
#define __PolyVox_PagedVolume_H__ #define __PolyVox_PagedVolume_H__
#include "PolyVox/BaseVolume.h" #include "BaseVolume.h"
#include "PolyVox/Region.h" #include "Region.h"
#include "PolyVox/Vector.h" #include "Vector.h"
#include <limits> #include <limits>
#include <cstdlib> //For abort() #include <cstdlib> //For abort()
@ -40,72 +41,18 @@ freely, subject to the following restrictions:
namespace PolyVox namespace PolyVox
{ {
/// The PagedVolume class provides a memory efficient method of storing voxel data while also allowing fast access and modification. /// This class provide a volume implementation which avoids storing all the data in memory at all times. Instead it breaks the volume
/// down into a set of chunks and moves these into and out of memory on demand. This means it is much more memory efficient than the
/// RawVolume, but may also be slower and is more complicated We encourage uses to work with RawVolume initially, and then switch to
/// PagedVolume once they have a larger application and/or a better understanding of PolyVox.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// A PagedVolume is essentially a 3D array in which each element (or <i>voxel</i>) is identified by a three dimensional (x,y,z) coordinate.
/// We use the PagedVolume class to store our data in an efficient way, and it is the input to many of the algorithms (such as the surface
/// extractors) which form the heart of PolyVox. The PagedVolume class is templatised so that different types of data can be stored within each voxel.
/// ///
/// Basic usage /// The PagedVolume makes use of a Pager which defines the source and/or destination for data paged into and out of memory. PolyVox
/// ----------- /// comes with an example FilePager though users can also implement their own approaches. For example, the Pager could instead stream
/// data from a network connection or generate it procedurally on demand.
/// ///
/// The following code snippet shows how to construct a volume and demonstrates basic usage: /// A consequence of this paging approach is that (unlike the RawVolume) the PagedVolume does not need to have a predefined size. After
/// /// the volume has been created you can begin acessing voxels anywhere in space and the required data will be created automatically.
/// \code
/// PagedVolume<int> volume(Region(Vector3DInt32(0,0,0), Vector3DInt32(63,127,255)));
/// volume.setVoxel(15, 90, 42, int(5));
/// std::cout << "Voxel at (15, 90, 42) has value: " << volume.getVoxel(15, 90, 42) << std::endl;
/// std::cout << "Width = " << volume.getWidth() << ", Height = " << volume.getHeight() << ", Depth = " << volume.getDepth() << std::endl;
/// \endcode
///
/// The PagedVolume constructor takes a Region as a parameter. This specifies the valid range of voxels which can be held in the volume, so in this
/// particular case the valid voxel positions are (0,0,0) to (63, 127, 255). The result of attempts to access voxels outside this range will result
/// are defined by the WrapMode). PolyVox also has support for near infinite volumes which will be discussed later.
///
/// Access to individual voxels is provided via the setVoxel() and getVoxel() member functions. Advanced users may also be interested in
/// the Sampler nested class for faster read-only access to a large number of voxels.
///
/// Lastly the example prints out some properties of the PagedVolume. Note that the dimentsions getWidth(), getHeight(), and getDepth() are inclusive, such
/// that the width is 64 when the range of valid x coordinates goes from 0 to 63.
///
/// Data Representaion
/// ------------------
/// If stored carelessly, volume data can take up a huge amount of memory. For example, a volume of dimensions 1024x1024x1024 with
/// 1 byte per voxel will require 1GB of memory if stored in an uncompressed form. Natuarally our PagedVolume class is much more efficient
/// than this and it is worth understanding (at least at a high level) the approach which is used.
///
/// Essentially, the PagedVolume class stores its data as a collection of chunks. Each of these chunk is much smaller than the whole volume,
/// for example a typical size might be 32x32x32 voxels (though is is configurable by the user). In this case, a 256x512x1024 volume
/// would contain 8x16x32 = 4096 chunks. Typically these chunks do not need to all be in memory all the time, and the Pager class can
/// be used to control how they are loaded and unloaded. This mechanism allows a
/// potentially unlimited amount of data to be loaded, provided the user is able to take responsibility for storing any data which PolyVox
/// cannot fit in memory, and then returning it back to PolyVox on demand. For example, the user might choose to temporarily store this data
/// on disk or stream it to a remote database.
///
/// Essentially you are providing an extension to the PagedVolume class - a way for data to be stored once PolyVox has run out of memory for it. Note
/// that you don't actually have to do anything with the data - you could simply decide that once it gets removed from memory it doesn't matter
/// anymore.
///
/// Cache-aware traversal
/// ---------------------
/// *NOTE: This needs updating for PagedVolume rather than the old LargeVolume*
/// You might be suprised at just how many cache misses can occur when you traverse the volume in a naive manner. Consider a 1024x1024x1024 volume
/// with chunks of size 32x32x32. And imagine you iterate over this volume with a simple three-level for loop which iterates over x, the y, then z.
/// If you start at position (0,0,0) then ny the time you reach position (1023,0,0) you have touched 1024 voxels along one edge of the volume and
/// have pulled 32 chunks into the cache. By the time you reach (1023,1023,0) you have hit 1024x1024 voxels and pulled 32x32 chunks into the cache.
/// You are now ready to touch voxel (0,0,1) which is right next to where you started, but unless your cache is at least 32x32 chunks large then this
/// initial chunk has already been cleared from the cache.
///
/// Ensuring you have a large enough cache size can obviously help the above situation, but you might also consider iterating over the voxels in a
/// different order. For example, if you replace your three-level loop with a six-level loop then you can first process all the voxels between (0,0,0)
/// and (31,31,31), then process all the voxels between (32,0,0) and (63,0,0), and so forth. Using this approach you will have no cache misses even
/// is your cache size is only one. Of course the logic is more complex, but writing code in such a cache-aware manner may be beneficial in some situations.
///
/// Threading
/// ---------
/// The PagedVolume class does not make any guarentees about thread safety. You should ensure that all accesses are performed from the same thread.
/// This is true even if you are only reading data from the volume, as concurrently reading from different threads can invalidate the contents
/// of the chunk cache (amoung other problems).
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
class PagedVolume : public BaseVolume<VoxelType> class PagedVolume : public BaseVolume<VoxelType>
@ -113,7 +60,7 @@ namespace PolyVox
public: public:
/// The PagedVolume stores it data as a set of Chunk instances which can be loaded and unloaded as memory requirements dictate. /// The PagedVolume stores it data as a set of Chunk instances which can be loaded and unloaded as memory requirements dictate.
class Chunk; class Chunk;
/// The Pager class is responsible for the loading and unloading of Chunks, and can be overridden by the user. /// The Pager class is responsible for the loading and unloading of Chunks, and can be subclassed by the user.
class Pager; class Pager;
class Chunk class Chunk
@ -127,11 +74,14 @@ namespace PolyVox
VoxelType* getData(void) const; VoxelType* getData(void) const;
uint32_t getDataSizeInBytes(void) const; uint32_t getDataSizeInBytes(void) const;
VoxelType getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const; VoxelType getVoxel(uint32_t uXPos, uint32_t uYPos, uint32_t uZPos) const;
VoxelType getVoxel(const Vector3DUint16& v3dPos) const; VoxelType getVoxel(const Vector3DUint16& v3dPos) const;
void setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue); void setVoxel(uint32_t uXPos, uint32_t uYPos, uint32_t uZPos, VoxelType tValue);
void setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue); void setVoxel(const Vector3DUint16& v3dPos, VoxelType tValue);
void changeLinearOrderingToMorton(void);
void changeMortonOrderingToLinear(void);
private: private:
/// Private copy constructor to prevent accisdental copying /// Private copy constructor to prevent accisdental copying
@ -183,7 +133,7 @@ namespace PolyVox
//in the future //in the future
//typedef Volume<VoxelType> VolumeOfVoxelType; //Workaround for GCC/VS2010 differences. //typedef Volume<VoxelType> VolumeOfVoxelType; //Workaround for GCC/VS2010 differences.
//class Sampler : public VolumeOfVoxelType::template Sampler< PagedVolume<VoxelType> > //class Sampler : public VolumeOfVoxelType::template Sampler< PagedVolume<VoxelType> >
#ifndef SWIG #ifndef SWIG
#if defined(_MSC_VER) #if defined(_MSC_VER)
class Sampler : public BaseVolume<VoxelType>::Sampler< PagedVolume<VoxelType> > //This line works on VS2010 class Sampler : public BaseVolume<VoxelType>::Sampler< PagedVolume<VoxelType> > //This line works on VS2010
#else #else
@ -194,8 +144,6 @@ namespace PolyVox
Sampler(PagedVolume<VoxelType>* volume); Sampler(PagedVolume<VoxelType>* volume);
~Sampler(); ~Sampler();
/// \deprecated
POLYVOX_DEPRECATED VoxelType getSubSampledVoxel(uint8_t uLevel) const;
inline VoxelType getVoxel(void) const; inline VoxelType getVoxel(void) const;
void setPosition(const Vector3DInt32& v3dNewPos); void setPosition(const Vector3DInt32& v3dNewPos);
@ -243,52 +191,37 @@ namespace PolyVox
private: private:
//Other current position information //Other current position information
VoxelType* mCurrentVoxel; VoxelType* mCurrentVoxel;
uint16_t m_uXPosInChunk;
uint16_t m_uYPosInChunk;
uint16_t m_uZPosInChunk;
// This should ideally be const, but that prevent automatic generation of an assignment operator (https://goo.gl/Sn7KpZ).
// We could provide one manually, but it's currently unused so there is no real test for if it works. I'm putting
// together a new release at the moment so I'd rathern not make 'risky' changes.
uint16_t m_uChunkSideLengthMinusOne;
}; };
#endif #endif // SWIG
public: public:
/// Constructor for creating a fixed size volume. /// Constructor for creating a fixed size volume.
PagedVolume PagedVolume(Pager* pPager, uint32_t uTargetMemoryUsageInBytes = 256 * 1024 * 1024, uint16_t uChunkSideLength = 32);
(
const Region& regValid,
Pager* pPager = nullptr,
uint16_t uChunkSideLength = 32
);
/// Destructor /// Destructor
~PagedVolume(); ~PagedVolume();
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates /// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
template <WrapMode eWrapMode> VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder = VoxelType()) const;
/// Gets a voxel at the position given by a 3D vector /// Gets a voxel at the position given by a 3D vector
template <WrapMode eWrapMode> VoxelType getVoxel(const Vector3DInt32& v3dPos) const;
VoxelType getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder = VoxelType()) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const;
/// Gets a voxel at the position given by a 3D vector
VoxelType getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode = WrapModes::Validate, VoxelType tBorder = VoxelType()) const;
/// Gets a voxel at the position given by <tt>x,y,z</tt> coordinates
POLYVOX_DEPRECATED VoxelType getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const;
/// Gets a voxel at the position given by a 3D vector
POLYVOX_DEPRECATED VoxelType getVoxelAt(const Vector3DInt32& v3dPos) const;
/// Sets the number of chunks for which uncompressed data is stored
void setMemoryUsageLimit(uint32_t uMemoryUsageInBytes);
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates /// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); void setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue);
/// Sets the voxel at the position given by a 3D vector /// Sets the voxel at the position given by a 3D vector
void setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode = WrapModes::Validate); void setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue);
/// Sets the voxel at the position given by <tt>x,y,z</tt> coordinates
bool setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue);
/// Sets the voxel at the position given by a 3D vector
bool setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue);
/// Tries to ensure that the voxels within the specified Region are loaded into memory. /// Tries to ensure that the voxels within the specified Region are loaded into memory.
void prefetch(Region regPrefetch); void prefetch(Region regPrefetch);
/// Ensures that any voxels within the specified Region are removed from memory.
void flush(Region regFlush);
/// Removes all voxels from memory /// Removes all voxels from memory
void flushAll(); void flushAll();
@ -303,64 +236,43 @@ namespace PolyVox
PagedVolume& operator=(const PagedVolume& rhs); PagedVolume& operator=(const PagedVolume& rhs);
private: private:
bool canReuseLastAccessedChunk(int32_t iChunkX, int32_t iChunkY, int32_t iChunkZ) const;
Chunk* getChunk(int32_t uChunkX, int32_t uChunkY, int32_t uChunkZ) const;
// FIXME - We can probably ove this into the constructor // Storing these properties individually has proved to be faster than keeping
void initialise(); // them in a Vector3DInt32 as it avoids constructions and comparison overheads.
// They are also at the start of the class in the hope that they will be pulled
// into cache - I've got no idea if this actually makes a difference.
mutable int32_t m_v3dLastAccessedChunkX = 0;
mutable int32_t m_v3dLastAccessedChunkY = 0;
mutable int32_t m_v3dLastAccessedChunkZ = 0;
mutable Chunk* m_pLastAccessedChunk = nullptr;
// A trick to implement specialization of template member functions in template classes. See http://stackoverflow.com/a/4951057 mutable uint32_t m_uTimestamper = 0;
template <WrapMode eWrapMode>
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const;
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Validate>, VoxelType tBorder) const;
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Clamp>, VoxelType tBorder) const;
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Border>, VoxelType tBorder) const;
VoxelType getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, VoxelType tBorder) const;
std::shared_ptr<Chunk> getChunk(int32_t uChunkX, int32_t uChunkY, int32_t uChunkZ) const; uint32_t m_uChunkCountLimit = 0;
void purgeNullPtrsFromAllChunks(void) const; // Chunks are stored in the following array which is used as a hash-table. Conventional wisdom is that such a hash-table
// should not be more than half full to avoid conflicts, and a practical chunk size seems to be 64^3. With this configuration
// The chunk data is stored in the pair of maps below. This will often hold the same set of chunks but there are occasions // there can be up to 32768*64^3 = 8 gigavoxels (with each voxel perhaps being many bytes). This should effectively make use
// when they can differ (more on that in a moment). The main store is the set of 'recently used chunks' which holds shared_ptr's // of even high end machines. Of course, the user can choose to limit the memory usage in which case much less of the chunk
// to the chunk data. When memory is low chunks can be removed from this list and, assuming there are no more references to // array will actually be used. None-the-less, we have chosen to use a fixed size array (rather than a vector) as it appears to
// them, they will be deleted. However, it is also possible that a Sampler is pointing at a given chunk, and in this case the // be slightly faster (probably due to the extra pointer indirection in a vector?) and the actual size of this array should
// reference counting will ensure that the chunk survives until the sampler has finished with it. // just be 1Mb or so.
// static const uint32_t uChunkArraySize = 65536;
// However, this leaves us open to a subtle bug. If a chunk is removed from the recently used set, continues to exist due to a mutable std::unique_ptr< Chunk > m_arrayChunks[uChunkArraySize];
// sampler using it, and then the user tries to access it through the volume interface, then the volume will page the chunk
// back in (not knowing the sampler still has it). This would result in two chunks in memory with the same position is space.
// To avoid this, the 'all chunks' set tracks chunks with are used by the volume *and/or* the samplers. It holds weak pointers
// so does not cause chunks to persist.
//
// TODO: Do we really need maps here? It means we are storing the chunk positions in the map, but they are also stored in the
// chunks themselves (so they can be passed to the pager from the chunks destructor). Can we use a set here? What is a better approach?
typedef std::unordered_map<Vector3DInt32, std::weak_ptr< Chunk > > WeakPtrChunkMap;
mutable WeakPtrChunkMap m_pAllChunks;
typedef std::unordered_map<Vector3DInt32, std::shared_ptr< Chunk > > SharedPtrChunkMap;
mutable SharedPtrChunkMap m_pRecentlyUsedChunks;
mutable uint32_t m_uTimestamper;
mutable Vector3DInt32 m_v3dLastAccessedChunkPos;
mutable std::shared_ptr<Chunk> m_pLastAccessedChunk;
uint32_t m_uChunkCountLimit;
// The size of the volume
Region m_regValidRegionInChunks;
// The size of the chunks // The size of the chunks
uint16_t m_uChunkSideLength; uint16_t m_uChunkSideLength;
uint8_t m_uChunkSideLengthPower; uint8_t m_uChunkSideLengthPower;
int32_t m_iChunkMask;
Pager* m_pPager; Pager* m_pPager = nullptr;
// Enough to make sure a chunks and it's neighbours can be loaded, with a few to spare.
const uint32_t uMinPracticalNoOfChunks = 32;
// Should prevent multi-gigabyte volumes when chunk sizes are reasonable.
const uint32_t uMaxPracticalNoOfChunks = 32768;
}; };
} }
#include "PolyVox/PagedVolume.inl" #include "PagedVolume.inl"
#include "PolyVox/PagedVolumeChunk.inl" #include "PagedVolumeChunk.inl"
#include "PolyVox/PagedVolumeSampler.inl" #include "PagedVolumeSampler.inl"
#endif //__PolyVox_PagedVolume_H__ #endif //__PolyVox_PagedVolume_H__

View File

@ -1,27 +1,28 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "PolyVox/Impl/ErrorHandling.h" #include "Impl/ErrorHandling.h"
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
@ -30,62 +31,43 @@ namespace PolyVox
{ {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// This constructor creates a volume with a fixed size which is specified as a parameter. By default this constructor will not enable paging but you can override this if desired. If you do wish to enable paging then you are required to provide the call back function (see the other PagedVolume constructor). /// This constructor creates a volume with a fixed size which is specified as a parameter. By default this constructor will not enable paging but you can override this if desired. If you do wish to enable paging then you are required to provide the call back function (see the other PagedVolume constructor).
/// \param regValid Specifies the minimum and maximum valid voxel positions. /// \param pPager Called by PolyVox to load and unload data on demand.
/// \param dataRequiredHandler The callback function which will be called when PolyVox tries to use data which is not currently in momory. /// \param uTargetMemoryUsageInBytes The upper limit to how much memory this PagedVolume should aim to use.
/// \param dataOverflowHandler The callback function which will be called when PolyVox has too much data and needs to remove some from memory.
/// \param bPagingEnabled Controls whether or not paging is enabled for this PagedVolume.
/// \param uChunkSideLength The size of the chunks making up the volume. Small chunks will compress/decompress faster, but there will also be more of them meaning voxel access could be slower. /// \param uChunkSideLength The size of the chunks making up the volume. Small chunks will compress/decompress faster, but there will also be more of them meaning voxel access could be slower.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
PagedVolume<VoxelType>::PagedVolume PagedVolume<VoxelType>::PagedVolume(Pager* pPager, uint32_t uTargetMemoryUsageInBytes, uint16_t uChunkSideLength)
( :BaseVolume<VoxelType>()
const Region& regValid, , m_uChunkSideLength(uChunkSideLength)
Pager* pPager, , m_pPager(pPager)
uint16_t uChunkSideLength
)
:BaseVolume<VoxelType>(regValid)
{ {
m_uChunkSideLength = uChunkSideLength; // Validation of parameters
m_pPager = pPager; POLYVOX_THROW_IF(!pPager, std::invalid_argument, "You must provide a valid pager when constructing a PagedVolume");
POLYVOX_THROW_IF(uTargetMemoryUsageInBytes < 1 * 1024 * 1024, std::invalid_argument, "Target memory usage is too small to be practical");
POLYVOX_THROW_IF(m_uChunkSideLength == 0, std::invalid_argument, "Chunk side length cannot be zero.");
POLYVOX_THROW_IF(m_uChunkSideLength > 256, std::invalid_argument, "Chunk size is too large to be practical.");
POLYVOX_THROW_IF(!isPowerOf2(m_uChunkSideLength), std::invalid_argument, "Chunk side length must be a power of two.");
if (m_pPager) // Used to perform multiplications and divisions by bit shifting.
{ m_uChunkSideLengthPower = logBase2(m_uChunkSideLength);
// If the user is creating a vast (almost infinite) volume then we can bet they will be // Use to perform modulo by bit operations
// expecting a high memory usage and will want a fair number of chunks to play around with. m_iChunkMask = m_uChunkSideLength - 1;
if (regValid == Region::MaxRegion())
{
m_uChunkCountLimit = 1024;
}
else
{
// Otherwise we try to choose a chunk count to avoid too much thrashing, particularly when iterating
// over the whole volume. This means at least enough chunks to cover one edge of the volume, and ideally
// enough for a whole face. Which face? Longest edge by shortest edge seems like a reasonable guess.
uint32_t longestSide = (std::max)(regValid.getWidthInVoxels(), (std::max)(regValid.getHeightInVoxels(), regValid.getDepthInVoxels()));
uint32_t shortestSide = (std::min)(regValid.getWidthInVoxels(), (std::min)(regValid.getHeightInVoxels(), regValid.getDepthInVoxels()));
longestSide /= m_uChunkSideLength; // Calculate the number of chunks based on the memory limit and the size of each chunk.
shortestSide /= m_uChunkSideLength; uint32_t uChunkSizeInBytes = PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(m_uChunkSideLength);
m_uChunkCountLimit = uTargetMemoryUsageInBytes / uChunkSizeInBytes;
m_uChunkCountLimit = longestSide * shortestSide; // Enforce sensible limits on the number of chunks.
} const uint32_t uMinPracticalNoOfChunks = 32; // Enough to make sure a chunks and it's neighbours can be loaded, with a few to spare.
} const uint32_t uMaxPracticalNoOfChunks = uChunkArraySize / 2; // A hash table should only become half-full to avoid too many clashes.
else POLYVOX_LOG_WARNING_IF(m_uChunkCountLimit < uMinPracticalNoOfChunks, "Requested memory usage limit of ",
{ uTargetMemoryUsageInBytes / (1024 * 1024), "Mb is too low and cannot be adhered to.");
// If there is no pager provided then we set the chunk limit to the maximum
// value to ensure the system never attempts to page chunks out of memory.
m_uChunkCountLimit = (std::numeric_limits<uint32_t>::max)();
}
// Make sure the calculated chunk limit is within practical bounds
m_uChunkCountLimit = (std::max)(m_uChunkCountLimit, uMinPracticalNoOfChunks); m_uChunkCountLimit = (std::max)(m_uChunkCountLimit, uMinPracticalNoOfChunks);
m_uChunkCountLimit = (std::min)(m_uChunkCountLimit, uMaxPracticalNoOfChunks); m_uChunkCountLimit = (std::min)(m_uChunkCountLimit, uMaxPracticalNoOfChunks);
uint32_t uChunkSizeInBytes = PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(m_uChunkSideLength); // Inform the user about the chosen memory configuration.
POLYVOX_LOG_DEBUG("Memory usage limit for volume initially set to " << (m_uChunkCountLimit * uChunkSizeInBytes) / (1024 * 1024) POLYVOX_LOG_DEBUG("Memory usage limit for volume now set to ", (m_uChunkCountLimit * uChunkSizeInBytes) / (1024 * 1024),
<< "Mb (" << m_uChunkCountLimit << " chunks of " << uChunkSizeInBytes / 1024 << "Kb each)."); "Mb (", m_uChunkCountLimit, " chunks of ", uChunkSizeInBytes / 1024, "Kb each).");
initialise();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -98,7 +80,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
PagedVolume<VoxelType>::PagedVolume(const PagedVolume<VoxelType>& /*rhs*/) PagedVolume<VoxelType>::PagedVolume(const PagedVolume<VoxelType>& /*rhs*/)
{ {
POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented for performance reasons."); POLYVOX_THROW(not_implemented, "Volume copy constructor not implemented to prevent accidental copying.");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -120,43 +102,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
PagedVolume<VoxelType>& PagedVolume<VoxelType>::operator=(const PagedVolume<VoxelType>& /*rhs*/) PagedVolume<VoxelType>& PagedVolume<VoxelType>::operator=(const PagedVolume<VoxelType>& /*rhs*/)
{ {
POLYVOX_THROW(not_implemented, "Volume assignment operator not implemented for performance reasons."); POLYVOX_THROW(not_implemented, "Volume assignment operator not implemented to prevent accidental copying.");
}
////////////////////////////////////////////////////////////////////////////////
/// This version of the function requires the wrap mode to be specified as a
/// template parameter, which can provide better performance.
/// \param uXPos The \c x position of the voxel
/// \param uYPos The \c y position of the voxel
/// \param uZPos The \c z position of the voxel
/// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume.
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
template <WrapMode eWrapMode>
VoxelType PagedVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tBorder) const
{
// Simply call through to the real implementation
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<eWrapMode>(), tBorder);
}
////////////////////////////////////////////////////////////////////////////////
/// This version of the function requires the wrap mode to be specified as a
/// template parameter, which can provide better performance.
/// \param uXPos The \c x position of the voxel
/// \param uYPos The \c y position of the voxel
/// \param uZPos The \c z position of the voxel
/// \tparam eWrapMode Specifies the behaviour when the requested position is outside of the volume.
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
template <WrapMode eWrapMode>
VoxelType PagedVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos, VoxelType tBorder) const
{
// Simply call through to the real implementation
return getVoxel<eWrapMode>(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tBorder);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -165,139 +111,44 @@ namespace PolyVox
/// \param uXPos The \c x position of the voxel /// \param uXPos The \c x position of the voxel
/// \param uYPos The \c y position of the voxel /// \param uYPos The \c y position of the voxel
/// \param uZPos The \c z position of the voxel /// \param uZPos The \c z position of the voxel
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
/// \return The voxel value /// \return The voxel value
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapMode eWrapMode, VoxelType tBorder) const VoxelType PagedVolume<VoxelType>::getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
{
switch(eWrapMode)
{
case WrapModes::Validate:
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::Validate>(), tBorder);
case WrapModes::Clamp:
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::Clamp>(), tBorder);
case WrapModes::Border:
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::Border>(), tBorder);
case WrapModes::AssumeValid:
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder);
default:
// Should never happen
POLYVOX_ASSERT(false, "Invalid wrap mode");
return VoxelType();
}
}
////////////////////////////////////////////////////////////////////////////////
/// This version of the function is provided so that the wrap mode does not need
/// to be specified as a template parameter, as it may be confusing to some users.
/// \param v3dPos The 3D position of the voxel
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
/// \param tBorder The border value to use if the wrap mode is set to 'Border'.
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos, WrapMode eWrapMode, VoxelType tBorder) const
{
return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), eWrapMode, tBorder);
}
////////////////////////////////////////////////////////////////////////////////
/// \param uXPos The \c x position of the voxel
/// \param uYPos The \c y position of the voxel
/// \param uZPos The \c z position of the voxel
/// \return The voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::getVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos) const
{
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)))
{ {
const int32_t chunkX = uXPos >> m_uChunkSideLengthPower; const int32_t chunkX = uXPos >> m_uChunkSideLengthPower;
const int32_t chunkY = uYPos >> m_uChunkSideLengthPower; const int32_t chunkY = uYPos >> m_uChunkSideLengthPower;
const int32_t chunkZ = uZPos >> m_uChunkSideLengthPower; const int32_t chunkZ = uZPos >> m_uChunkSideLengthPower;
const uint16_t xOffset = static_cast<uint16_t>(uXPos - (chunkX << m_uChunkSideLengthPower)); const uint16_t xOffset = static_cast<uint16_t>(uXPos & m_iChunkMask);
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (chunkY << m_uChunkSideLengthPower)); const uint16_t yOffset = static_cast<uint16_t>(uYPos & m_iChunkMask);
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (chunkZ << m_uChunkSideLengthPower)); const uint16_t zOffset = static_cast<uint16_t>(uZPos & m_iChunkMask);
auto pChunk = getChunk(chunkX, chunkY, chunkZ); auto pChunk = canReuseLastAccessedChunk(chunkX, chunkY, chunkZ) ? m_pLastAccessedChunk : getChunk(chunkX, chunkY, chunkZ);
return pChunk->getVoxel(xOffset, yOffset, zOffset); return pChunk->getVoxel(xOffset, yOffset, zOffset);
} }
else
{
return this->getBorderValue();
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// This version of the function is provided so that the wrap mode does not need
/// to be specified as a template parameter, as it may be confusing to some users.
/// \param v3dPos The 3D position of the voxel /// \param v3dPos The 3D position of the voxel
/// \return The voxel value /// \return The voxel value
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::getVoxelAt(const Vector3DInt32& v3dPos) const VoxelType PagedVolume<VoxelType>::getVoxel(const Vector3DInt32& v3dPos) const
{ {
return getVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); return getVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ());
}
////////////////////////////////////////////////////////////////////////////////
/// Increasing the size of the chunk cache will increase memory but may improve performance.
/// You may want to set this to a large value (e.g. 1024) when you are first loading your
/// volume data and then set it to a smaller value (e.g.64) for general processing.
/// \param uMaxNumberOfChunks The number of chunks for which uncompressed data can be cached.
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
void PagedVolume<VoxelType>::setMemoryUsageLimit(uint32_t uMemoryUsageInBytes)
{
POLYVOX_THROW_IF(!m_pPager, invalid_operation, "You cannot limit the memory usage of the volume because it was created without a pager attached.");
// Calculate the number of chunks based on the memory limit and the size of each chunk.
uint32_t uChunkSizeInBytes = PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(m_uChunkSideLength);
m_uChunkCountLimit = uMemoryUsageInBytes / uChunkSizeInBytes;
// We need at least a few chunks available to avoid thrashing, and in pratice there will probably be hundreds.
POLYVOX_LOG_WARNING_IF(m_uChunkCountLimit < uMinPracticalNoOfChunks, "Requested memory usage limit of "
<< uMemoryUsageInBytes / (1024 * 1024) << "Mb is too low and cannot be adhered to.");
m_uChunkCountLimit = (std::max)(m_uChunkCountLimit, uMinPracticalNoOfChunks);
m_uChunkCountLimit = (std::min)(m_uChunkCountLimit, uMaxPracticalNoOfChunks);
// If the new limit is less than the number of chunks already loaded then the easiest solution is to flush and start loading again.
if (m_pRecentlyUsedChunks.size() > m_uChunkCountLimit)
{
flushAll();
}
POLYVOX_LOG_DEBUG("Memory usage limit for volume now set to " << (m_uChunkCountLimit * uChunkSizeInBytes) / (1024 * 1024)
<< "Mb (" << m_uChunkCountLimit << " chunks of " << uChunkSizeInBytes / 1024 << "Kb each).");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// \param uXPos the \c x position of the voxel /// \param uXPos the \c x position of the voxel
/// \param uYPos the \c y position of the voxel /// \param uYPos the \c y position of the voxel
/// \param uZPos the \c z position of the voxel /// \param uZPos the \c z position of the voxel
/// \param tValue the value to which the voxel will be set
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
/// This must be set to 'None' or 'DontCheck'. Other wrap modes cannot be used when writing to volume data.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
void PagedVolume<VoxelType>::setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue, WrapMode eWrapMode) void PagedVolume<VoxelType>::setVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue)
{ {
if((eWrapMode != WrapModes::Validate) && (eWrapMode != WrapModes::AssumeValid))
{
POLYVOX_THROW(std::invalid_argument, "Invalid wrap mode in call to setVoxel(). It must be 'None' or 'DontCheck'.");
}
// This validation is skipped if the wrap mode is 'DontCheck'
if(eWrapMode == WrapModes::Validate)
{
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false)
{
POLYVOX_THROW(std::out_of_range, "Position is outside valid region");
}
}
const int32_t chunkX = uXPos >> m_uChunkSideLengthPower; const int32_t chunkX = uXPos >> m_uChunkSideLengthPower;
const int32_t chunkY = uYPos >> m_uChunkSideLengthPower; const int32_t chunkY = uYPos >> m_uChunkSideLengthPower;
const int32_t chunkZ = uZPos >> m_uChunkSideLengthPower; const int32_t chunkZ = uZPos >> m_uChunkSideLengthPower;
@ -306,63 +157,21 @@ namespace PolyVox
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (chunkY << m_uChunkSideLengthPower)); const uint16_t yOffset = static_cast<uint16_t>(uYPos - (chunkY << m_uChunkSideLengthPower));
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (chunkZ << m_uChunkSideLengthPower)); const uint16_t zOffset = static_cast<uint16_t>(uZPos - (chunkZ << m_uChunkSideLengthPower));
auto pChunk = getChunk(chunkX, chunkY, chunkZ); auto pChunk = canReuseLastAccessedChunk(chunkX, chunkY, chunkZ) ? m_pLastAccessedChunk : getChunk(chunkX, chunkY, chunkZ);
pChunk->setVoxelAt(xOffset, yOffset, zOffset, tValue);
pChunk->setVoxel(xOffset, yOffset, zOffset, tValue);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// \param v3dPos the 3D position of the voxel /// \param v3dPos the 3D position of the voxel
/// \param tValue the value to which the voxel will be set /// \param tValue the value to which the voxel will be set
/// \param eWrapMode Specifies the behaviour when the requested position is outside of the volume.
/// This must be set to 'None' or 'DontCheck'. Other wrap modes cannot be used when writing to volume data.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> template <typename VoxelType>
void PagedVolume<VoxelType>::setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue, WrapMode eWrapMode) void PagedVolume<VoxelType>::setVoxel(const Vector3DInt32& v3dPos, VoxelType tValue)
{ {
setVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue, eWrapMode); setVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
} }
////////////////////////////////////////////////////////////////////////////////
/// \param uXPos the \c x position of the voxel
/// \param uYPos the \c y position of the voxel
/// \param uZPos the \c z position of the voxel
/// \param tValue the value to which the voxel will be set
/// \return whether the requested position is inside the volume
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
bool PagedVolume<VoxelType>::setVoxelAt(int32_t uXPos, int32_t uYPos, int32_t uZPos, VoxelType tValue)
{
// PolyVox does not throw an exception when a voxel is out of range. Please see 'Error Handling' in the User Manual.
POLYVOX_ASSERT(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)), "Position is outside valid region");
const int32_t chunkX = uXPos >> m_uChunkSideLengthPower;
const int32_t chunkY = uYPos >> m_uChunkSideLengthPower;
const int32_t chunkZ = uZPos >> m_uChunkSideLengthPower;
const uint16_t xOffset = static_cast<uint16_t>(uXPos - (chunkX << m_uChunkSideLengthPower));
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (chunkY << m_uChunkSideLengthPower));
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (chunkZ << m_uChunkSideLengthPower));
auto pChunk = getChunk(chunkX, chunkY, chunkZ);
pChunk->setVoxelAt(xOffset, yOffset, zOffset, tValue);
//Return true to indicate that we modified a voxel.
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// \param v3dPos the 3D position of the voxel
/// \param tValue the value to which the voxel will be set
/// \return whether the requested position is inside the volume
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
bool PagedVolume<VoxelType>::setVoxelAt(const Vector3DInt32& v3dPos, VoxelType tValue)
{
return setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// Note that if the memory usage limit is not large enough to support the region this function will only load part of the region. In this case it is undefined which parts will actually be loaded. If all the voxels in the given region are already loaded, this function will not do anything. Other voxels might be unloaded to make space for the new voxels. /// Note that if the memory usage limit is not large enough to support the region this function will only load part of the region. In this case it is undefined which parts will actually be loaded. If all the voxels in the given region are already loaded, this function will not do anything. Other voxels might be unloaded to make space for the new voxels.
/// \param regPrefetch The Region of voxels to prefetch into memory. /// \param regPrefetch The Region of voxels to prefetch into memory.
@ -372,13 +181,13 @@ namespace PolyVox
{ {
// Convert the start and end positions into chunk space coordinates // Convert the start and end positions into chunk space coordinates
Vector3DInt32 v3dStart; Vector3DInt32 v3dStart;
for(int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
v3dStart.setElement(i, regPrefetch.getLowerCorner().getElement(i) >> m_uChunkSideLengthPower); v3dStart.setElement(i, regPrefetch.getLowerCorner().getElement(i) >> m_uChunkSideLengthPower);
} }
Vector3DInt32 v3dEnd; Vector3DInt32 v3dEnd;
for(int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
v3dEnd.setElement(i, regPrefetch.getUpperCorner().getElement(i) >> m_uChunkSideLengthPower); v3dEnd.setElement(i, regPrefetch.getUpperCorner().getElement(i) >> m_uChunkSideLengthPower);
} }
@ -386,17 +195,17 @@ namespace PolyVox
// Ensure we don't page in more chunks than the volume can hold. // Ensure we don't page in more chunks than the volume can hold.
Region region(v3dStart, v3dEnd); Region region(v3dStart, v3dEnd);
uint32_t uNoOfChunks = static_cast<uint32_t>(region.getWidthInVoxels() * region.getHeightInVoxels() * region.getDepthInVoxels()); uint32_t uNoOfChunks = static_cast<uint32_t>(region.getWidthInVoxels() * region.getHeightInVoxels() * region.getDepthInVoxels());
POLYVOX_LOG_WARNING_IF(uNoOfChunks > m_uChunkCountLimit, "Attempting to prefetch more than the maximum number of chunks."); POLYVOX_LOG_WARNING_IF(uNoOfChunks > m_uChunkCountLimit, "Attempting to prefetch more than the maximum number of chunks (this will cause thrashing).");
uNoOfChunks = (std::min)(uNoOfChunks, m_uChunkCountLimit); uNoOfChunks = (std::min)(uNoOfChunks, m_uChunkCountLimit);
// Loops over the specified positions and touch the corresponding chunks. // Loops over the specified positions and touch the corresponding chunks.
for(int32_t x = v3dStart.getX(); x <= v3dEnd.getX(); x++) for (int32_t x = v3dStart.getX(); x <= v3dEnd.getX(); x++)
{ {
for(int32_t y = v3dStart.getY(); y <= v3dEnd.getY(); y++) for (int32_t y = v3dStart.getY(); y <= v3dEnd.getY(); y++)
{ {
for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++) for (int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++)
{ {
getChunk(x,y,z); getChunk(x, y, z);
} }
} }
} }
@ -408,198 +217,124 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void PagedVolume<VoxelType>::flushAll() void PagedVolume<VoxelType>::flushAll()
{ {
POLYVOX_LOG_WARNING_IF(!m_pPager, "Data discarded by flush operation as no pager is attached."); // Clear this pointer as all chunks are about to be removed.
// Clear this pointer so it doesn't hang on to any chunks.
m_pLastAccessedChunk = nullptr; m_pLastAccessedChunk = nullptr;
// Erase all the most recently used chunks. // Erase all the most recently used chunks.
m_pRecentlyUsedChunks.clear(); for (uint32_t uIndex = 0; uIndex < uChunkArraySize; uIndex++)
// Remove deleted chunks from the list of all loaded chunks.
purgeNullPtrsFromAllChunks();
// If there are still some chunks left then this is a cause for concern. Perhaps samplers are holding on to them?
POLYVOX_LOG_WARNING_IF(m_pAllChunks.size() > 0, "Chunks still exist after performing flushAll()! Perhaps you have samplers attached?");
}
////////////////////////////////////////////////////////////////////////////////
/// Removes all voxels in the specified Region from memory, and calls dataOverflowHandler() to ensure the application has a chance to store the data. It is possible that there are no voxels loaded in the Region, in which case the function will have no effect.
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
void PagedVolume<VoxelType>::flush(Region regFlush)
{ {
POLYVOX_LOG_WARNING_IF(!m_pPager, "Data discarded by flush operation as no pager is attached."); m_arrayChunks[uIndex] = nullptr;
// Clear this pointer so it doesn't hang on to any chunks.
m_pLastAccessedChunk = nullptr;
// Convert the start and end positions into chunk space coordinates
Vector3DInt32 v3dStart;
for(int i = 0; i < 3; i++)
{
v3dStart.setElement(i, regFlush.getLowerCorner().getElement(i) >> m_uChunkSideLengthPower);
} }
Vector3DInt32 v3dEnd;
for(int i = 0; i < 3; i++)
{
v3dEnd.setElement(i, regFlush.getUpperCorner().getElement(i) >> m_uChunkSideLengthPower);
}
// Loops over the specified positions and delete the corresponding chunks.
for(int32_t x = v3dStart.getX(); x <= v3dEnd.getX(); x++)
{
for(int32_t y = v3dStart.getY(); y <= v3dEnd.getY(); y++)
{
for(int32_t z = v3dStart.getZ(); z <= v3dEnd.getZ(); z++)
{
m_pRecentlyUsedChunks.erase(Vector3DInt32(x, y, z));
}
}
}
m_pLastAccessedChunk = nullptr;
// We might now have so null pointers in the 'all chunks' list so clean them up.
purgeNullPtrsFromAllChunks();
}
////////////////////////////////////////////////////////////////////////////////
/// This function should probably be made internal...
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
void PagedVolume<VoxelType>::initialise()
{
//Validate parameters
if(m_uChunkSideLength == 0)
{
POLYVOX_THROW(std::invalid_argument, "Chunk side length cannot be zero.");
}
if(!isPowerOf2(m_uChunkSideLength))
{
POLYVOX_THROW(std::invalid_argument, "Chunk side length must be a power of two.");
}
m_uTimestamper = 0;
m_v3dLastAccessedChunkPos = Vector3DInt32(0,0,0); //There are no invalid positions, but initially the m_pLastAccessedChunk pointer will be null;
m_pLastAccessedChunk = nullptr;
//Compute the chunk side length
m_uChunkSideLengthPower = logBase2(m_uChunkSideLength);
m_regValidRegionInChunks.setLowerX(this->m_regValidRegion.getLowerX() >> m_uChunkSideLengthPower);
m_regValidRegionInChunks.setLowerY(this->m_regValidRegion.getLowerY() >> m_uChunkSideLengthPower);
m_regValidRegionInChunks.setLowerZ(this->m_regValidRegion.getLowerZ() >> m_uChunkSideLengthPower);
m_regValidRegionInChunks.setUpperX(this->m_regValidRegion.getUpperX() >> m_uChunkSideLengthPower);
m_regValidRegionInChunks.setUpperY(this->m_regValidRegion.getUpperY() >> m_uChunkSideLengthPower);
m_regValidRegionInChunks.setUpperZ(this->m_regValidRegion.getUpperZ() >> m_uChunkSideLengthPower);
//setMaxNumberOfChunks(m_uChunkCountLimit);
//Clear the previous data
m_pRecentlyUsedChunks.clear();
//Other properties we might find useful later
this->m_uLongestSideLength = (std::max)((std::max)(this->getWidth(),this->getHeight()),this->getDepth());
this->m_uShortestSideLength = (std::min)((std::min)(this->getWidth(),this->getHeight()),this->getDepth());
this->m_fDiagonalLength = sqrtf(static_cast<float>(this->getWidth() * this->getWidth() + this->getHeight() * this->getHeight() + this->getDepth() * this->getDepth()));
} }
template <typename VoxelType> template <typename VoxelType>
std::shared_ptr<typename PagedVolume<VoxelType>::Chunk> PagedVolume<VoxelType>::getChunk(int32_t uChunkX, int32_t uChunkY, int32_t uChunkZ) const bool PagedVolume<VoxelType>::canReuseLastAccessedChunk(int32_t iChunkX, int32_t iChunkY, int32_t iChunkZ) const
{ {
Vector3DInt32 v3dChunkPos(uChunkX, uChunkY, uChunkZ); return ((iChunkX == m_v3dLastAccessedChunkX) &&
(iChunkY == m_v3dLastAccessedChunkY) &&
//Check if we have the same chunk as last time, if so there's no need to even update (iChunkZ == m_v3dLastAccessedChunkZ) &&
//the time stamp. If we updated it everytime then that would be every time we touched (m_pLastAccessedChunk));
//a voxel, which would overflow a uint32_t and require us to use a uint64_t instead.
//This check should also provide a significant speed boost as usually it is true.
if((v3dChunkPos == m_v3dLastAccessedChunkPos) && (m_pLastAccessedChunk != 0))
{
return m_pLastAccessedChunk;
} }
// The chunk was not the same as last time, but we can now hope it is in the set of most recently used chunks. template <typename VoxelType>
std::shared_ptr<typename PagedVolume<VoxelType>::Chunk> pChunk = nullptr; typename PagedVolume<VoxelType>::Chunk* PagedVolume<VoxelType>::getChunk(int32_t uChunkX, int32_t uChunkY, int32_t uChunkZ) const
typename SharedPtrChunkMap::iterator itChunk = m_pRecentlyUsedChunks.find(v3dChunkPos);
// Check whether the chunk was found.
if ((itChunk) != m_pRecentlyUsedChunks.end())
{ {
// The chunk was found so we can use it. Chunk* pChunk = nullptr;
pChunk = itChunk->second;
POLYVOX_ASSERT(pChunk, "Recent chunk list shold never contain a null pointer."); // We generate a 16-bit hash here and assume this matches the range available in the chunk
// array. The assert here is just to make sure we take care if change this in the future.
static_assert(uChunkArraySize == 65536, "Chunk array size has changed, check if the hash calculation needs updating.");
// Extract the lower five bits from each position component.
const uint32_t uChunkXLowerBits = static_cast<uint32_t>(uChunkX & 0x1F);
const uint32_t uChunkYLowerBits = static_cast<uint32_t>(uChunkY & 0x1F);
const uint32_t uChunkZLowerBits = static_cast<uint32_t>(uChunkZ & 0x1F);
// Combine then to form a 15-bit hash of the position. Also shift by one to spread the values out in the whole 16-bit space.
const uint32_t iPosisionHash = (((uChunkXLowerBits)) | ((uChunkYLowerBits) << 5) | ((uChunkZLowerBits) << 10) << 1);
// Starting at the position indicated by the hash, and then search through the whole array looking for a chunk with the correct
// position. In most cases we expect to find it in the first place we look. Note that this algorithm is slow in the case that
// the chunk is not found because the whole array has to be searched, but in this case we are going to have to page the data in
// from an external source which is likely to be slow anyway.
uint32_t iIndex = iPosisionHash;
do
{
if (m_arrayChunks[iIndex])
{
Vector3DInt32& entryPos = m_arrayChunks[iIndex]->m_v3dChunkSpacePosition;
if (entryPos.getX() == uChunkX && entryPos.getY() == uChunkY && entryPos.getZ() == uChunkZ)
{
pChunk = m_arrayChunks[iIndex].get();
pChunk->m_uChunkLastAccessed = ++m_uTimestamper;
break;
}
} }
if (!pChunk) iIndex++;
{ iIndex %= uChunkArraySize;
// Although it's not in our recently use chunks, there's some (slim) chance that it } while (iIndex != iPosisionHash); // Keep searching until we get back to our start position.
// exists in the list of all loaded chunks, because a sampler may be holding on to it.
typename WeakPtrChunkMap::iterator itWeakChunk = m_pAllChunks.find(v3dChunkPos);
if (itWeakChunk != m_pAllChunks.end())
{
// We've found an entry in the 'all chunks' list, but it can be null. This happens if a sampler was the
// last thing to be keeping it alive and then the sampler let it go. In this case we remove it from the
// list, and it will get added again soon when we page it in and fill it with valid data.
if (itWeakChunk->second.expired())
{
m_pAllChunks.erase(itWeakChunk);
}
else
{
// The chunk is valid. We know it's not in the recently used list (we checked earlier) so it should be added.
pChunk = std::shared_ptr< PagedVolume<VoxelType>::Chunk >(itWeakChunk->second);
m_pRecentlyUsedChunks.insert(std::make_pair(v3dChunkPos, pChunk));
}
}
}
// If we still haven't found the chunk then it's time to create a new one and page it in from disk. // If we still haven't found the chunk then it's time to create a new one and page it in from disk.
if (!pChunk) if (!pChunk)
{ {
// The chunk was not found so we will create a new one. // The chunk was not found so we will create a new one.
pChunk = std::make_shared< PagedVolume<VoxelType>::Chunk >(v3dChunkPos, m_uChunkSideLength, m_pPager); Vector3DInt32 v3dChunkPos(uChunkX, uChunkY, uChunkZ);
pChunk = new PagedVolume<VoxelType>::Chunk(v3dChunkPos, m_uChunkSideLength, m_pPager);
pChunk->m_uChunkLastAccessed = ++m_uTimestamper; // Important, as we may soon delete the oldest chunk
// As we are loading a new chunk we should try to ensure we don't go over our target memory usage. // Store the chunk at the appropriate place in out chunk array. Ideally this place is
bool erasedChunk = false; // given by the hash, otherwise we do a linear search for the next available location
while (m_pRecentlyUsedChunks.size() + 1 > m_uChunkCountLimit) // +1 ready for new chunk we will add next. // We always expect to find a free place because we aim to keep the array only half full.
uint32_t iIndex = iPosisionHash;
bool bInsertedSucessfully = false;
do
{ {
// This should never hit, because it should not have been possible for if (m_arrayChunks[iIndex] == nullptr)
// the user to limit the number of chunks if they did not provide a pager.
POLYVOX_ASSERT(m_pPager, "A valid pager is required to limit number of chunks");
// Find the least recently used chunk. Hopefully this isn't too slow.
typename SharedPtrChunkMap::iterator itUnloadChunk = m_pRecentlyUsedChunks.begin();
for (typename SharedPtrChunkMap::iterator i = m_pRecentlyUsedChunks.begin(); i != m_pRecentlyUsedChunks.end(); i++)
{ {
if (i->second->m_uChunkLastAccessed < itUnloadChunk->second->m_uChunkLastAccessed) m_arrayChunks[iIndex] = std::move(std::unique_ptr< Chunk >(pChunk));
bInsertedSucessfully = true;
break;
}
iIndex++;
iIndex %= uChunkArraySize;
} while (iIndex != iPosisionHash); // Keep searching until we get back to our start position.
// This should never really happen unless we are failing to keep our number of active chunks
// significantly under the target amount. Perhaps if chunks are 'pinned' for threading purposes?
POLYVOX_THROW_IF(!bInsertedSucessfully, std::logic_error, "No space in chunk array for new chunk.");
// As we have added a chunk we may have exceeded our target chunk limit. Search through the array to
// determine how many chunks we have, as well as finding the oldest timestamp. Note that this is potentially
// wasteful and we may instead wish to track how many chunks we have and/or delete a chunk at random (or
// just check e.g. 10 and delete the oldest of those) but we'll see if this is a bottleneck first. Paging
// the data in is probably more expensive.
uint32_t uChunkCount = 0;
uint32_t uOldestChunkIndex = 0;
uint32_t uOldestChunkTimestamp = std::numeric_limits<uint32_t>::max();
for (uint32_t uIndex = 0; uIndex < uChunkArraySize; uIndex++)
{ {
itUnloadChunk = i; if (m_arrayChunks[uIndex])
}
}
// Erase the least recently used chunk
m_pRecentlyUsedChunks.erase(itUnloadChunk);
erasedChunk = true;
}
// If we've deleted any chunks from the recently used list then this
// seems like a good place to purge the 'all chunks' list as well.
if (erasedChunk)
{ {
purgeNullPtrsFromAllChunks(); uChunkCount++;
if (m_arrayChunks[uIndex]->m_uChunkLastAccessed < uOldestChunkTimestamp)
{
uOldestChunkTimestamp = m_arrayChunks[uIndex]->m_uChunkLastAccessed;
uOldestChunkIndex = uIndex;
}
}
} }
// Add our new chunk to the maps. // Check if we have too many chunks, and delete the oldest if so.
m_pAllChunks.insert(std::make_pair(v3dChunkPos, pChunk)); if (uChunkCount > m_uChunkCountLimit)
m_pRecentlyUsedChunks.insert(std::make_pair(v3dChunkPos, pChunk)); {
m_arrayChunks[uOldestChunkIndex] = nullptr;
}
} }
pChunk->m_uChunkLastAccessed = ++m_uTimestamper;
m_pLastAccessedChunk = pChunk; m_pLastAccessedChunk = pChunk;
m_v3dLastAccessedChunkPos = v3dChunkPos; m_v3dLastAccessedChunkX = uChunkX;
m_v3dLastAccessedChunkY = uChunkY;
m_v3dLastAccessedChunkZ = uChunkZ;
return pChunk; return pChunk;
} }
@ -610,89 +345,18 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
uint32_t PagedVolume<VoxelType>::calculateSizeInBytes(void) uint32_t PagedVolume<VoxelType>::calculateSizeInBytes(void)
{ {
// Purge null chunks so we know that all chunks are used. uint32_t uChunkCount = 0;
purgeNullPtrsFromAllChunks(); for (uint32_t uIndex = 0; uIndex < uChunkArraySize; uIndex++)
{
if (m_arrayChunks[uIndex])
{
uChunkCount++;
}
}
// Note: We disregard the size of the other class members as they are likely to be very small compared to the size of the // Note: We disregard the size of the other class members as they are likely to be very small compared to the size of the
// allocated voxel data. This also keeps the reported size as a power of two, which makes other memory calculations easier. // allocated voxel data. This also keeps the reported size as a power of two, which makes other memory calculations easier.
return PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(m_uChunkSideLength) * m_pAllChunks.size(); return PagedVolume<VoxelType>::Chunk::calculateSizeInBytes(m_uChunkSideLength) * uChunkCount;
}
template <typename VoxelType>
void PagedVolume<VoxelType>::purgeNullPtrsFromAllChunks(void) const
{
for (auto chunkIter = m_pAllChunks.begin(); chunkIter != m_pAllChunks.end();)
{
if (chunkIter->second.expired())
{
chunkIter = m_pAllChunks.erase(chunkIter);
}
else
{
chunkIter++;
}
}
}
template <typename VoxelType>
template <WrapMode eWrapMode>
VoxelType PagedVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<eWrapMode>, VoxelType tBorder) const
{
// This function should never be called because one of the specialisations should always match.
POLYVOX_ASSERT(false, "This function is not implemented and should never be called!");
}
template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Validate>, VoxelType tBorder) const
{
if(this->m_regValidRegion.containsPoint(Vector3DInt32(uXPos, uYPos, uZPos)) == false)
{
POLYVOX_THROW(std::out_of_range, "Position is outside valid region");
}
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder); // No wrapping as we've just validated the position.
}
template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Clamp>, VoxelType tBorder) const
{
//Perform clamping
uXPos = (std::max)(uXPos, this->m_regValidRegion.getLowerX());
uYPos = (std::max)(uYPos, this->m_regValidRegion.getLowerY());
uZPos = (std::max)(uZPos, this->m_regValidRegion.getLowerZ());
uXPos = (std::min)(uXPos, this->m_regValidRegion.getUpperX());
uYPos = (std::min)(uYPos, this->m_regValidRegion.getUpperY());
uZPos = (std::min)(uZPos, this->m_regValidRegion.getUpperZ());
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder); // No wrapping as we've just validated the position.
}
template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::Border>, VoxelType tBorder) const
{
if(this->m_regValidRegion.containsPoint(uXPos, uYPos, uZPos))
{
return getVoxelImpl(uXPos, uYPos, uZPos, WrapModeType<WrapModes::AssumeValid>(), tBorder); // No wrapping as we've just validated the position.
}
else
{
return tBorder;
}
}
template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::getVoxelImpl(int32_t uXPos, int32_t uYPos, int32_t uZPos, WrapModeType<WrapModes::AssumeValid>, VoxelType /*tBorder*/) const
{
const int32_t chunkX = uXPos >> m_uChunkSideLengthPower;
const int32_t chunkY = uYPos >> m_uChunkSideLengthPower;
const int32_t chunkZ = uZPos >> m_uChunkSideLengthPower;
const uint16_t xOffset = static_cast<uint16_t>(uXPos - (chunkX << m_uChunkSideLengthPower));
const uint16_t yOffset = static_cast<uint16_t>(uYPos - (chunkY << m_uChunkSideLengthPower));
const uint16_t zOffset = static_cast<uint16_t>(uZPos - (chunkZ << m_uChunkSideLengthPower));
auto pChunk = getChunk(chunkX, chunkY, chunkZ);
return pChunk->getVoxel(xOffset, yOffset, zOffset);
} }
} }

View File

@ -1,40 +1,45 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2013 David Williams and Matthew Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "PolyVox/Impl/Utility.h" #include "Impl/Morton.h"
#include "Impl/Utility.h"
namespace PolyVox namespace PolyVox
{ {
template <typename VoxelType> template <typename VoxelType>
PagedVolume<VoxelType>::Chunk::Chunk(Vector3DInt32 v3dPosition, uint16_t uSideLength, Pager* pPager) PagedVolume<VoxelType>::Chunk::Chunk(Vector3DInt32 v3dPosition, uint16_t uSideLength, Pager* pPager)
:m_uChunkLastAccessed(0) :m_uChunkLastAccessed(0)
,m_bDataModified(true) , m_bDataModified(true)
,m_tData(0) , m_tData(0)
,m_uSideLength(0) , m_uSideLength(0)
,m_uSideLengthPower(0) , m_uSideLengthPower(0)
,m_pPager(pPager) , m_pPager(pPager)
,m_v3dChunkSpacePosition(v3dPosition) , m_v3dChunkSpacePosition(v3dPosition)
{ {
POLYVOX_ASSERT(m_pPager, "No valid pager supplied to chunk constructor.");
POLYVOX_ASSERT(uSideLength <= 256, "Chunk side length cannot be greater than 256.");
// Compute the side length // Compute the side length
m_uSideLength = uSideLength; m_uSideLength = uSideLength;
m_uSideLengthPower = logBase2(uSideLength); m_uSideLengthPower = logBase2(uSideLength);
@ -44,21 +49,17 @@ namespace PolyVox
m_tData = new VoxelType[uNoOfVoxels]; m_tData = new VoxelType[uNoOfVoxels];
// Pass the chunk to the Pager to give it a chance to initialise it with any data // Pass the chunk to the Pager to give it a chance to initialise it with any data
if (m_pPager)
{
// From the coordinates of the chunk we deduce the coordinates of the contained voxels. // From the coordinates of the chunk we deduce the coordinates of the contained voxels.
Vector3DInt32 v3dLower = m_v3dChunkSpacePosition * static_cast<int32_t>(m_uSideLength); Vector3DInt32 v3dLower = m_v3dChunkSpacePosition * static_cast<int32_t>(m_uSideLength);
Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uSideLength - 1, m_uSideLength - 1, m_uSideLength - 1); Vector3DInt32 v3dUpper = v3dLower + Vector3DInt32(m_uSideLength - 1, m_uSideLength - 1, m_uSideLength - 1);
Region reg(v3dLower, v3dUpper); Region reg(v3dLower, v3dUpper);
// A valid pager is normally present - this check is mostly to ease unit testing.
if (m_pPager)
{
// Page the data in // Page the data in
m_pPager->pageIn(reg, this); m_pPager->pageIn(reg, this);
} }
else
{
// Just fill with zeros
std::fill(m_tData, m_tData + uNoOfVoxels, VoxelType());
}
// We'll use this later to decide if data needs to be paged out again. // We'll use this later to decide if data needs to be paged out again.
m_bDataModified = false; m_bDataModified = false;
@ -67,7 +68,7 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
PagedVolume<VoxelType>::Chunk::~Chunk() PagedVolume<VoxelType>::Chunk::~Chunk()
{ {
if (m_pPager && m_bDataModified) if (m_bDataModified && m_pPager)
{ {
// From the coordinates of the chunk we deduce the coordinates of the contained voxels. // From the coordinates of the chunk we deduce the coordinates of the contained voxels.
Vector3DInt32 v3dLower = m_v3dChunkSpacePosition * static_cast<int32_t>(m_uSideLength); Vector3DInt32 v3dLower = m_v3dChunkSpacePosition * static_cast<int32_t>(m_uSideLength);
@ -94,7 +95,7 @@ namespace PolyVox
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Chunk::getVoxel(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const VoxelType PagedVolume<VoxelType>::Chunk::getVoxel(uint32_t uXPos, uint32_t uYPos, uint32_t uZPos) const
{ {
// This code is not usually expected to be called by the user, with the exception of when implementing paging // This code is not usually expected to be called by the user, with the exception of when implementing paging
// of uncompressed data. It's a performance critical code path so we use asserts rather than exceptions. // of uncompressed data. It's a performance critical code path so we use asserts rather than exceptions.
@ -103,12 +104,9 @@ namespace PolyVox
POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the chunk"); POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the chunk");
POLYVOX_ASSERT(m_tData, "No uncompressed data - chunk must be decompressed before accessing voxels."); POLYVOX_ASSERT(m_tData, "No uncompressed data - chunk must be decompressed before accessing voxels.");
return m_tData uint32_t index = morton256_x[uXPos] | morton256_y[uYPos] | morton256_z[uZPos];
[
uXPos + return m_tData[index];
uYPos * m_uSideLength +
uZPos * m_uSideLength * m_uSideLength
];
} }
template <typename VoxelType> template <typename VoxelType>
@ -118,7 +116,7 @@ namespace PolyVox
} }
template <typename VoxelType> template <typename VoxelType>
void PagedVolume<VoxelType>::Chunk::setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue) void PagedVolume<VoxelType>::Chunk::setVoxel(uint32_t uXPos, uint32_t uYPos, uint32_t uZPos, VoxelType tValue)
{ {
// This code is not usually expected to be called by the user, with the exception of when implementing paging // This code is not usually expected to be called by the user, with the exception of when implementing paging
// of uncompressed data. It's a performance critical code path so we use asserts rather than exceptions. // of uncompressed data. It's a performance critical code path so we use asserts rather than exceptions.
@ -127,20 +125,17 @@ namespace PolyVox
POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the chunk"); POLYVOX_ASSERT(uZPos < m_uSideLength, "Supplied position is outside of the chunk");
POLYVOX_ASSERT(m_tData, "No uncompressed data - chunk must be decompressed before accessing voxels."); POLYVOX_ASSERT(m_tData, "No uncompressed data - chunk must be decompressed before accessing voxels.");
m_tData uint32_t index = morton256_x[uXPos] | morton256_y[uYPos] | morton256_z[uZPos];
[
uXPos + m_tData[index] = tValue;
uYPos * m_uSideLength +
uZPos * m_uSideLength * m_uSideLength
] = tValue;
this->m_bDataModified = true; this->m_bDataModified = true;
} }
template <typename VoxelType> template <typename VoxelType>
void PagedVolume<VoxelType>::Chunk::setVoxelAt(const Vector3DUint16& v3dPos, VoxelType tValue) void PagedVolume<VoxelType>::Chunk::setVoxel(const Vector3DUint16& v3dPos, VoxelType tValue)
{ {
setVoxelAt(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue); setVoxel(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ(), tValue);
} }
template <typename VoxelType> template <typename VoxelType>
@ -158,4 +153,65 @@ namespace PolyVox
uint32_t uSizeInBytes = uSideLength * uSideLength * uSideLength * sizeof(VoxelType); uint32_t uSizeInBytes = uSideLength * uSideLength * uSideLength * sizeof(VoxelType);
return uSizeInBytes; return uSizeInBytes;
} }
// This convienience function exists for historical reasons. Chunks used to store their data in 'linear' order but now we
// use Morton encoding. Users who still have data in linear order (on disk, in databases, etc) will need to call this function
// if they load the data in by memcpy()ing it via the raw pointer. On the other hand, if they set the data using setVoxel()
// then the ordering is automatically handled correctly.
template <typename VoxelType>
void PagedVolume<VoxelType>::Chunk::changeLinearOrderingToMorton(void)
{
VoxelType* pTempBuffer = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength];
// We should prehaps restructure this loop. From: https://fgiesen.wordpress.com/2011/01/17/texture-tiling-and-swizzling/
//
// "There's two basic ways to structure the actual swizzling: either you go through the (linear) source image in linear order,
// writing in (somewhat) random order, or you iterate over the output data, picking the right source pixel for each target
// location. The former is more natural, especially when updating subrects of the destination texture (the source pixels still
// consist of one linear sequence of bytes per line; the pattern of destination addresses written is considerably more
// complicated), but the latter is usually much faster, especially if the source image data is in cached memory while the output
// data resides in non-cached write-combined memory where non-sequential writes are expensive."
//
// This is something to consider if profiling identifies it as a hotspot.
for (uint16_t z = 0; z < m_uSideLength; z++)
{
for (uint16_t y = 0; y < m_uSideLength; y++)
{
for (uint16_t x = 0; x < m_uSideLength; x++)
{
uint32_t uLinearIndex = x + y * m_uSideLength + z * m_uSideLength * m_uSideLength;
uint32_t uMortonIndex = morton256_x[x] | morton256_y[y] | morton256_z[z];
pTempBuffer[uMortonIndex] = m_tData[uLinearIndex];
}
}
}
std::memcpy(m_tData, pTempBuffer, getDataSizeInBytes());
delete[] pTempBuffer;
}
// Like the above function, this is provided fot easing backwards compatibility. In Cubiquity we have some
// old databases which use linear ordering, and we need to continue to save such data in linear order.
template <typename VoxelType>
void PagedVolume<VoxelType>::Chunk::changeMortonOrderingToLinear(void)
{
VoxelType* pTempBuffer = new VoxelType[m_uSideLength * m_uSideLength * m_uSideLength];
for (uint16_t z = 0; z < m_uSideLength; z++)
{
for (uint16_t y = 0; y < m_uSideLength; y++)
{
for (uint16_t x = 0; x < m_uSideLength; x++)
{
uint32_t uLinearIndex = x + y * m_uSideLength + z * m_uSideLength * m_uSideLength;
uint32_t uMortonIndex = morton256_x[x] | morton256_y[y] | morton256_z[z];
pTempBuffer[uLinearIndex] = m_tData[uMortonIndex];
}
}
}
std::memcpy(m_tData, pTempBuffer, getDataSizeInBytes());
delete[] pTempBuffer;
}
} }

View File

@ -1,38 +1,54 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2005-2009 David Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#define CAN_GO_NEG_X(val) ((val > this->mVolume->getEnclosingRegion().getLowerX()) && (val % this->mVolume->m_uChunkSideLength != 0)) #include <array>
#define CAN_GO_POS_X(val) ((val < this->mVolume->getEnclosingRegion().getUpperX()) && ((val + 1) % this->mVolume->m_uChunkSideLength != 0))
#define CAN_GO_NEG_Y(val) ((val > this->mVolume->getEnclosingRegion().getLowerY()) && (val % this->mVolume->m_uChunkSideLength != 0)) #define CAN_GO_NEG_X(val) (val > 0)
#define CAN_GO_POS_Y(val) ((val < this->mVolume->getEnclosingRegion().getUpperY()) && ((val + 1) % this->mVolume->m_uChunkSideLength != 0)) #define CAN_GO_POS_X(val) (val < this->m_uChunkSideLengthMinusOne)
#define CAN_GO_NEG_Z(val) ((val > this->mVolume->getEnclosingRegion().getLowerZ()) && (val % this->mVolume->m_uChunkSideLength != 0)) #define CAN_GO_NEG_Y(val) (val > 0)
#define CAN_GO_POS_Z(val) ((val < this->mVolume->getEnclosingRegion().getUpperZ()) && ((val + 1) % this->mVolume->m_uChunkSideLength != 0)) #define CAN_GO_POS_Y(val) (val < this->m_uChunkSideLengthMinusOne)
#define CAN_GO_NEG_Z(val) (val > 0)
#define CAN_GO_POS_Z(val) (val < this->m_uChunkSideLengthMinusOne)
#define NEG_X_DELTA (-(deltaX[this->m_uXPosInChunk-1]))
#define POS_X_DELTA (deltaX[this->m_uXPosInChunk])
#define NEG_Y_DELTA (-(deltaY[this->m_uYPosInChunk-1]))
#define POS_Y_DELTA (deltaY[this->m_uYPosInChunk])
#define NEG_Z_DELTA (-(deltaZ[this->m_uZPosInChunk-1]))
#define POS_Z_DELTA (deltaZ[this->m_uZPosInChunk])
namespace PolyVox namespace PolyVox
{ {
// These precomputed offset are used to determine how much we move our pointer by to move a single voxel in the x, y, or z direction given an x, y, or z starting position inside a chunk.
// More information in this discussion: https://bitbucket.org/volumesoffun/polyvox/issue/61/experiment-with-morton-ordering-of-voxel
static const std::array<int32_t, 256> deltaX = { 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 3511, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 28087, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 3511, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 224695, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 3511, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 28087, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 3511, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 1797559, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 3511, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 28087, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 3511, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 224695, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 3511, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 28087, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1, 3511, 1, 7, 1, 55, 1, 7, 1, 439, 1, 7, 1, 55, 1, 7, 1 };
static const std::array<int32_t, 256> deltaY = { 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 7022, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 56174, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 7022, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 449390, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 7022, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 56174, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 7022, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 3595118, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 7022, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 56174, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 7022, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 449390, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 7022, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 56174, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2, 7022, 2, 14, 2, 110, 2, 14, 2, 878, 2, 14, 2, 110, 2, 14, 2 };
static const std::array<int32_t, 256> deltaZ = { 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 14044, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 112348, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 14044, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 898780, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 14044, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 112348, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 14044, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 7190236, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 14044, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 112348, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 14044, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 898780, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 14044, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 112348, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4, 14044, 4, 28, 4, 220, 4, 28, 4, 1756, 4, 28, 4, 220, 4, 28, 4 };
template <typename VoxelType> template <typename VoxelType>
PagedVolume<VoxelType>::Sampler::Sampler(PagedVolume<VoxelType>* volume) PagedVolume<VoxelType>::Sampler::Sampler(PagedVolume<VoxelType>* volume)
:BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >(volume) :BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >(volume), m_uChunkSideLengthMinusOne(volume->m_uChunkSideLength - 1)
{ {
} }
@ -41,56 +57,11 @@ namespace PolyVox
{ {
} }
template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::getSubSampledVoxel(uint8_t uLevel) const
{
if(uLevel == 0)
{
return getVoxel();
}
else if(uLevel == 1)
{
VoxelType tValue = getVoxel();
tValue = (std::min)(tValue, peekVoxel1px0py0pz());
tValue = (std::min)(tValue, peekVoxel0px1py0pz());
tValue = (std::min)(tValue, peekVoxel1px1py0pz());
tValue = (std::min)(tValue, peekVoxel0px0py1pz());
tValue = (std::min)(tValue, peekVoxel1px0py1pz());
tValue = (std::min)(tValue, peekVoxel0px1py1pz());
tValue = (std::min)(tValue, peekVoxel1px1py1pz());
return tValue;
}
else
{
const uint8_t uSize = 1 << uLevel;
VoxelType tValue = (std::numeric_limits<VoxelType>::max)();
for(uint8_t z = 0; z < uSize; ++z)
{
for(uint8_t y = 0; y < uSize; ++y)
{
for(uint8_t x = 0; x < uSize; ++x)
{
tValue = (std::min)(tValue, this->mVolume->getVoxelAt(this->mXPosInVolume + x, this->mYPosInVolume + y, this->mZPosInVolume + z));
}
}
}
return tValue;
}
}
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::getVoxel(void) const VoxelType PagedVolume<VoxelType>::Sampler::getVoxel(void) const
{
if(this->isCurrentPositionValid())
{ {
return *mCurrentVoxel; return *mCurrentVoxel;
} }
else
{
return this->getVoxelImpl(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume);
}
}
template <typename VoxelType> template <typename VoxelType>
void PagedVolume<VoxelType>::Sampler::setPosition(const Vector3DInt32& v3dNewPos) void PagedVolume<VoxelType>::Sampler::setPosition(const Vector3DInt32& v3dNewPos)
@ -105,43 +76,25 @@ namespace PolyVox
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::setPosition(xPos, yPos, zPos); BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::setPosition(xPos, yPos, zPos);
// Then we update the voxel pointer // Then we update the voxel pointer
if(this->isCurrentPositionValid())
{
const int32_t uXChunk = this->mXPosInVolume >> this->mVolume->m_uChunkSideLengthPower; const int32_t uXChunk = this->mXPosInVolume >> this->mVolume->m_uChunkSideLengthPower;
const int32_t uYChunk = this->mYPosInVolume >> this->mVolume->m_uChunkSideLengthPower; const int32_t uYChunk = this->mYPosInVolume >> this->mVolume->m_uChunkSideLengthPower;
const int32_t uZChunk = this->mZPosInVolume >> this->mVolume->m_uChunkSideLengthPower; const int32_t uZChunk = this->mZPosInVolume >> this->mVolume->m_uChunkSideLengthPower;
const uint16_t uXPosInChunk = static_cast<uint16_t>(this->mXPosInVolume - (uXChunk << this->mVolume->m_uChunkSideLengthPower)); m_uXPosInChunk = static_cast<uint16_t>(this->mXPosInVolume - (uXChunk << this->mVolume->m_uChunkSideLengthPower));
const uint16_t uYPosInChunk = static_cast<uint16_t>(this->mYPosInVolume - (uYChunk << this->mVolume->m_uChunkSideLengthPower)); m_uYPosInChunk = static_cast<uint16_t>(this->mYPosInVolume - (uYChunk << this->mVolume->m_uChunkSideLengthPower));
const uint16_t uZPosInChunk = static_cast<uint16_t>(this->mZPosInVolume - (uZChunk << this->mVolume->m_uChunkSideLengthPower)); m_uZPosInChunk = static_cast<uint16_t>(this->mZPosInVolume - (uZChunk << this->mVolume->m_uChunkSideLengthPower));
const uint32_t uVoxelIndexInChunk = uXPosInChunk + uint32_t uVoxelIndexInChunk = morton256_x[m_uXPosInChunk] | morton256_y[m_uYPosInChunk] | morton256_z[m_uZPosInChunk];
uYPosInChunk * this->mVolume->m_uChunkSideLength +
uZPosInChunk * this->mVolume->m_uChunkSideLength * this->mVolume->m_uChunkSideLength;
auto pCurrentChunk = this->mVolume->getChunk(uXChunk, uYChunk, uZChunk); auto pCurrentChunk = this->mVolume->canReuseLastAccessedChunk(uXChunk, uYChunk, uZChunk) ?
this->mVolume->m_pLastAccessedChunk : this->mVolume->getChunk(uXChunk, uYChunk, uZChunk);
mCurrentVoxel = pCurrentChunk->m_tData + uVoxelIndexInChunk; mCurrentVoxel = pCurrentChunk->m_tData + uVoxelIndexInChunk;
} }
else
{
mCurrentVoxel = 0;
}
}
template <typename VoxelType> template <typename VoxelType>
bool PagedVolume<VoxelType>::Sampler::setVoxel(VoxelType tValue) bool PagedVolume<VoxelType>::Sampler::setVoxel(VoxelType tValue)
{ {
/*if(m_bIsCurrentPositionValidInX && m_bIsCurrentPositionValidInY && m_bIsCurrentPositionValidInZ)
{
*mCurrentVoxel = tValue;
return true;
}
else
{
return false;
}*/
//Need to think what effect this has on any existing iterators. //Need to think what effect this has on any existing iterators.
POLYVOX_THROW(not_implemented, "This function cannot be used on PagedVolume samplers."); POLYVOX_THROW(not_implemented, "This function cannot be used on PagedVolume samplers.");
return false; return false;
@ -150,17 +103,15 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void PagedVolume<VoxelType>::Sampler::movePositiveX(void) void PagedVolume<VoxelType>::Sampler::movePositiveX(void)
{ {
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags. // Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::movePositiveX(); BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::movePositiveX();
// Then we update the voxel pointer // Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mXPosInVolume) % this->mVolume->m_uChunkSideLength != 0)) if (CAN_GO_POS_X(this->m_uXPosInChunk))
{ {
//No need to compute new chunk. //No need to compute new chunk.
++mCurrentVoxel; mCurrentVoxel += POS_X_DELTA;
this->m_uXPosInChunk++;
} }
else else
{ {
@ -172,17 +123,15 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void PagedVolume<VoxelType>::Sampler::movePositiveY(void) void PagedVolume<VoxelType>::Sampler::movePositiveY(void)
{ {
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags. // Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::movePositiveY(); BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::movePositiveY();
// Then we update the voxel pointer // Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mYPosInVolume) % this->mVolume->m_uChunkSideLength != 0)) if (CAN_GO_POS_Y(this->m_uYPosInChunk))
{ {
//No need to compute new chunk. //No need to compute new chunk.
mCurrentVoxel += this->mVolume->m_uChunkSideLength; mCurrentVoxel += POS_Y_DELTA;
this->m_uYPosInChunk++;
} }
else else
{ {
@ -194,17 +143,15 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void PagedVolume<VoxelType>::Sampler::movePositiveZ(void) void PagedVolume<VoxelType>::Sampler::movePositiveZ(void)
{ {
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags. // Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::movePositiveZ(); BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::movePositiveZ();
// Then we update the voxel pointer // Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mZPosInVolume) % this->mVolume->m_uChunkSideLength != 0)) if (CAN_GO_POS_Z(this->m_uZPosInChunk))
{ {
//No need to compute new chunk. //No need to compute new chunk.
mCurrentVoxel += this->mVolume->m_uChunkSideLength * this->mVolume->m_uChunkSideLength; mCurrentVoxel += POS_Z_DELTA;
this->m_uZPosInChunk++;
} }
else else
{ {
@ -216,17 +163,15 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void PagedVolume<VoxelType>::Sampler::moveNegativeX(void) void PagedVolume<VoxelType>::Sampler::moveNegativeX(void)
{ {
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags. // Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::moveNegativeX(); BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::moveNegativeX();
// Then we update the voxel pointer // Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mXPosInVolume + 1) % this->mVolume->m_uChunkSideLength != 0)) if (CAN_GO_NEG_X(this->m_uXPosInChunk))
{ {
//No need to compute new chunk. //No need to compute new chunk.
--mCurrentVoxel; mCurrentVoxel += NEG_X_DELTA;
this->m_uXPosInChunk--;
} }
else else
{ {
@ -238,17 +183,15 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void PagedVolume<VoxelType>::Sampler::moveNegativeY(void) void PagedVolume<VoxelType>::Sampler::moveNegativeY(void)
{ {
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags. // Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::moveNegativeY(); BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::moveNegativeY();
// Then we update the voxel pointer // Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mYPosInVolume + 1) % this->mVolume->m_uChunkSideLength != 0)) if (CAN_GO_NEG_Y(this->m_uYPosInChunk))
{ {
//No need to compute new chunk. //No need to compute new chunk.
mCurrentVoxel -= this->mVolume->m_uChunkSideLength; mCurrentVoxel += NEG_Y_DELTA;
this->m_uYPosInChunk--;
} }
else else
{ {
@ -260,17 +203,15 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
void PagedVolume<VoxelType>::Sampler::moveNegativeZ(void) void PagedVolume<VoxelType>::Sampler::moveNegativeZ(void)
{ {
// We'll need this in a moment...
bool bIsOldPositionValid = this->isCurrentPositionValid();
// Base version updates position and validity flags. // Base version updates position and validity flags.
BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::moveNegativeZ(); BaseVolume<VoxelType>::template Sampler< PagedVolume<VoxelType> >::moveNegativeZ();
// Then we update the voxel pointer // Then we update the voxel pointer
if((this->isCurrentPositionValid()) && bIsOldPositionValid && ((this->mZPosInVolume + 1) % this->mVolume->m_uChunkSideLength != 0)) if (CAN_GO_NEG_Z(this->m_uZPosInChunk))
{ {
//No need to compute new chunk. //No need to compute new chunk.
mCurrentVoxel -= this->mVolume->m_uChunkSideLength * this->mVolume->m_uChunkSideLength; mCurrentVoxel += NEG_Z_DELTA;
this->m_uZPosInChunk--;
} }
else else
{ {
@ -282,91 +223,91 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1ny1nz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1ny1nz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) if (CAN_GO_NEG_X(this->m_uXPosInChunk) && CAN_GO_NEG_Y(this->m_uYPosInChunk) && CAN_GO_NEG_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel - 1 - this->mVolume->m_uChunkSideLength - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + NEG_X_DELTA + NEG_Y_DELTA + NEG_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume - 1, this->mYPosInVolume - 1, this->mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1ny0pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1ny0pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) ) if (CAN_GO_NEG_X(this->m_uXPosInChunk) && CAN_GO_NEG_Y(this->m_uYPosInChunk))
{ {
return *(mCurrentVoxel - 1 - this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + NEG_X_DELTA + NEG_Y_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume - 1, this->mYPosInVolume - 1, this->mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1ny1pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1ny1pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) if (CAN_GO_NEG_X(this->m_uXPosInChunk) && CAN_GO_NEG_Y(this->m_uYPosInChunk) && CAN_GO_POS_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel - 1 - this->mVolume->m_uChunkSideLength + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + NEG_X_DELTA + NEG_Y_DELTA + POS_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume - 1, this->mYPosInVolume - 1, this->mZPosInVolume + 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx0py1nz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx0py1nz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) if (CAN_GO_NEG_X(this->m_uXPosInChunk) && CAN_GO_NEG_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel - 1 - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + NEG_X_DELTA + NEG_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume - 1, this->mYPosInVolume, this->mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx0py0pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx0py0pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) ) if (CAN_GO_NEG_X(this->m_uXPosInChunk))
{ {
return *(mCurrentVoxel - 1); return *(mCurrentVoxel + NEG_X_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume - 1, this->mYPosInVolume, this->mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx0py1pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx0py1pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) if (CAN_GO_NEG_X(this->m_uXPosInChunk) && CAN_GO_POS_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel - 1 + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + NEG_X_DELTA + POS_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume - 1, this->mYPosInVolume, this->mZPosInVolume + 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1py1nz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1py1nz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) if (CAN_GO_NEG_X(this->m_uXPosInChunk) && CAN_GO_POS_Y(this->m_uYPosInChunk) && CAN_GO_NEG_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel - 1 + this->mVolume->m_uChunkSideLength - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + NEG_X_DELTA + POS_Y_DELTA + NEG_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume - 1, this->mYPosInVolume + 1, this->mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1py0pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1py0pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) ) if (CAN_GO_NEG_X(this->m_uXPosInChunk) && CAN_GO_POS_Y(this->m_uYPosInChunk))
{ {
return *(mCurrentVoxel - 1 + this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + NEG_X_DELTA + POS_Y_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume - 1, this->mYPosInVolume + 1, this->mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1py1pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1nx1py1pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) if (CAN_GO_NEG_X(this->m_uXPosInChunk) && CAN_GO_POS_Y(this->m_uYPosInChunk) && CAN_GO_POS_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel - 1 + this->mVolume->m_uChunkSideLength + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + NEG_X_DELTA + POS_Y_DELTA + POS_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume-1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume - 1, this->mYPosInVolume + 1, this->mZPosInVolume + 1);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -374,91 +315,87 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1ny1nz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1ny1nz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) if (CAN_GO_NEG_Y(this->m_uYPosInChunk) && CAN_GO_NEG_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel - this->mVolume->m_uChunkSideLength - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + NEG_Y_DELTA + NEG_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume - 1, this->mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1ny0pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1ny0pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) ) if (CAN_GO_NEG_Y(this->m_uYPosInChunk))
{ {
return *(mCurrentVoxel - this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + NEG_Y_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume - 1, this->mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1ny1pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1ny1pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) if (CAN_GO_NEG_Y(this->m_uYPosInChunk) && CAN_GO_POS_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel - this->mVolume->m_uChunkSideLength + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + NEG_Y_DELTA + POS_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume - 1, this->mZPosInVolume + 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px0py1nz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px0py1nz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_NEG_Z(this->mZPosInVolume) ) if (CAN_GO_NEG_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + NEG_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px0py0pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px0py0pz(void) const
{
if((this->isCurrentPositionValid()))
{ {
return *mCurrentVoxel; return *mCurrentVoxel;
} }
return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder);
}
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px0py1pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px0py1pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_Z(this->mZPosInVolume) ) if (CAN_GO_POS_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + POS_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume, this->mZPosInVolume + 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1py1nz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1py1nz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) if (CAN_GO_POS_Y(this->m_uYPosInChunk) && CAN_GO_NEG_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel + this->mVolume->m_uChunkSideLength - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + POS_Y_DELTA + NEG_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume + 1, this->mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1py0pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1py0pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) ) if (CAN_GO_POS_Y(this->m_uYPosInChunk))
{ {
return *(mCurrentVoxel + this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + POS_Y_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume + 1, this->mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1py1pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel0px1py1pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) if (CAN_GO_POS_Y(this->m_uYPosInChunk) && CAN_GO_POS_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel + this->mVolume->m_uChunkSideLength + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + POS_Y_DELTA + POS_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume, this->mYPosInVolume + 1, this->mZPosInVolume + 1);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -466,91 +403,91 @@ namespace PolyVox
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1ny1nz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1ny1nz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) if (CAN_GO_POS_X(this->m_uXPosInChunk) && CAN_GO_NEG_Y(this->m_uYPosInChunk) && CAN_GO_NEG_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel + 1 - this->mVolume->m_uChunkSideLength - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + POS_X_DELTA + NEG_Y_DELTA + NEG_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume + 1, this->mYPosInVolume - 1, this->mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1ny0pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1ny0pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) ) if (CAN_GO_POS_X(this->m_uXPosInChunk) && CAN_GO_NEG_Y(this->m_uYPosInChunk))
{ {
return *(mCurrentVoxel + 1 - this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + POS_X_DELTA + NEG_Y_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume + 1, this->mYPosInVolume - 1, this->mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1ny1pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1ny1pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) if (CAN_GO_POS_X(this->m_uXPosInChunk) && CAN_GO_NEG_Y(this->m_uYPosInChunk) && CAN_GO_POS_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel + 1 - this->mVolume->m_uChunkSideLength + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + POS_X_DELTA + NEG_Y_DELTA + POS_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume-1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume + 1, this->mYPosInVolume - 1, this->mZPosInVolume + 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px0py1nz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px0py1nz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) if (CAN_GO_POS_X(this->m_uXPosInChunk) && CAN_GO_NEG_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel + 1 - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + POS_X_DELTA + NEG_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume + 1, this->mYPosInVolume, this->mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px0py0pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px0py0pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) ) if (CAN_GO_POS_X(this->m_uXPosInChunk))
{ {
return *(mCurrentVoxel + 1); return *(mCurrentVoxel + POS_X_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume + 1, this->mYPosInVolume, this->mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px0py1pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px0py1pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) if (CAN_GO_POS_X(this->m_uXPosInChunk) && CAN_GO_POS_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel + 1 + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + POS_X_DELTA + POS_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume + 1, this->mYPosInVolume, this->mZPosInVolume + 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1py1nz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1py1nz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_NEG_Z(this->mZPosInVolume) ) if (CAN_GO_POS_X(this->m_uXPosInChunk) && CAN_GO_POS_Y(this->m_uYPosInChunk) && CAN_GO_NEG_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel + 1 + this->mVolume->m_uChunkSideLength - this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + POS_X_DELTA + POS_Y_DELTA + NEG_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume-1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume + 1, this->mYPosInVolume + 1, this->mZPosInVolume - 1);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1py0pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1py0pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) ) if (CAN_GO_POS_X(this->m_uXPosInChunk) && CAN_GO_POS_Y(this->m_uYPosInChunk))
{ {
return *(mCurrentVoxel + 1 + this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + POS_X_DELTA + POS_Y_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume + 1, this->mYPosInVolume + 1, this->mZPosInVolume);
} }
template <typename VoxelType> template <typename VoxelType>
VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1py1pz(void) const VoxelType PagedVolume<VoxelType>::Sampler::peekVoxel1px1py1pz(void) const
{ {
if((this->isCurrentPositionValid()) && CAN_GO_POS_X(this->mXPosInVolume) && CAN_GO_POS_Y(this->mYPosInVolume) && CAN_GO_POS_Z(this->mZPosInVolume) ) if (CAN_GO_POS_X(this->m_uXPosInChunk) && CAN_GO_POS_Y(this->m_uYPosInChunk) && CAN_GO_POS_Z(this->m_uZPosInChunk))
{ {
return *(mCurrentVoxel + 1 + this->mVolume->m_uChunkSideLength + this->mVolume->m_uChunkSideLength*this->mVolume->m_uChunkSideLength); return *(mCurrentVoxel + POS_X_DELTA + POS_Y_DELTA + POS_Z_DELTA);
} }
return this->mVolume->getVoxel(this->mXPosInVolume+1,this->mYPosInVolume+1,this->mZPosInVolume+1,this->m_eWrapMode, this->m_tBorder); return this->mVolume->getVoxel(this->mXPosInVolume + 1, this->mYPosInVolume + 1, this->mZPosInVolume + 1);
} }
} }
@ -560,3 +497,10 @@ namespace PolyVox
#undef CAN_GO_POS_Y #undef CAN_GO_POS_Y
#undef CAN_GO_NEG_Z #undef CAN_GO_NEG_Z
#undef CAN_GO_POS_Z #undef CAN_GO_POS_Z
#undef NEG_X_DELTA
#undef POS_X_DELTA
#undef NEG_Y_DELTA
#undef POS_Y_DELTA
#undef NEG_Z_DELTA
#undef POS_Z_DELTA

View File

@ -1,30 +1,31 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2013 Matt Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#ifndef __PolyVox_Picking_H__ #ifndef __PolyVox_Picking_H__
#define __PolyVox_Picking_H__ #define __PolyVox_Picking_H__
#include "PolyVox/Vector.h" #include "Vector.h"
namespace PolyVox namespace PolyVox
{ {
@ -33,9 +34,10 @@ namespace PolyVox
*/ */
struct PickResult struct PickResult
{ {
PickResult() : didHit(false) {} PickResult() : didHit(false), hasPreviousVoxel(false) {}
bool didHit; ///< Did the picking operation hit anything bool didHit; ///< Did the picking operation hit anything
Vector3DInt32 hitVoxel; ///< The location of the solid voxel it hit Vector3DInt32 hitVoxel; ///< The location of the solid voxel it hit
bool hasPreviousVoxel; //< Whether there is a previous voxel (there may not be if the raycast started in a solid object).
Vector3DInt32 previousVoxel; ///< The location of the voxel before the one it hit Vector3DInt32 previousVoxel; ///< The location of the voxel before the one it hit
}; };
@ -44,6 +46,6 @@ namespace PolyVox
PickResult pickVoxel(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, const typename VolumeType::VoxelType& emptyVoxelExample); PickResult pickVoxel(VolumeType* volData, const Vector3DFloat& v3dStart, const Vector3DFloat& v3dDirectionAndLength, const typename VolumeType::VoxelType& emptyVoxelExample);
} }
#include "PolyVox/Picking.inl" #include "Picking.inl"
#endif //__PolyVox_Picking_H__ #endif //__PolyVox_Picking_H__

View File

@ -1,27 +1,28 @@
/******************************************************************************* /*******************************************************************************
Copyright (c) 2013 Matt Williams * The MIT License (MIT)
*
This software is provided 'as-is', without any express or implied * Copyright (c) 2015 David Williams and Matthew Williams
warranty. In no event will the authors be held liable for any damages *
arising from the use of this software. * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Permission is granted to anyone to use this software for any purpose, * in the Software without restriction, including without limitation the rights
including commercial applications, and to alter it and redistribute it * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
freely, subject to the following restrictions: * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
1. The origin of this software must not be misrepresented; you must not *
claim that you wrote the original software. If you use this software * The above copyright notice and this permission notice shall be included in all
in a product, an acknowledgment in the product documentation would be * copies or substantial portions of the Software.
appreciated but is not required. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2. Altered source versions must be plainly marked as such, and must not be * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
misrepresented as being the original software. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3. This notice may not be removed or altered from any source * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
distribution. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************/ *******************************************************************************/
#include "PolyVox/Raycast.h" #include "Raycast.h"
namespace PolyVox namespace PolyVox
{ {
@ -42,19 +43,20 @@ namespace PolyVox
public: public:
RaycastPickingFunctor(const typename VolumeType::VoxelType& emptyVoxelExample) RaycastPickingFunctor(const typename VolumeType::VoxelType& emptyVoxelExample)
:m_emptyVoxelExample(emptyVoxelExample) :m_emptyVoxelExample(emptyVoxelExample)
,m_result() , m_result()
{ {
} }
bool operator()(const typename VolumeType::Sampler& sampler) bool operator()(const typename VolumeType::Sampler& sampler)
{ {
if(sampler.getVoxel() != m_emptyVoxelExample) //If we've hit something if (sampler.getVoxel() != m_emptyVoxelExample) //If we've hit something
{ {
m_result.didHit = true; m_result.didHit = true;
m_result.hitVoxel = sampler.getPosition(); m_result.hitVoxel = sampler.getPosition();
return false; return false;
} }
m_result.hasPreviousVoxel = true;
m_result.previousVoxel = sampler.getPosition(); m_result.previousVoxel = sampler.getPosition();
return true; return true;

View File

@ -1,195 +0,0 @@
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#ifndef __PolyVox_ForwardDeclarations_H__
#define __PolyVox_ForwardDeclarations_H__
#include "Impl/TypeDef.h"
#include <cstdint>
namespace PolyVox
{
////////////////////////////////////////////////////////////////////////////////
// Array
////////////////////////////////////////////////////////////////////////////////
/*template<uint32_t dimensions, typename ElementType> class Array;
typedef Array<1,float> Array1DFloat;
typedef Array<1,double> Array1DDouble;
typedef Array<1,int8_t> Array1DInt8;
typedef Array<1,uint8_t> Array1DUint8;
typedef Array<1,int16_t> Array1DInt16;
typedef Array<1,uint16_t> Array1DUint16;
typedef Array<1,int32_t> Array1DInt32;
typedef Array<1,uint32_t> Array1DUint32;*/
/*typedef Array<2,float> Array2DFloat;
typedef Array<2,double> Array2DDouble;
typedef Array<2,int8_t> Array2DInt8;
typedef Array<2,uint8_t> Array2DUint8;
typedef Array<2,int16_t> Array2DInt16;
typedef Array<2,uint16_t> Array2DUint16;
typedef Array<2,int32_t> Array2DInt32;
typedef Array<2,uint32_t> Array2DUint32;*/
/*typedef Array<3,float> Array3DFloat;
typedef Array<3,double> Array3DDouble;
typedef Array<3,int8_t> Array3DInt8;
typedef Array<3,uint8_t> Array3DUint8;
typedef Array<3,int16_t> Array3DInt16;
typedef Array<3,uint16_t> Array3DUint16;
typedef Array<3,int32_t> Array3DInt32;
typedef Array<3,uint32_t> Array3DUint32;*/
////////////////////////////////////////////////////////////////////////////////
// Compressor
////////////////////////////////////////////////////////////////////////////////
class Compressor;
////////////////////////////////////////////////////////////////////////////////
// CubicSurfaceExtractor
////////////////////////////////////////////////////////////////////////////////
template<typename VoxelType> class DefaultIsQuadNeeded;
template<typename VolumeType, typename MeshType, typename IsQuadNeeded = DefaultIsQuadNeeded<typename VolumeType::VoxelType> > class CubicSurfaceExtractor;
////////////////////////////////////////////////////////////////////////////////
// CubicVertex
////////////////////////////////////////////////////////////////////////////////
template<typename VoxelType> struct CubicVertex;
////////////////////////////////////////////////////////////////////////////////
// Density
////////////////////////////////////////////////////////////////////////////////
template <typename Type> class Density;
typedef Density<int8_t> DensityI8;
typedef Density<uint8_t> DensityU8;
typedef Density<int16_t> DensityI16;
typedef Density<uint16_t> DensityU16;
typedef Density<float> DensityFloat;
typedef Density<double> DensityDouble;
typedef DensityU8 Density8; //Backwards compatibility
typedef DensityU16 Density16; //Backwards compatibility
////////////////////////////////////////////////////////////////////////////////
// FilePager
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> class FilePager;
////////////////////////////////////////////////////////////////////////////////
// MarchingCubesSurfaceExtractor
////////////////////////////////////////////////////////////////////////////////
template<typename VolumeType, typename MeshType, typename ControllerType> class MarchingCubesSurfaceExtractor;
////////////////////////////////////////////////////////////////////////////////
// MarchingCubesVertex
////////////////////////////////////////////////////////////////////////////////
template<typename VoxelType> struct MarchingCubesVertex;
////////////////////////////////////////////////////////////////////////////////
// Material
////////////////////////////////////////////////////////////////////////////////
template <typename Type> class Material;
typedef Material<uint8_t> MaterialU8;
typedef Material<uint16_t> MaterialU16;
typedef Material<uint32_t> MaterialU32;
typedef MaterialU8 Material8;
typedef MaterialU16 Material16;
typedef MaterialU32 Material32;
////////////////////////////////////////////////////////////////////////////////
// MaterialDensityPair
////////////////////////////////////////////////////////////////////////////////
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits> class MaterialDensityPair;
typedef MaterialDensityPair<uint8_t, 4, 4> MaterialDensityPair44;
typedef MaterialDensityPair<uint16_t, 8, 8> MaterialDensityPair88;
////////////////////////////////////////////////////////////////////////////////
// Mesh
////////////////////////////////////////////////////////////////////////////////
typedef uint32_t DefaultIndexType;
template <typename VertexType, typename IndexType = DefaultIndexType> class Mesh;
////////////////////////////////////////////////////////////////////////////////
// PagedVolume
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> class PagedVolume;
template <typename VoxelType>
using LargeVolume = PagedVolume<VoxelType>;
template <typename VoxelType>
using SimpleVolume = PagedVolume<VoxelType>;
////////////////////////////////////////////////////////////////////////////////
// Pager
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> class Pager;
////////////////////////////////////////////////////////////////////////////////
// RawVolume
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType> class RawVolume;
////////////////////////////////////////////////////////////////////////////////
// Region
////////////////////////////////////////////////////////////////////////////////
class Region;
////////////////////////////////////////////////////////////////////////////////
// Vector
////////////////////////////////////////////////////////////////////////////////
template <uint32_t Size, typename StorageType, typename OperationType = StorageType> class Vector;
typedef Vector<2,float,float> Vector2DFloat;
typedef Vector<2,double,double> Vector2DDouble;
typedef Vector<2,int8_t,int32_t> Vector2DInt8;
typedef Vector<2,uint8_t,int32_t> Vector2DUint8;
typedef Vector<2,int16_t,int32_t> Vector2DInt16;
typedef Vector<2,uint16_t,int32_t> Vector2DUint16;
typedef Vector<2,int32_t,int32_t> Vector2DInt32;
typedef Vector<2,uint32_t,int32_t> Vector2DUint32;
typedef Vector<3,float,float> Vector3DFloat;
typedef Vector<3,double,double> Vector3DDouble;
typedef Vector<3,int8_t,int32_t> Vector3DInt8;
typedef Vector<3,uint8_t,int32_t> Vector3DUint8;
typedef Vector<3,int16_t,int32_t> Vector3DInt16;
typedef Vector<3,uint16_t,int32_t> Vector3DUint16;
typedef Vector<3,int32_t,int32_t> Vector3DInt32;
typedef Vector<3,uint32_t,int32_t> Vector3DUint32;
typedef Vector<4,float,float> Vector4DFloat;
typedef Vector<4,double,double> Vector4DDouble;
typedef Vector<4,int8_t,int32_t> Vector4DInt8;
typedef Vector<4,uint8_t,int32_t> Vector4DUint8;
typedef Vector<4,int16_t,int32_t> Vector4DInt16;
typedef Vector<4,uint16_t,int32_t> Vector4DUint16;
typedef Vector<4,int32_t,int32_t> Vector4DInt32;
typedef Vector<4,uint32_t,int32_t> Vector4DUint32;
}
#endif

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