├── .gitignore
├── CMakeLists.txt
├── Header.png
├── LICENSE
├── README.md
├── cmake
├── AddCompilerFlag.cmake
├── CXX11.cmake
├── CheckCCompilerFlag.cmake
├── CheckCXXCompilerFlag.cmake
├── CheckMicCCompilerFlag.cmake
├── CheckMicCXXCompilerFlag.cmake
├── FindSDL.cmake
└── OptimizeForArchitecture.cmake
├── models
└── XYZRGB-Dragon.oct
├── run_builder.bat
├── run_viewer.bat
├── setup_builds.bat
├── setup_builds.sh
└── src
├── ChunkedAllocator.hpp
├── Debug.cpp
├── Debug.hpp
├── Events.cpp
├── Events.hpp
├── IntTypes.hpp
├── Main.cpp
├── PlyLoader.cpp
├── PlyLoader.hpp
├── SDLMain.h
├── SDLMain.m
├── ThreadBarrier.cpp
├── ThreadBarrier.hpp
├── Timer.hpp
├── Util.cpp
├── Util.hpp
├── VoxelData.cpp
├── VoxelData.hpp
├── VoxelOctree.cpp
├── VoxelOctree.hpp
├── math
├── Mat4.cpp
├── Mat4.hpp
├── MatrixStack.cpp
├── MatrixStack.hpp
└── Vec3.hpp
├── third-party
├── lz4.c
├── lz4.h
├── ply.h
├── plyfile.c
├── tribox3.c
└── tribox3.h
└── thread
├── TaskGroup.hpp
├── ThreadPool.cpp
├── ThreadPool.hpp
├── ThreadUtils.cpp
└── ThreadUtils.hpp
/.gitignore:
--------------------------------------------------------------------------------
1 | /*
2 | /*/
3 | !/.gitignore
4 | !/CMakeLists.txt
5 | !/setup_builds.sh
6 | !/setup_builds.bat
7 | !/Header.png
8 | !/README.md
9 | !/LICENSE
10 | !/src/
11 | !/models/
12 | !/cmake/
13 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 | project(sparse-voxel-octrees)
3 |
4 | set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
5 |
6 | include(CXX11)
7 | check_for_cxx11_compiler(CXX11_COMPILER)
8 |
9 | if(CXX11_COMPILER)
10 | enable_cxx11()
11 | else()
12 | message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} seems to have no C++11 support. Please try again with a more recent compiler version.")
13 | endif()
14 |
15 | include(OptimizeForArchitecture)
16 | OptimizeForArchitecture()
17 |
18 | if (MSVC)
19 | add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
20 | endif()
21 |
22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Vc_ARCHITECTURE_FLAGS}")
23 |
24 | if (CMAKE_COMPILER_IS_GNUCXX)
25 | set(CXX_WARNINGS "-Wall -Wextra -Wpointer-arith -Wcast-align -fstrict-aliasing -Wno-unused-local-typedefs")
26 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_WARNINGS} -fvisibility-inlines-hidden")
27 | endif()
28 |
29 | find_package(SDL REQUIRED)
30 |
31 | include_directories(src ${SDL_INCLUDE_DIR})
32 | file(GLOB_RECURSE Sources "src/*.hpp" "src/*.cpp" "src/*.c")
33 |
34 | if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
35 | set(Sources ${Sources} "src/SDLMain.m")
36 | endif()
37 |
38 | if (WIN32)
39 | add_executable(sparse-voxel-octrees WIN32 ${Sources})
40 | else()
41 | add_executable(sparse-voxel-octrees ${Sources})
42 | endif()
43 | target_link_libraries(sparse-voxel-octrees ${SDLMAIN_LIBRARY} ${SDL_LIBRARY})
44 |
45 | set_target_properties(sparse-voxel-octrees PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/bin)
46 | set_target_properties(sparse-voxel-octrees PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/bin)
--------------------------------------------------------------------------------
/Header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tunabrain/sparse-voxel-octrees/c4c2a9d3015056c269c73430f223e69e3b933b83/Header.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Benedikt Bitterli
2 |
3 | This software is provided 'as-is', without any express or implied
4 | warranty. In no event will the authors be held liable for any damages
5 | arising from the use of this software.
6 |
7 | Permission is granted to anyone to use this software for any purpose,
8 | including commercial applications, and to alter it and redistribute it
9 | freely, subject to the following restrictions:
10 |
11 | 1. The origin of this software must not be misrepresented; you must not
12 | claim that you wrote the original software. If you use this software
13 | in a product, an acknowledgment in the product documentation would be
14 | appreciated but is not required.
15 |
16 | 2. Altered source versions must be plainly marked as such, and must not be
17 | misrepresented as being the original software.
18 |
19 | 3. This notice may not be removed or altered from any source
20 | distribution.
21 |
22 | The CMake models in the cmake/ subfolder were written by Alexander Neundorf,
23 | Matthias Kretz and Nathan Osman and come with their own licenses. See the
24 | respective .cmake files for more information.
25 |
26 | The files src/third-party/tribox.c and src/third-party/tribox.h are courtesy
27 | of Tomas Akenine-Moller
28 |
29 | The files src/third-party/lc4.c and src/third-party/lc4.h are part of the LZ4
30 | compression library available here: https://github.com/Cyan4973/lz4
31 |
32 | Its license text is reproduced here
33 |
34 | LZ4 - Fast LZ compression algorithm
35 | Copyright (C) 2011-2015, Yann Collet.
36 |
37 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
38 |
39 | Redistribution and use in source and binary forms, with or without
40 | modification, are permitted provided that the following conditions are
41 | met:
42 |
43 | * Redistributions of source code must retain the above copyright
44 | notice, this list of conditions and the following disclaimer.
45 | * Redistributions in binary form must reproduce the above
46 | copyright notice, this list of conditions and the following disclaimer
47 | in the documentation and/or other materials provided with the
48 | distribution.
49 |
50 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
54 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
56 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
57 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
58 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 |
62 | You can contact the author at :
63 | - LZ4 source repository : https://github.com/Cyan4973/lz4
64 | - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
65 |
66 |
67 | The files src/third-party/ply.h and src/third-party/plyfile.c are part of the PLY
68 | library. Its license text is reproduced here
69 |
70 | Copyright (c) 1994 The Board of Trustees of The Leland Stanford
71 | Junior University. All rights reserved.
72 |
73 | Permission to use, copy, modify and distribute this software and its
74 | documentation for any purpose is hereby granted without fee, provided
75 | that the above copyright notice and this permission notice appear in
76 | all copies of this software and that you do not sell the software.
77 |
78 | THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
79 | EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
80 | WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | Sparse Voxel Octrees
4 | =========
5 |
6 | This project provides a multithreaded, CPU Sparse Voxel Octree implementation in C++, capable of raytracing large datasets in real-time, converting raw voxel files to octrees and converting mesh data (in form of PLY files) to voxel octrees.
7 |
8 | The conversion routines are capable of handling datasets much larger than the working memory, allowing the creation and rendering of very large octrees (resolution 8192x8192x8192 and up).
9 |
10 | This implementation closely follows the paper [Efficient Sparse Voxel Octrees](https://research.nvidia.com/publication/efficient-sparse-voxel-octrees) by Samuli Laine and Tero Karras.
11 |
12 | The XYZRGB dragon belongs the the Stanford 3D Scanning Repository and is available from [their homepage](http://graphics.stanford.edu/data/3Dscanrep/)
13 |
14 | Compilation
15 | ===========
16 |
17 | A recent compiler cupporting C++11, CMake 2.8 and SDL 1.2 are required to build.
18 |
19 | To build on Linux, you can use the `setup_builds.sh` shell script to setup build and release configurations using CMake. After running `setup_builds.sh`, run `make` inside the newly created `build/release/` folder. Alternatively, you can use the standard CMake CLI to configure the project.
20 |
21 | To build on Windows, you will need Visual Studio 2013 or later. Before running CMake, make sure that
22 |
23 | * CMake is on the `PATH` environment variable. An easy check to verify that this is the case is to open CMD and type `cmake`, which should output the CMake CLI help.
24 | * You have Windows 64bit binaries of SDL 1.2. These are available [here](https://www.libsdl.org/download-1.2.php). Make sure to grab the `SDL-devel-1.2.XX-VC.zip`. Note that if you are using a newer version of Visual Studio, you may need to compile SDL yourself in order to be compatible. Please see the SDL website for details
25 | * The environment variable `SDLDIR` exists and is set to the path to the folder containing SDL1.2 (you will have to set it up manually - it needs to be a system environment variable, not a user variable, for CMake to find it). CMake will use this variable to find the SDL relevant files and configure MSVC to use them
26 |
27 | After these prerequisites are setup, you can run `setup_builds.bat` to create the Visual Studio files. It will create a folder `vstudio` containing the `sparse-voxel-octrees.sln` solution.
28 |
29 | Alternatively, you can also run CMake manually or setup the MSVC project yourself, without CMake. The sources don't require special build flags, so the latter is easily doable if you can't get CMake to work.
30 |
31 | To build on macOS, you will need to install SDL first (i.e. `brew install sdl`). Then build it like a regular CMake project:
32 |
33 | mkdir build
34 | cd build
35 | cmake ../
36 | make
37 | ./sparse-voxel-octrees -viewer ../models/XYZRGB-Dragon.oct
38 |
39 | On macOS, you may need to click+drag within the application window first to make the render visible.
40 |
41 | Note: If building fails on macOS, you can try commenting out the follow lines in CMakeLists.txt
42 |
43 | #if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
44 | # set(Sources ${Sources} "src/SDLMain.m")
45 | #endif()
46 |
47 | Usage
48 | =====
49 |
50 | On startup, the program will load the sample octree and render it. Left mouse rotates the model, right mouse zooms. Escape quits the program. In order to make CLI arguments easier on Windows, you can use run_viewer.bat
to start the viewer.
51 |
52 | Note that due to repository size considerations, the sample octree has poor resolution (256x256x256). You can generate larger octrees using the code, however. See Main.cpp:initScene
for details. You can also use run_builder.bat
to build the XYZ RGB dragon model. To do this, simply download the XYZ RGB dragon model from http://graphics.stanford.edu/data/3Dscanrep/ and place it in the models
folder.
53 |
54 | Code
55 | ====
56 |
57 | Main.cpp
controls application setup, thread spawning and basic rendering (should move this into a different file instead at some point).
58 |
59 | VoxelOctree.cpp
provides routines for octree raymarching as well as generating, saving and loading octrees. It uses VoxelData.cpp
, which robustly handles fast access to non-square, non-power-of-two voxel data not completely loaded in memory.
60 |
61 | The VoxelData
class can also pull voxel data directly from PlyLoader.cpp
, generating data from triangle meshes on demand, instead of from file, which vastly improves conversion performance due to elimination of file I/O.
62 |
--------------------------------------------------------------------------------
/cmake/AddCompilerFlag.cmake:
--------------------------------------------------------------------------------
1 | # - Add a given compiler flag to flags variables.
2 | # AddCompilerFlag( [])
3 | # or
4 | # AddCompilerFlag( [C_FLAGS ] [CXX_FLAGS ] [C_RESULT ]
5 | # [CXX_RESULT ])
6 |
7 | #=============================================================================
8 | # Copyright 2010-2013 Matthias Kretz
9 | #
10 | # Redistribution and use in source and binary forms, with or without
11 | # modification, are permitted provided that the following conditions are
12 | # met:
13 | #
14 | # * Redistributions of source code must retain the above copyright notice,
15 | # this list of conditions and the following disclaimer.
16 | #
17 | # * Redistributions in binary form must reproduce the above copyright notice,
18 | # this list of conditions and the following disclaimer in the documentation
19 | # and/or other materials provided with the distribution.
20 | #
21 | # * The names of Kitware, Inc., the Insight Consortium, or the names of
22 | # any consortium members, or of any contributors, may not be used to
23 | # endorse or promote products derived from this software without
24 | # specific prior written permission.
25 | #
26 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
27 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
30 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
34 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 | #=============================================================================
37 |
38 | get_filename_component(_currentDir "${CMAKE_CURRENT_LIST_FILE}" PATH)
39 | include("${_currentDir}/CheckCCompilerFlag.cmake")
40 | include("${_currentDir}/CheckCXXCompilerFlag.cmake")
41 | include("${_currentDir}/CheckMicCCompilerFlag.cmake")
42 | include("${_currentDir}/CheckMicCXXCompilerFlag.cmake")
43 |
44 | macro(AddCompilerFlag _flag)
45 | string(REGEX REPLACE "[-.+/:= ]" "_" _flag_esc "${_flag}")
46 |
47 | set(_c_flags "CMAKE_C_FLAGS")
48 | set(_cxx_flags "CMAKE_CXX_FLAGS")
49 | set(_mic_c_flags "CMAKE_MIC_C_FLAGS")
50 | set(_mic_cxx_flags "CMAKE_MIC_CXX_FLAGS")
51 | set(_c_result tmp)
52 | set(_cxx_result tmp)
53 | set(_mic_c_result)
54 | set(_mic_cxx_result)
55 | if(${ARGC} EQUAL 2)
56 | message(WARNING "Deprecated use of the AddCompilerFlag macro.")
57 | unset(_c_result)
58 | set(_cxx_result ${ARGV1})
59 | elseif(${ARGC} GREATER 2)
60 | set(state 0)
61 | unset(_c_flags)
62 | unset(_cxx_flags)
63 | unset(_mic_c_flags)
64 | unset(_mic_cxx_flags)
65 | unset(_c_result)
66 | unset(_cxx_result)
67 | unset(_mic_c_result)
68 | unset(_mic_cxx_result)
69 | foreach(_arg ${ARGN})
70 | if(_arg STREQUAL "C_FLAGS")
71 | set(state 1)
72 | if(NOT DEFINED _c_result)
73 | set(_c_result tmp0)
74 | endif()
75 | elseif(_arg STREQUAL "CXX_FLAGS")
76 | set(state 2)
77 | if(NOT DEFINED _cxx_result)
78 | set(_cxx_result tmp1)
79 | endif()
80 | elseif(_arg STREQUAL "C_RESULT")
81 | set(state 3)
82 | elseif(_arg STREQUAL "CXX_RESULT")
83 | set(state 4)
84 | elseif(_arg STREQUAL "MIC_C_RESULT")
85 | set(state 5)
86 | elseif(_arg STREQUAL "MIC_CXX_RESULT")
87 | set(state 6)
88 | elseif(_arg STREQUAL "MIC_C_FLAGS")
89 | if(NOT DEFINED _mic_c_result)
90 | set(_mic_c_result tmp2)
91 | endif()
92 | set(state 7)
93 | elseif(_arg STREQUAL "MIC_CXX_FLAGS")
94 | if(NOT DEFINED _mic_cxx_result)
95 | set(_mic_cxx_result tmp3)
96 | endif()
97 | set(state 8)
98 | elseif(state EQUAL 1)
99 | set(_c_flags "${_arg}")
100 | elseif(state EQUAL 2)
101 | set(_cxx_flags "${_arg}")
102 | elseif(state EQUAL 3)
103 | set(_c_result "${_arg}")
104 | elseif(state EQUAL 4)
105 | set(_cxx_result "${_arg}")
106 | elseif(state EQUAL 5)
107 | set(_mic_c_result "${_arg}")
108 | elseif(state EQUAL 6)
109 | set(_mic_cxx_result "${_arg}")
110 | elseif(state EQUAL 7)
111 | set(_mic_c_flags "${_arg}")
112 | elseif(state EQUAL 8)
113 | set(_mic_cxx_flags "${_arg}")
114 | else()
115 | message(FATAL_ERROR "Syntax error for AddCompilerFlag")
116 | endif()
117 | endforeach()
118 | endif()
119 |
120 | if("${_flag}" STREQUAL "-mfma")
121 | # Compiling with FMA3 support may fail only at the assembler level.
122 | # In that case we need to have such an instruction in the test code
123 | set(_code "#include
124 | __m128 foo(__m128 x) { return _mm_fmadd_ps(x, x, x); }
125 | int main() { return 0; }")
126 | elseif("${_flag}" STREQUAL "-stdlib=libc++")
127 | # Compiling with libc++ not only requires a compiler that understands it, but also
128 | # the libc++ headers itself
129 | set(_code "#include
130 | int main() { return 0; }")
131 | else()
132 | set(_code "int main() { return 0; }")
133 | endif()
134 |
135 | if(DEFINED _c_result)
136 | check_c_compiler_flag("${_flag}" check_c_compiler_flag_${_flag_esc} "${_code}")
137 | set(${_c_result} ${check_c_compiler_flag_${_flag_esc}})
138 | endif()
139 | if(DEFINED _cxx_result)
140 | check_cxx_compiler_flag("${_flag}" check_cxx_compiler_flag_${_flag_esc} "${_code}")
141 | set(${_cxx_result} ${check_cxx_compiler_flag_${_flag_esc}})
142 | endif()
143 |
144 | if(check_c_compiler_flag_${_flag_esc} AND DEFINED _c_flags)
145 | if(${_c_flags})
146 | set(${_c_flags} "${${_c_flags}} ${_flag}")
147 | else()
148 | set(${_c_flags} "${_flag}")
149 | endif()
150 | endif()
151 | if(check_cxx_compiler_flag_${_flag_esc} AND DEFINED _cxx_flags)
152 | if(${_cxx_flags})
153 | set(${_cxx_flags} "${${_cxx_flags}} ${_flag}")
154 | else()
155 | set(${_cxx_flags} "${_flag}")
156 | endif()
157 | endif()
158 |
159 | if(MIC_NATIVE_FOUND)
160 | if(DEFINED _mic_c_result)
161 | check_mic_c_compiler_flag("${_flag}" check_mic_c_compiler_flag_${_flag_esc} "${_code}")
162 | set(${_mic_c_result} ${check_mic_c_compiler_flag_${_flag_esc}})
163 | endif()
164 | if(DEFINED _mic_cxx_result)
165 | check_mic_cxx_compiler_flag("${_flag}" check_mic_cxx_compiler_flag_${_flag_esc} "${_code}")
166 | set(${_mic_cxx_result} ${check_mic_cxx_compiler_flag_${_flag_esc}})
167 | endif()
168 |
169 | if(check_mic_c_compiler_flag_${_flag_esc} AND DEFINED _mic_c_flags)
170 | set(${_mic_c_flags} "${${_mic_c_flags}} ${_flag}")
171 | endif()
172 | if(check_mic_cxx_compiler_flag_${_flag_esc} AND DEFINED _mic_cxx_flags)
173 | set(${_mic_cxx_flags} "${${_mic_cxx_flags}} ${_flag}")
174 | endif()
175 | endif()
176 | endmacro(AddCompilerFlag)
177 |
--------------------------------------------------------------------------------
/cmake/CXX11.cmake:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2013 Nathan Osman
2 |
3 | # Permission is hereby granted, free of charge, to any person obtaining a copy
4 | # of this software and associated documentation files (the "Software"), to deal
5 | # in the Software without restriction, including without limitation the rights
6 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | # copies of the Software, and to permit persons to whom the Software is
8 | # furnished to do so, subject to the following conditions:
9 |
10 | # The above copyright notice and this permission notice shall be included in
11 | # all copies or substantial portions of the Software.
12 |
13 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | # THE SOFTWARE.
20 |
21 | # Determines whether or not the compiler supports C++11
22 | macro(check_for_cxx11_compiler _VAR)
23 | message(STATUS "Checking for C++11 compiler")
24 | set(${_VAR})
25 | if((MSVC AND (MSVC10 OR MSVC11 OR MSVC12 OR MSVC14 OR MSVC15)) OR
26 | (CMAKE_COMPILER_IS_GNUCXX AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.6) OR
27 | (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 3.1))
28 | set(${_VAR} 1)
29 | message(STATUS "Checking for C++11 compiler - available")
30 | else()
31 | message(STATUS "Checking for C++11 compiler - unavailable")
32 | endif()
33 | endmacro()
34 |
35 | # Sets the appropriate flag to enable C++11 support
36 | macro(enable_cxx11)
37 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
38 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
39 | endif()
40 | endmacro()
41 |
42 |
--------------------------------------------------------------------------------
/cmake/CheckCCompilerFlag.cmake:
--------------------------------------------------------------------------------
1 | # - Check whether the C compiler supports a given flag.
2 | # CHECK_C_COMPILER_FLAG( )
3 | # - the compiler flag
4 | # - variable to store the result
5 | # This internally calls the check_c_source_compiles macro.
6 | # See help for CheckCSourceCompiles for a listing of variables
7 | # that can modify the build.
8 |
9 | #=============================================================================
10 | # Copyright 2006-2009 Kitware, Inc.
11 | # Copyright 2006 Alexander Neundorf
12 | # Copyright 2011-2013 Matthias Kretz
13 | #
14 | # Redistribution and use in source and binary forms, with or without
15 | # modification, are permitted provided that the following conditions are
16 | # met:
17 | #
18 | # * Redistributions of source code must retain the above copyright notice,
19 | # this list of conditions and the following disclaimer.
20 | #
21 | # * Redistributions in binary form must reproduce the above copyright notice,
22 | # this list of conditions and the following disclaimer in the documentation
23 | # and/or other materials provided with the distribution.
24 | #
25 | # * The names of Kitware, Inc., the Insight Consortium, or the names of
26 | # any consortium members, or of any contributors, may not be used to
27 | # endorse or promote products derived from this software without
28 | # specific prior written permission.
29 | #
30 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
31 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
34 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
36 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
38 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 | #=============================================================================
41 |
42 | INCLUDE(CheckCSourceCompiles)
43 |
44 | MACRO (CHECK_C_COMPILER_FLAG _FLAG _RESULT)
45 | SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
46 | SET(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
47 | if(${ARGC} GREATER 2)
48 | SET(TEST_SOURCE "${ARGV2}")
49 | else()
50 | SET(TEST_SOURCE "int main() { return 0;}")
51 | endif()
52 | CHECK_C_SOURCE_COMPILES("${TEST_SOURCE}" ${_RESULT}
53 | # Some compilers do not fail with a bad flag
54 | FAIL_REGEX "error: bad value (.*) for .* switch" # GNU
55 | FAIL_REGEX "argument unused during compilation" # clang
56 | FAIL_REGEX "is valid for .* but not for C" # GNU
57 | FAIL_REGEX "unrecognized .*option" # GNU
58 | FAIL_REGEX "ignored for target" # GNU
59 | FAIL_REGEX "ignoring unknown option" # MSVC
60 | FAIL_REGEX "[Uu]nknown option" # HP
61 | FAIL_REGEX "[Ww]arning: [Oo]ption" # SunPro
62 | FAIL_REGEX "command option .* is not recognized" # XL
63 | FAIL_REGEX "WARNING: unknown flag:" # Open64
64 | FAIL_REGEX "command line error" # ICC
65 | FAIL_REGEX "command line warning" # ICC
66 | FAIL_REGEX "#10236:" # ICC: File not found
67 | FAIL_REGEX " #10159: " # ICC
68 | FAIL_REGEX " #10353: " # ICC: option '-mfma' ignored, suggest using '-march=core-avx2'
69 | )
70 | SET (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
71 | ENDMACRO (CHECK_C_COMPILER_FLAG)
72 |
73 |
--------------------------------------------------------------------------------
/cmake/CheckCXXCompilerFlag.cmake:
--------------------------------------------------------------------------------
1 | # - Check whether the CXX compiler supports a given flag.
2 | # CHECK_CXX_COMPILER_FLAG( )
3 | # - the compiler flag
4 | # - variable to store the result
5 | # This internally calls the check_cxx_source_compiles macro. See help
6 | # for CheckCXXSourceCompiles for a listing of variables that can
7 | # modify the build.
8 |
9 | #=============================================================================
10 | # Copyright 2006-2009 Kitware, Inc.
11 | # Copyright 2006 Alexander Neundorf
12 | # Copyright 2011-2013 Matthias Kretz
13 | #
14 | # Redistribution and use in source and binary forms, with or without
15 | # modification, are permitted provided that the following conditions are
16 | # met:
17 | #
18 | # * Redistributions of source code must retain the above copyright notice,
19 | # this list of conditions and the following disclaimer.
20 | #
21 | # * Redistributions in binary form must reproduce the above copyright notice,
22 | # this list of conditions and the following disclaimer in the documentation
23 | # and/or other materials provided with the distribution.
24 | #
25 | # * The names of Kitware, Inc., the Insight Consortium, or the names of
26 | # any consortium members, or of any contributors, may not be used to
27 | # endorse or promote products derived from this software without
28 | # specific prior written permission.
29 | #
30 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
31 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
34 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
36 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
38 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 | #=============================================================================
41 |
42 | INCLUDE(CheckCXXSourceCompiles)
43 |
44 | MACRO (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT)
45 | SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
46 | SET(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}")
47 | if(${ARGC} GREATER 2)
48 | SET(TEST_SOURCE "${ARGV2}")
49 | else()
50 | SET(TEST_SOURCE "int main() { return 0;}")
51 | endif()
52 | CHECK_CXX_SOURCE_COMPILES("${TEST_SOURCE}" ${_RESULT}
53 | # Some compilers do not fail with a bad flag
54 | FAIL_REGEX "error: bad value (.*) for .* switch" # GNU
55 | FAIL_REGEX "argument unused during compilation" # clang
56 | FAIL_REGEX "is valid for .* but not for C\\\\+\\\\+" # GNU
57 | FAIL_REGEX "unrecognized .*option" # GNU
58 | FAIL_REGEX "ignored for target" # GNU
59 | FAIL_REGEX "ignoring unknown option" # MSVC
60 | FAIL_REGEX "[Uu]nknown option" # HP
61 | FAIL_REGEX "[Ww]arning: [Oo]ption" # SunPro
62 | FAIL_REGEX "command option .* is not recognized" # XL
63 | FAIL_REGEX "WARNING: unknown flag:" # Open64
64 | FAIL_REGEX "command line error" # ICC
65 | FAIL_REGEX "command line warning" # ICC
66 | FAIL_REGEX "#10236:" # ICC: File not found
67 | FAIL_REGEX " #10159: " # ICC
68 | FAIL_REGEX " #10353: " # ICC: option '-mfma' ignored, suggest using '-march=core-avx2'
69 | )
70 | SET (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
71 | ENDMACRO (CHECK_CXX_COMPILER_FLAG)
72 |
73 |
--------------------------------------------------------------------------------
/cmake/CheckMicCCompilerFlag.cmake:
--------------------------------------------------------------------------------
1 | # - Check whether the MIC C compiler supports a given flag.
2 | # CHECK_MIC_C_COMPILER_FLAG( )
3 | # - the compiler flag
4 | # - variable to store the result
5 | # This internally calls the check_c_source_compiles macro. See help
6 | # for CheckCSourceCompiles for a listing of variables that can
7 | # modify the build.
8 |
9 | #=============================================================================
10 | # Copyright 2006-2009 Kitware, Inc.
11 | # Copyright 2006 Alexander Neundorf
12 | # Copyright 2011-2013 Matthias Kretz
13 | #
14 | # Redistribution and use in source and binary forms, with or without
15 | # modification, are permitted provided that the following conditions are
16 | # met:
17 | #
18 | # * Redistributions of source code must retain the above copyright notice,
19 | # this list of conditions and the following disclaimer.
20 | #
21 | # * Redistributions in binary form must reproduce the above copyright notice,
22 | # this list of conditions and the following disclaimer in the documentation
23 | # and/or other materials provided with the distribution.
24 | #
25 | # * The names of Kitware, Inc., the Insight Consortium, or the names of
26 | # any consortium members, or of any contributors, may not be used to
27 | # endorse or promote products derived from this software without
28 | # specific prior written permission.
29 | #
30 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
31 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
34 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
36 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
38 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 | #=============================================================================
41 |
42 | macro(check_mic_c_compiler_flag _FLAG _RESULT)
43 | if("${_RESULT}" MATCHES "^${_RESULT}$")
44 | set(_tmpdir "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
45 | if(${ARGC} GREATER 2)
46 | file(WRITE "${_tmpdir}/src.c" "${ARGV2}")
47 | else()
48 | file(WRITE "${_tmpdir}/src.c" "int main() { return 0; }")
49 | endif()
50 |
51 | execute_process(
52 | COMMAND "${MIC_CC}" -mmic -c -o "${_tmpdir}/src.o"
53 | "${_FLAG}" "${_tmpdir}/src.c"
54 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
55 | RESULT_VARIABLE ${_RESULT}
56 | OUTPUT_VARIABLE OUTPUT
57 | ERROR_VARIABLE OUTPUT
58 | )
59 |
60 | if(${_RESULT})
61 | foreach(_fail_regex
62 | "error: bad value (.*) for .* switch" # GNU
63 | "argument unused during compilation" # clang
64 | "is valid for .* but not for C" # GNU
65 | "unrecognized .*option" # GNU
66 | "ignored for target" # GNU
67 | "ignoring unknown option" # MSVC
68 | "[Uu]nknown option" # HP
69 | "[Ww]arning: [Oo]ption" # SunPro
70 | "command option .* is not recognized" # XL
71 | "WARNING: unknown flag:" # Open64
72 | "command line error" # ICC
73 | "command line warning" # ICC
74 | "#10236:" # ICC: File not found
75 | )
76 | if("${OUTPUT}" MATCHES "${_fail_regex}")
77 | set(${_RESULT} FALSE)
78 | endif()
79 | endforeach()
80 | endif()
81 |
82 | if(${_RESULT})
83 | set(${_RESULT} 1 CACHE INTERNAL "Test ${_FLAG}")
84 | message(STATUS "Performing Test Check MIC C Compiler flag ${_FLAG} - Success")
85 | file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
86 | "Performing MIC C Compiler Flag Test ${_FLAG} succeded with the following output:\n"
87 | "${OUTPUT}\n"
88 | "COMMAND: ${MIC_CC} -mmic -c -o ${_tmpdir}/src.o ${_FLAG} ${_tmpdir}/src.cpp\n"
89 | )
90 | else()
91 | message(STATUS "Performing Test Check MIC C Compiler flag ${_FLAG} - Failed")
92 | set(${_RESULT} "" CACHE INTERNAL "Test ${_FLAG}")
93 | file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
94 | "Performing MIC C Compiler Flag Test ${_FLAG} failed with the following output:\n"
95 | "${OUTPUT}\n"
96 | "COMMAND: ${MIC_CC} -mmic -c -o ${_tmpdir}/src.o ${_FLAG} ${_tmpdir}/src.cpp\n"
97 | )
98 | endif()
99 | endif()
100 | endmacro()
101 |
102 |
--------------------------------------------------------------------------------
/cmake/CheckMicCXXCompilerFlag.cmake:
--------------------------------------------------------------------------------
1 | # - Check whether the MIC CXX compiler supports a given flag.
2 | # CHECK_MIC_CXX_COMPILER_FLAG( )
3 | # - the compiler flag
4 | # - variable to store the result
5 | # This internally calls the check_cxx_source_compiles macro. See help
6 | # for CheckCXXSourceCompiles for a listing of variables that can
7 | # modify the build.
8 |
9 | #=============================================================================
10 | # Copyright 2006-2009 Kitware, Inc.
11 | # Copyright 2006 Alexander Neundorf
12 | # Copyright 2011-2013 Matthias Kretz
13 | #
14 | # Redistribution and use in source and binary forms, with or without
15 | # modification, are permitted provided that the following conditions are
16 | # met:
17 | #
18 | # * Redistributions of source code must retain the above copyright notice,
19 | # this list of conditions and the following disclaimer.
20 | #
21 | # * Redistributions in binary form must reproduce the above copyright notice,
22 | # this list of conditions and the following disclaimer in the documentation
23 | # and/or other materials provided with the distribution.
24 | #
25 | # * The names of Kitware, Inc., the Insight Consortium, or the names of
26 | # any consortium members, or of any contributors, may not be used to
27 | # endorse or promote products derived from this software without
28 | # specific prior written permission.
29 | #
30 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
31 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
34 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
36 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
38 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 | #=============================================================================
41 |
42 | macro(check_mic_cxx_compiler_flag _FLAG _RESULT)
43 | if("${_RESULT}" MATCHES "^${_RESULT}$")
44 | set(_tmpdir "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
45 | if(${ARGC} GREATER 2)
46 | file(WRITE "${_tmpdir}/src.cpp" "${ARGV2}")
47 | else()
48 | file(WRITE "${_tmpdir}/src.cpp" "int main() { return 0; }")
49 | endif()
50 |
51 | execute_process(
52 | COMMAND "${MIC_CXX}" -mmic -c -o "${_tmpdir}/src.o"
53 | "${_FLAG}" "${_tmpdir}/src.cpp"
54 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
55 | RESULT_VARIABLE ${_RESULT}
56 | OUTPUT_VARIABLE OUTPUT
57 | ERROR_VARIABLE OUTPUT
58 | )
59 |
60 | if(${_RESULT} EQUAL 0)
61 | foreach(_fail_regex
62 | "error: bad value (.*) for .* switch" # GNU
63 | "argument unused during compilation" # clang
64 | "is valid for .* but not for C\\\\+\\\\+" # GNU
65 | "unrecognized .*option" # GNU
66 | "ignored for target" # GNU
67 | "ignoring unknown option" # MSVC
68 | "[Uu]nknown option" # HP
69 | "[Ww]arning: [Oo]ption" # SunPro
70 | "command option .* is not recognized" # XL
71 | "WARNING: unknown flag:" # Open64
72 | "command line error" # ICC
73 | "command line warning" # ICC
74 | "#10236:" # ICC: File not found
75 | )
76 | if("${OUTPUT}" MATCHES "${_fail_regex}")
77 | set(${_RESULT} FALSE)
78 | endif()
79 | endforeach()
80 | endif()
81 |
82 | if(${_RESULT} EQUAL 0)
83 | set(${_RESULT} 1 CACHE INTERNAL "Test ${_FLAG}")
84 | message(STATUS "Performing Test Check MIC C++ Compiler flag ${_FLAG} - Success")
85 | file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
86 | "Performing MIC C++ Compiler Flag Test ${_FLAG} succeded with the following output:\n"
87 | "${OUTPUT}\n"
88 | "COMMAND: ${MIC_CXX} -mmic -c -o ${_tmpdir}/src.o ${_FLAG} ${_tmpdir}/src.cpp\n"
89 | )
90 | else()
91 | message(STATUS "Performing Test Check MIC C++ Compiler flag ${_FLAG} - Failed")
92 | set(${_RESULT} "" CACHE INTERNAL "Test ${_FLAG}")
93 | file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
94 | "Performing MIC C++ Compiler Flag Test ${_FLAG} failed with the following output:\n"
95 | "${OUTPUT}\n"
96 | "COMMAND: ${MIC_CXX} -mmic -c -o ${_tmpdir}/src.o ${_FLAG} ${_tmpdir}/src.cpp\n"
97 | )
98 | endif()
99 | endif()
100 | endmacro()
101 |
102 |
--------------------------------------------------------------------------------
/cmake/FindSDL.cmake:
--------------------------------------------------------------------------------
1 | # - Locate SDL library
2 | # This module defines
3 | # SDL_LIBRARY, the name of the library to link against
4 | # SDL_FOUND, if false, do not try to link to SDL
5 | # SDL_INCLUDE_DIR, where to find SDL.h
6 | # SDL_VERSION_STRING, human-readable string containing the version of SDL
7 | #
8 | # This module responds to the the flag:
9 | # SDL_BUILDING_LIBRARY
10 | # If this is defined, then no SDL_main will be linked in because
11 | # only applications need main().
12 | # Otherwise, it is assumed you are building an application and this
13 | # module will attempt to locate and set the the proper link flags
14 | # as part of the returned SDL_LIBRARY variable.
15 | #
16 | # Don't forget to include SDLmain.h and SDLmain.m your project for the
17 | # OS X framework based version. (Other versions link to -lSDLmain which
18 | # this module will try to find on your behalf.) Also for OS X, this
19 | # module will automatically add the -framework Cocoa on your behalf.
20 | #
21 | #
22 | # Additional Note: If you see an empty SDL_LIBRARY_TEMP in your configuration
23 | # and no SDL_LIBRARY, it means CMake did not find your SDL library
24 | # (SDL.dll, libsdl.so, SDL.framework, etc).
25 | # Set SDL_LIBRARY_TEMP to point to your SDL library, and configure again.
26 | # Similarly, if you see an empty SDLMAIN_LIBRARY, you should set this value
27 | # as appropriate. These values are used to generate the final SDL_LIBRARY
28 | # variable, but when these values are unset, SDL_LIBRARY does not get created.
29 | #
30 | #
31 | # $SDLDIR is an environment variable that would
32 | # correspond to the ./configure --prefix=$SDLDIR
33 | # used in building SDL.
34 | # l.e.galup 9-20-02
35 | #
36 | # Modified by Eric Wing.
37 | # Added code to assist with automated building by using environmental variables
38 | # and providing a more controlled/consistent search behavior.
39 | # Added new modifications to recognize OS X frameworks and
40 | # additional Unix paths (FreeBSD, etc).
41 | # Also corrected the header search path to follow "proper" SDL guidelines.
42 | # Added a search for SDLmain which is needed by some platforms.
43 | # Added a search for threads which is needed by some platforms.
44 | # Added needed compile switches for MinGW.
45 | #
46 | # On OSX, this will prefer the Framework version (if found) over others.
47 | # People will have to manually change the cache values of
48 | # SDL_LIBRARY to override this selection or set the CMake environment
49 | # CMAKE_INCLUDE_PATH to modify the search paths.
50 | #
51 | # Note that the header path has changed from SDL/SDL.h to just SDL.h
52 | # This needed to change because "proper" SDL convention
53 | # is #include "SDL.h", not . This is done for portability
54 | # reasons because not all systems place things in SDL/ (see FreeBSD).
55 |
56 | #=============================================================================
57 | # Copyright 2003-2009 Kitware, Inc.
58 | # Copyright 2012 Benjamin Eikel
59 | #
60 | # Distributed under the OSI-approved BSD License (the "License");
61 | # see accompanying file Copyright.txt for details.
62 | #
63 | # This software is distributed WITHOUT ANY WARRANTY; without even the
64 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
65 | # See the License for more information.
66 | #=============================================================================
67 | # (To distribute this file outside of CMake, substitute the full
68 | # License text for the above reference.)
69 |
70 | find_path(SDL_INCLUDE_DIR SDL.h
71 | HINTS
72 | ENV SDLDIR
73 | PATH_SUFFIXES SDL include/SDL include/SDL12 include/SDL11 include
74 | )
75 |
76 | # SDL-1.1 is the name used by FreeBSD ports...
77 | # don't confuse it for the version number.
78 | find_library(SDL_LIBRARY_TEMP
79 | NAMES SDL SDL-1.1
80 | HINTS
81 | ENV SDLDIR ENV LIBRARY_PATH
82 | PATH_SUFFIXES lib lib/x64
83 | )
84 |
85 | if(NOT SDL_BUILDING_LIBRARY)
86 | if(NOT ${SDL_INCLUDE_DIR} MATCHES ".framework")
87 | # Non-OS X framework versions expect you to also dynamically link to
88 | # SDLmain. This is mainly for Windows and OS X. Other (Unix) platforms
89 | # seem to provide SDLmain for compatibility even though they don't
90 | # necessarily need it.
91 | find_library(SDLMAIN_LIBRARY
92 | NAMES SDLmain SDLmain-1.1
93 | HINTS
94 | ENV SDLDIR ENV LIBRARY_PATH
95 | PATH_SUFFIXES lib lib/x64
96 | PATHS
97 | /sw
98 | /opt/local
99 | /opt/csw
100 | /opt
101 | )
102 | endif()
103 | endif()
104 |
105 | # SDL may require threads on your system.
106 | # The Apple build may not need an explicit flag because one of the
107 | # frameworks may already provide it.
108 | # But for non-OSX systems, I will use the CMake Threads package.
109 | if(NOT APPLE)
110 | find_package(Threads)
111 | endif()
112 |
113 | # MinGW needs an additional library, mwindows
114 | # It's total link flags should look like -lmingw32 -lSDLmain -lSDL -lmwindows
115 | # (Actually on second look, I think it only needs one of the m* libraries.)
116 | if(MINGW)
117 | set(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
118 | endif()
119 |
120 | if(SDL_LIBRARY_TEMP)
121 | # For SDLmain
122 | if(SDLMAIN_LIBRARY AND NOT SDL_BUILDING_LIBRARY)
123 | list(FIND SDL_LIBRARY_TEMP "${SDLMAIN_LIBRARY}" _SDL_MAIN_INDEX)
124 | if(_SDL_MAIN_INDEX EQUAL -1)
125 | set(SDL_LIBRARY_TEMP "${SDLMAIN_LIBRARY}" ${SDL_LIBRARY_TEMP})
126 | endif()
127 | unset(_SDL_MAIN_INDEX)
128 | endif()
129 |
130 | # For OS X, SDL uses Cocoa as a backend so it must link to Cocoa.
131 | # CMake doesn't display the -framework Cocoa string in the UI even
132 | # though it actually is there if I modify a pre-used variable.
133 | # I think it has something to do with the CACHE STRING.
134 | # So I use a temporary variable until the end so I can set the
135 | # "real" variable in one-shot.
136 | if(APPLE)
137 | set(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} "-framework Cocoa")
138 | endif()
139 |
140 | # For threads, as mentioned Apple doesn't need this.
141 | # In fact, there seems to be a problem if I used the Threads package
142 | # and try using this line, so I'm just skipping it entirely for OS X.
143 | if(NOT APPLE)
144 | set(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
145 | endif()
146 |
147 | # For MinGW library
148 | if(MINGW)
149 | set(SDL_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL_LIBRARY_TEMP})
150 | endif()
151 |
152 | # Set the final string here so the GUI reflects the final state.
153 | set(SDL_LIBRARY ${SDL_LIBRARY_TEMP} CACHE STRING "Where the SDL Library can be found")
154 | # Set the temp variable to INTERNAL so it is not seen in the CMake GUI
155 | set(SDL_LIBRARY_TEMP "${SDL_LIBRARY_TEMP}" CACHE INTERNAL "")
156 | endif()
157 |
158 | if(SDL_INCLUDE_DIR AND EXISTS "${SDL_INCLUDE_DIR}/SDL_version.h")
159 | file(STRINGS "${SDL_INCLUDE_DIR}/SDL_version.h" SDL_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+$")
160 | file(STRINGS "${SDL_INCLUDE_DIR}/SDL_version.h" SDL_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+$")
161 | file(STRINGS "${SDL_INCLUDE_DIR}/SDL_version.h" SDL_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+$")
162 | string(REGEX REPLACE "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_VERSION_MAJOR "${SDL_VERSION_MAJOR_LINE}")
163 | string(REGEX REPLACE "^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_VERSION_MINOR "${SDL_VERSION_MINOR_LINE}")
164 | string(REGEX REPLACE "^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_VERSION_PATCH "${SDL_VERSION_PATCH_LINE}")
165 | set(SDL_VERSION_STRING ${SDL_VERSION_MAJOR}.${SDL_VERSION_MINOR}.${SDL_VERSION_PATCH})
166 | unset(SDL_VERSION_MAJOR_LINE)
167 | unset(SDL_VERSION_MINOR_LINE)
168 | unset(SDL_VERSION_PATCH_LINE)
169 | unset(SDL_VERSION_MAJOR)
170 | unset(SDL_VERSION_MINOR)
171 | unset(SDL_VERSION_PATCH)
172 | endif()
173 |
174 | include(FindPackageHandleStandardArgs)
175 |
176 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL
177 | REQUIRED_VARS SDL_LIBRARY SDL_INCLUDE_DIR
178 | VERSION_VAR SDL_VERSION_STRING)
179 |
--------------------------------------------------------------------------------
/models/XYZRGB-Dragon.oct:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tunabrain/sparse-voxel-octrees/c4c2a9d3015056c269c73430f223e69e3b933b83/models/XYZRGB-Dragon.oct
--------------------------------------------------------------------------------
/run_builder.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | cd bin
3 | sparse-voxel-octrees -builder --resolution 1024 --mode 0 ../models/xyzrgb_dragon.ply ../models/XYZRGB-Dragon.oct
--------------------------------------------------------------------------------
/run_viewer.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | cd bin
3 | sparse-voxel-octrees -viewer ../models/XYZRGB-Dragon.oct
--------------------------------------------------------------------------------
/setup_builds.bat:
--------------------------------------------------------------------------------
1 | rmdir /S /Q vstudio
2 | mkdir vstudio
3 | cd vstudio
4 | cmake ../ -G "Visual Studio 12 2013 Win64"
--------------------------------------------------------------------------------
/setup_builds.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | GENERATOR=""
3 | if [ "$(uname -o)" = "Msys" ];
4 | then
5 | GENERATOR=(-G "MSYS Makefiles")
6 | fi
7 | if [[ -n "$*" ]];
8 | then
9 | GENERATOR=(-G "$*")
10 | fi
11 |
12 | ROOTDIR="$(dirname "$(readlink -fn "$0")")"
13 |
14 | rm -rf build
15 | mkdir build
16 | cd build
17 |
18 | mkdir release
19 | cd release
20 | cmake -DCMAKE_BUILD_TYPE=Release "${GENERATOR[@]}" ${ROOTDIR}
21 | cd ..
22 |
23 | mkdir debug
24 | cd debug
25 | cmake -DCMAKE_BUILD_TYPE=Debug "${GENERATOR[@]}" ${ROOTDIR}
26 |
--------------------------------------------------------------------------------
/src/ChunkedAllocator.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef CHUNKEDALLOCATOR_HPP_
25 | #define CHUNKEDALLOCATOR_HPP_
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | template
33 | class ChunkedAllocator {
34 | static const size_t ChunkSize = 4096;
35 |
36 | struct InsertionPoint {
37 | size_t idx;
38 | Type data;
39 | };
40 |
41 | size_t _size;
42 | std::vector> _data;
43 | std::vector _insertions;
44 |
45 | public:
46 | ChunkedAllocator() : _size(0) {}
47 |
48 | size_t size() {
49 | return _size;
50 | }
51 |
52 | size_t insertionCount() {
53 | return _insertions.size();
54 | }
55 |
56 | Type &operator[](size_t i) {
57 | return _data[i/ChunkSize][i % ChunkSize];
58 | }
59 |
60 | const Type &operator[](size_t i) const {
61 | return _data[i/ChunkSize][i % ChunkSize];
62 | }
63 |
64 | void pushBack(Type t) {
65 | if ((_size % ChunkSize) == 0)
66 | _data.emplace_back(new Type[ChunkSize]);
67 |
68 | _data[_size/ChunkSize][_size % ChunkSize] = std::move(t);
69 | _size++;
70 | }
71 |
72 | void insert(size_t index, Type data) {
73 | _insertions.emplace_back(InsertionPoint{index, std::move(data)});
74 | }
75 |
76 | std::unique_ptr finalize() {
77 | std::sort(_insertions.begin(), _insertions.end(), [](const InsertionPoint &a, const InsertionPoint &b) {
78 | return a.idx < b.idx;
79 | });
80 |
81 | size_t length = _size + _insertions.size();
82 | std::unique_ptr result(new Type[length]);
83 |
84 | size_t insertionIdx = 0;
85 | size_t outputOffset = 0;
86 | size_t inputOffset = 0;
87 | while (inputOffset < _size) {
88 | size_t dataIdx = inputOffset/ChunkSize;
89 | size_t dataOffset = inputOffset % ChunkSize;
90 |
91 | // Clear out data blocks once we've copied them completely
92 | if (dataOffset == 0 && dataIdx > 0)
93 | _data[dataIdx - 1].reset();
94 |
95 | size_t copySize = std::min(ChunkSize - dataOffset, _size - inputOffset);
96 | if (insertionIdx < _insertions.size())
97 | copySize = std::min(copySize, _insertions[insertionIdx].idx - inputOffset);
98 |
99 | if (copySize > 0) {
100 | std::memcpy(result.get() + outputOffset, _data[dataIdx].get() + dataOffset, copySize*sizeof(Type));
101 | inputOffset += copySize;
102 | outputOffset += copySize;
103 | }
104 |
105 | if (insertionIdx < _insertions.size() && _insertions[insertionIdx].idx == inputOffset)
106 | result[outputOffset++] = std::move(_insertions[insertionIdx++].data);
107 | }
108 |
109 | _insertions.clear();
110 | _data.clear();
111 | _size = 0;
112 |
113 | return std::move(result);
114 | }
115 | };
116 |
117 | #endif /* CHUNKEDALLOCATOR_HPP_ */
118 |
--------------------------------------------------------------------------------
/src/Debug.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #include
25 | #include
26 | #include
27 |
28 | #include "Debug.hpp"
29 |
30 | const char *levelStr[] = {"WARN", "INFO", "DEBUG"};
31 |
32 | void debugLog(const char *module, DebugLevel level, const char *fmt, ...)
33 | {
34 | if (level > DEBUG_LEVEL)
35 | return;
36 | va_list argp;
37 | va_start(argp, fmt);
38 | printf("%s | %-10s | ", levelStr[level], module);
39 | vprintf(fmt, argp);
40 | va_end(argp);
41 | fflush(stdout);
42 | }
43 |
44 | void debugAssert(const char *file, int line, bool exp, const char *format, ...) {
45 | if (!exp) {
46 | printf("ASSERTION FAILURE: %s:%d: ", file, line);
47 | va_list args;
48 | va_start(args, format);
49 | vprintf(format, args);
50 | va_end(args);
51 | fflush(stdout);
52 | exit(EXIT_FAILURE);
53 | }
54 | }
55 |
56 | void debugFail(const char *file, int line, const char *format, ...) {
57 | printf("PROGRAM FAILURE: %s:%d: ", file, line);
58 | va_list args;
59 | va_start(args, format);
60 | vprintf(format, args);
61 | va_end(args);
62 | fflush(stdout);
63 | exit(EXIT_FAILURE);
64 | }
65 |
--------------------------------------------------------------------------------
/src/Debug.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef DEBUG_HPP_
25 | #define DEBUG_HPP_
26 |
27 | #define DEBUG_LEVEL DEBUG
28 |
29 | enum DebugLevel {
30 | WARN,
31 | INFO,
32 | DEBUG
33 | };
34 |
35 | #ifndef NDEBUG
36 | # define DBG(MODULE, LEVEL, ...) debugLog(MODULE, LEVEL, __VA_ARGS__)
37 | # define ASSERT(EXP, ...) debugAssert(__FILE__, __LINE__, (bool)(EXP), __VA_ARGS__)
38 | # define FAIL(...) debugFail(__FILE__, __LINE__, __VA_ARGS__)
39 | #else
40 | # define DBG(MODULE, LEVEL, FMT, ...) do {} while (0);
41 | # define ASSERT(A, B, ...) do { (bool)(A); } while (0);
42 | # define FAIL(A, ...) do {} while (0);
43 | #endif
44 |
45 | void debugLog(const char *module, DebugLevel level, const char *format, ...);
46 | void debugAssert(const char *file, int line, bool exp, const char *format, ...);
47 | void debugFail(const char *file, int line, const char *format, ...);
48 |
49 | #endif /* DEBUG_HPP_ */
50 |
--------------------------------------------------------------------------------
/src/Events.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #include "Events.hpp"
25 |
26 | #include
27 |
28 | static int mouseX = 0;
29 | static int mouseY = 0;
30 | static int mouseZ = 0;
31 | static int mouseXSpeed = 0;
32 | static int mouseYSpeed = 0;
33 | static int mouseZSpeed = 0;
34 | static int mouseDown[] = {0, 0};
35 | static char keyHit[SDLK_LAST];
36 | static char keyDown[SDLK_LAST];
37 |
38 | static void processEvent(SDL_Event event) {
39 | switch (event.type) {
40 | case SDL_MOUSEMOTION:
41 | mouseX = event.motion.x;
42 | mouseY = event.motion.y;
43 | mouseXSpeed = event.motion.xrel;
44 | mouseYSpeed = event.motion.yrel;
45 |
46 | break;
47 | case SDL_MOUSEBUTTONDOWN:
48 | if (event.button.button == SDL_BUTTON_WHEELUP) {
49 | mouseZSpeed = 1;
50 | mouseZ += 1;
51 | } else if(event.button.button == SDL_BUTTON_WHEELDOWN) {
52 | mouseZSpeed = -1;
53 | mouseZ -= 1;
54 | } else if (event.button.button == SDL_BUTTON_LEFT)
55 | mouseDown[0] = 1;
56 | else if (event.button.button == SDL_BUTTON_RIGHT)
57 | mouseDown[1] = 1;
58 |
59 | break;
60 | case SDL_MOUSEBUTTONUP:
61 | if (event.button.button == SDL_BUTTON_LEFT)
62 | mouseDown[0] = 0;
63 | else if (event.button.button == SDL_BUTTON_RIGHT)
64 | mouseDown[1] = 0;
65 |
66 | break;
67 | case SDL_KEYDOWN:
68 | keyHit[event.key.keysym.sym] = 1;
69 | keyDown[event.key.keysym.sym] = 1;
70 |
71 | break;
72 | case SDL_KEYUP:
73 | keyDown[event.key.keysym.sym] = 0;
74 |
75 | break;
76 | case SDL_QUIT:
77 | exit(0);
78 | }
79 | }
80 |
81 | int waitEvent() {
82 | SDL_Event event;
83 | SDL_WaitEvent(&event);
84 | processEvent(event);
85 |
86 | return event.type;
87 | }
88 |
89 | void checkEvents() {
90 | SDL_Event event;
91 | while (SDL_PollEvent(&event))
92 | processEvent(event);
93 | }
94 |
95 | int getMouseX() {
96 | return mouseX;
97 | }
98 |
99 | int getMouseY() {
100 | return mouseY;
101 | }
102 |
103 | int getMouseZ() {
104 | return mouseZ;
105 | }
106 |
107 | int getMouseXSpeed() {
108 | int Temp = mouseXSpeed;
109 |
110 | mouseXSpeed = 0;
111 |
112 | return Temp;
113 | }
114 |
115 | int getMouseYSpeed() {
116 | int Temp = mouseYSpeed;
117 |
118 | mouseYSpeed = 0;
119 |
120 | return Temp;
121 | }
122 |
123 | int getMouseZSpeed() {
124 | int Temp = mouseZSpeed;
125 |
126 | mouseZSpeed = 0;
127 |
128 | return Temp;
129 | }
130 |
131 | int getMouseDown(int Button) {
132 | return mouseDown[Button];
133 | }
134 |
135 | int getKeyHit(int Key) {
136 | int Temp = keyHit[Key];
137 |
138 | keyHit[Key] = 0;
139 |
140 | return Temp;
141 | }
142 |
143 | int getKeyDown(int Key) {
144 | return keyDown[Key];
145 | }
146 |
--------------------------------------------------------------------------------
/src/Events.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef EVENTS_HPP_
25 | #define EVENTS_HPP_
26 |
27 | void checkEvents();
28 | int waitEvent();
29 | int getMouseX();
30 | int getMouseY();
31 | int getMouseZ();
32 | int getMouseXSpeed();
33 | int getMouseYSpeed();
34 | int getMouseZSpeed();
35 | int getMouseDown(int button);
36 | int getKeyHit(int button);
37 | int getKeyDown(int button);
38 |
39 | #endif /* EVENTS_HPP_ */
40 |
--------------------------------------------------------------------------------
/src/IntTypes.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef INTTYPES_HPP_
25 | #define INTTYPES_HPP_
26 |
27 | #include
28 |
29 | typedef std::uint8_t uint8;
30 | typedef std::uint16_t uint16;
31 | typedef std::uint32_t uint32;
32 | typedef std::uint64_t uint64;
33 |
34 | typedef std::int8_t int8;
35 | typedef std::int16_t int16;
36 | typedef std::int32_t int32;
37 | typedef std::int64_t int64;
38 |
39 | #endif /* INTTYPES_HPP_ */
40 |
--------------------------------------------------------------------------------
/src/Main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 |
25 | #include "ThreadBarrier.hpp"
26 | #include "VoxelOctree.hpp"
27 | #include "PlyLoader.hpp"
28 | #include "VoxelData.hpp"
29 | #include "Events.hpp"
30 | #include "Timer.hpp"
31 | #include "Util.hpp"
32 |
33 | #include "thread/ThreadUtils.hpp"
34 | #include "thread/ThreadPool.hpp"
35 |
36 | #include "math/MatrixStack.hpp"
37 | #include "math/Vec3.hpp"
38 | #include "math/Mat4.hpp"
39 |
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 | #include
49 | #include
50 | #include
51 |
52 | #ifndef M_PI
53 | #define M_PI 3.14159265358979323846
54 | #endif
55 |
56 | /* Number of threads to use - adapt this to your platform for optimal results */
57 | static const int NumThreads = 16;
58 | /* Screen resolution */
59 | static const int GWidth = 1280;
60 | static const int GHeight = 720;
61 |
62 | static const float AspectRatio = GHeight/(float)GWidth;
63 | static const int TileSize = 8;
64 |
65 | static SDL_Surface *backBuffer;
66 | static ThreadBarrier *barrier;
67 |
68 | static std::atomic doTerminate;
69 | static std::atomic renderHalfSize;
70 |
71 | struct BatchData {
72 | int id;
73 | int x0, y0;
74 | int x1, y1;
75 |
76 | int tilesX, tilesY;
77 | float *depthBuffer;
78 | VoxelOctree *tree;
79 | };
80 |
81 | Vec3 shade(int intNormal, const Vec3 &ray, const Vec3 &light) {
82 | Vec3 n;
83 | float c;
84 | decompressMaterial(intNormal, n, c);
85 |
86 | float d = std::max(light.dot(ray.reflect(n)), 0.0f);
87 | float specular = d*d;
88 |
89 | return c*0.9f*std::abs(light.dot(n)) + specular*0.2f;
90 | }
91 |
92 | void renderTile(int x0, int y0, int x1, int y1, int stride, float scale, float zx, float zy, float zz,
93 | const Mat4 &tform, const Vec3 &light, VoxelOctree *tree, const Vec3 &pos, float minT) {
94 | uint32 *buffer = (uint32 *)backBuffer->pixels;
95 | int pitch = backBuffer->pitch;
96 |
97 | float dy = AspectRatio - y0*scale;
98 | for (int y = y0; y < y1; ++y, dy -= scale) {
99 | float dx = -1.0f + x0*scale;
100 | for (int x = x0; x < x1; ++x, dx += scale) {
101 | int cornerX = x - ((x - x0) % stride);
102 | int cornerY = y - ((y - y0) % stride);
103 | if (cornerX != x || cornerY != y) {
104 | buffer[x + y*pitch/4] = buffer[cornerX + cornerY*pitch/4];
105 | continue;
106 | }
107 |
108 | Vec3 dir = Vec3(
109 | dx*tform.a11 + dy*tform.a12 + zx,
110 | dx*tform.a21 + dy*tform.a22 + zy,
111 | dx*tform.a31 + dy*tform.a32 + zz
112 | );
113 | dir *= invSqrt(dir.x*dir.x + dir.y*dir.y + dir.z*dir.z);
114 |
115 | uint32 intNormal;
116 | float t;
117 | Vec3 col;
118 | if (tree->raymarch(pos + dir*minT, dir, 0.0f, intNormal, t))
119 | col = shade(intNormal, dir, light);
120 |
121 | #ifdef __APPLE__
122 | uint32 color =
123 | uint32(std::min(col.x, 1.0f)*255.0) << 8 |
124 | (uint32(std::min(col.y, 1.0f)*255.0) << 16) |
125 | (uint32(std::min(col.z, 1.0f)*255.0) << 24) |
126 | 0x000000FFu;
127 | #else
128 | uint32 color =
129 | uint32(std::min(col.x, 1.0f)*255.0) |
130 | (uint32(std::min(col.y, 1.0f)*255.0) << 8) |
131 | (uint32(std::min(col.z, 1.0f)*255.0) << 16) |
132 | 0xFF000000u;
133 | #endif
134 | buffer[x + y*pitch/4] = color;
135 | }
136 | }
137 | }
138 |
139 | void renderBatch(BatchData *data) {
140 | const float TreeMiss = 1e10;
141 |
142 | int x0 = data->x0, y0 = data->y0;
143 | int x1 = data->x1, y1 = data->y1;
144 | int tilesX = data->tilesX;
145 | int tilesY = data->tilesY;
146 | float *depthBuffer = data->depthBuffer;
147 | VoxelOctree *tree = data->tree;
148 |
149 | Mat4 tform;
150 | MatrixStack::get(INV_MODELVIEW_STACK, tform);
151 |
152 | Vec3 pos = tform*Vec3() + tree->center() + Vec3(1.0);
153 |
154 | tform.a14 = tform.a24 = tform.a34 = 0.0f;
155 |
156 | float scale = 2.0f/GWidth;
157 | float tileScale = TileSize*scale;
158 | float planeDist = 1.0f/std::tan(float(M_PI)/6.0f);
159 | float zx = planeDist*tform.a13, zy = planeDist*tform.a23, zz = planeDist*tform.a33;
160 | float coarseScale = 2.0f*TileSize/(planeDist*GHeight);
161 | int stride = renderHalfSize ? 3 : 1;
162 |
163 | Vec3 light = (tform*Vec3(-1.0, 1.0, -1.0)).normalize();
164 |
165 | std::memset((uint8 *)backBuffer->pixels + y0*backBuffer->pitch, 0, (y1 - y0)*backBuffer->pitch);
166 |
167 | float dy = AspectRatio - y0*scale;
168 | for (int y = 0, idx = 0; y < tilesY; y++, dy -= tileScale) {
169 | float dx = -1.0f + x0*scale;
170 | for (int x = 0; x < tilesX; x++, dx += tileScale, idx++) {
171 | Vec3 dir = Vec3(
172 | dx*tform.a11 + dy*tform.a12 + zx,
173 | dx*tform.a21 + dy*tform.a22 + zy,
174 | dx*tform.a31 + dy*tform.a32 + zz
175 | );
176 | dir *= invSqrt(dir.x*dir.x + dir.y*dir.y + dir.z*dir.z);
177 |
178 | uint32 intNormal;
179 | float t;
180 | Vec3 col;
181 | if (tree->raymarch(pos, dir, coarseScale, intNormal, t))
182 | depthBuffer[idx] = t;
183 | else
184 | depthBuffer[idx] = TreeMiss;
185 |
186 | if (x > 0 && y > 0) {
187 | float minT = std::min(std::min(depthBuffer[idx], depthBuffer[idx - 1]),
188 | std::min(depthBuffer[idx - tilesX],
189 | depthBuffer[idx - tilesX - 1]));
190 |
191 | if (minT != TreeMiss) {
192 | int tx0 = (x - 1)*TileSize + x0;
193 | int ty0 = (y - 1)*TileSize + y0;
194 | int tx1 = std::min(tx0 + TileSize, x1);
195 | int ty1 = std::min(ty0 + TileSize, y1);
196 | renderTile(tx0, ty0, tx1, ty1, stride, scale, zx, zy, zz, tform, light, tree, pos,
197 | std::max(minT - 0.03f, 0.0f));
198 | }
199 | }
200 | }
201 | }
202 | }
203 |
204 | int renderLoop(void *threadData) {
205 | BatchData *data = (BatchData *)threadData;
206 |
207 | float radius = 1.0f;
208 | float pitch = 0.0f;
209 | float yaw = 0.0f;
210 |
211 | if (data->id == 0) {
212 | MatrixStack::set(VIEW_STACK, Mat4::translate(Vec3(0.0f, 0.0f, -radius)));
213 | MatrixStack::set(MODEL_STACK, Mat4());
214 | }
215 |
216 | while (!doTerminate) {
217 | barrier->waitPre();
218 | renderBatch(data);
219 | barrier->waitPost();
220 |
221 | if (data->id == 0) {
222 | if (SDL_MUSTLOCK(backBuffer))
223 | SDL_UnlockSurface(backBuffer);
224 |
225 | SDL_UpdateRect(backBuffer, 0, 0, 0, 0);
226 |
227 | int event;
228 | while ((event = waitEvent()) && (event == SDL_MOUSEMOTION && !getMouseDown(0) && !getMouseDown(1)));
229 |
230 | if (getKeyDown(SDLK_ESCAPE)) {
231 | doTerminate = true;
232 | barrier->releaseAll();
233 | }
234 |
235 | float mx = float(getMouseXSpeed());
236 | float my = float(getMouseYSpeed());
237 | if (getMouseDown(0) && (mx != 0 || my != 0)) {
238 | pitch = std::fmod(pitch - my, 360.0f);
239 | yaw = std::fmod(yaw + (std::fabs(pitch) > 90.0f ? mx : -mx), 360.0f);
240 |
241 | if (pitch > 180.0f) pitch -= 360.0f;
242 | else if (pitch < -180.0f) pitch += 360.0f;
243 |
244 | MatrixStack::set(MODEL_STACK, Mat4::rotXYZ(Vec3(pitch, 0.0f, 0.0f))*
245 | Mat4::rotXYZ(Vec3(0.0f, yaw, 0.0f)));
246 | renderHalfSize = true;
247 | } else if (getMouseDown(1) && my != 0) {
248 | radius *= std::min(std::max(1.0f - my*0.01f, 0.5f), 1.5f);
249 | radius = std::min(radius, 25.0f);
250 | MatrixStack::set(VIEW_STACK, Mat4::translate(Vec3(0.0f, 0.0f, -radius)));
251 | renderHalfSize = true;
252 | } else {
253 | renderHalfSize = false;
254 | }
255 |
256 | if (SDL_MUSTLOCK(backBuffer))
257 | SDL_LockSurface(backBuffer);
258 | }
259 | }
260 |
261 | return 0;
262 | }
263 |
264 | /* Maximum allowed memory allocation sizes for lookup table and cache blocks.
265 | * Larger => faster conversion usually, but adapt this to your own RAM size.
266 | * The conversion will still succeed with memory sizes much, much smaller than
267 | * the size of the voxel data, only slower.
268 | */
269 | static const size_t dataMemory = int64_t(1024)*1024*1024;
270 |
271 | void printHelp() {
272 | std::cout << "Usage: sparse-voxel-octrees [options] filename ..." << std::endl;
273 | std::cout << "Options:" << std::endl;
274 | std::cout << "-builder set program to SVO building mode." << std::endl;
275 | std::cout << " --resolution set voxel resolution. r is an integer which equals to a power of 2." << std::endl;
276 | std::cout << " --mode set where to generate voxel data, m equals 0 or 1, where 0 indicates GENERATE_IN_MEMORY while 1 indicates GENERATE_ON_DISK." << std::endl;
277 | std::cout << "-viewer set program to SVO rendering mode." << std::endl << std::endl;
278 | std::cout << "Examples:" << std::endl;
279 | std::cout << " sparse-voxel-octrees -builder --resolution 256 --mode 0 ../models/xyzrgb_dragon.ply ../models/xyzrgb_dragon.oct" << std::endl;
280 | std::cout << " sparse-voxel-octrees -builder ../models/xyzrgb_dragon.ply ../models/xyzrgb_dragon.oct" << std::endl;
281 | std::cout << " sparse-voxel-octrees -viewer ../models/XYZRGB-Dragon.oct" << std::endl << std::endl << std::endl;
282 | }
283 |
284 | int main(int argc, char *argv[]) {
285 |
286 | unsigned int resolution = 256; //default resolution
287 | unsigned int mode = 0; //default to generate in memory
288 | std::string inputFile = "";
289 | std::string outputFile = "";
290 |
291 | /* parse arguments */
292 | if ((argc == 8) && (std::string(argv[1]) == "-builder")) {
293 | resolution = atoi(argv[3]);
294 | mode = atoi(argv[5]);
295 | inputFile = argv[6];
296 | outputFile = argv[7];
297 | }
298 | else if ((argc == 4) && (std::string(argv[1]) == "-builder")) {
299 | inputFile = argv[2];
300 | outputFile = argv[3];
301 | }
302 | else if ((argc == 3) && (std::string(argv[1]) == "-viewer"))
303 | inputFile = argv[2];
304 | else {
305 | std::cout << "Invalid arguments! Please refer to the help info!" << std::endl;
306 | printHelp();
307 | return 0;
308 | }
309 |
310 | Timer timer;
311 |
312 | if (std::string(argv[1]) == "-builder") {
313 | ThreadUtils::startThreads(ThreadUtils::idealThreadCount());
314 |
315 | if (mode) { //generate on disk
316 | std::unique_ptr loader(new PlyLoader(inputFile.c_str()));
317 | loader->convertToVolume("models/temp.voxel", resolution, dataMemory);
318 | std::unique_ptr data(new VoxelData("models/temp.voxel", dataMemory));
319 | std::unique_ptr tree(new VoxelOctree(data.get()));
320 | tree->save(outputFile.c_str());
321 | }
322 | else { //generate in memory
323 | std::unique_ptr loader(new PlyLoader(inputFile.c_str()));
324 | std::unique_ptr data(new VoxelData(loader.get(), resolution, dataMemory));
325 | std::unique_ptr tree(new VoxelOctree(data.get()));
326 | tree->save(outputFile.c_str());
327 | }
328 | timer.bench("Octree initialization took");
329 | return 0;
330 | }
331 |
332 | if (std::string(argv[1]) == "-viewer") {
333 | std::unique_ptr tree(new VoxelOctree(inputFile.c_str()));
334 |
335 | timer.bench("Octree initialization took");
336 |
337 | SDL_Init(SDL_INIT_VIDEO);
338 |
339 | SDL_WM_SetCaption("Sparse Voxel Octrees", "Sparse Voxel Octrees");
340 | backBuffer = SDL_SetVideoMode(GWidth, GHeight, 32, SDL_SWSURFACE);
341 |
342 | SDL_Thread *threads[NumThreads - 1];
343 | BatchData threadData[NumThreads];
344 |
345 | barrier = new ThreadBarrier(NumThreads);
346 | doTerminate = false;
347 |
348 | if (SDL_MUSTLOCK(backBuffer))
349 | SDL_LockSurface(backBuffer);
350 |
351 | int stride = (GHeight - 1) / NumThreads + 1;
352 | for (int i = 0; i < NumThreads; i++) {
353 | threadData[i].id = i;
354 | threadData[i].tree = tree.get();
355 | threadData[i].x0 = 0;
356 | threadData[i].x1 = GWidth;
357 | threadData[i].y0 = i*stride;
358 | threadData[i].y1 = std::min((i + 1)*stride, GHeight);
359 | threadData[i].tilesX = (threadData[i].x1 - threadData[i].x0 - 1) / TileSize + 2;
360 | threadData[i].tilesY = (threadData[i].y1 - threadData[i].y0 - 1) / TileSize + 2;
361 | threadData[i].depthBuffer = new float[threadData[i].tilesX*threadData[i].tilesY];
362 | }
363 |
364 | for (int i = 1; i < NumThreads; i++)
365 | threads[i - 1] = SDL_CreateThread(&renderLoop, (void *)&threadData[i]);
366 |
367 | renderLoop((void *)&threadData[0]);
368 |
369 | for (int i = 1; i < NumThreads; i++)
370 | SDL_WaitThread(threads[i - 1], 0);
371 |
372 | if (SDL_MUSTLOCK(backBuffer))
373 | SDL_UnlockSurface(backBuffer);
374 |
375 | SDL_Quit();
376 | }
377 |
378 | return 0;
379 | }
380 |
--------------------------------------------------------------------------------
/src/PlyLoader.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #include "PlyLoader.hpp"
25 | #include "Debug.hpp"
26 | #include "Timer.hpp"
27 | #include "Util.hpp"
28 |
29 | #include "thread/ThreadUtils.hpp"
30 | #include "thread/ThreadPool.hpp"
31 |
32 | #include "third-party/tribox3.h"
33 | #include "third-party/ply.h"
34 |
35 | #include
36 | #include
37 | #include
38 | #include
39 |
40 | Triangle::Triangle(const Vertex &_v1, const Vertex &_v2, const Vertex &_v3) :
41 | v1(_v1), v2(_v2), v3(_v3) {
42 |
43 | lower = Vec3(
44 | std::min(v1.pos.x, std::min(v2.pos.x, v3.pos.x)),
45 | std::min(v1.pos.y, std::min(v2.pos.y, v3.pos.y)),
46 | std::min(v1.pos.z, std::min(v2.pos.z, v3.pos.z))
47 | );
48 | upper = Vec3(
49 | std::max(v1.pos.x, std::max(v2.pos.x, v3.pos.x)),
50 | std::max(v1.pos.y, std::max(v2.pos.y, v3.pos.y)),
51 | std::max(v1.pos.z, std::max(v2.pos.z, v3.pos.z))
52 | );
53 | }
54 |
55 | bool Triangle::barycentric(const Vec3 &p, float &lambda1, float &lambda2) const {
56 | Vec3 f1 = v1.pos - p;
57 | Vec3 f2 = v2.pos - p;
58 | Vec3 f3 = v3.pos - p;
59 | float area = (v1.pos - v2.pos).cross(v1.pos - v3.pos).length();
60 | lambda1 = f2.cross(f3).length()/area;
61 | lambda2 = f3.cross(f1).length()/area;
62 |
63 | return lambda1 >= 0.0f && lambda2 >= 0.0f && lambda1 + lambda2 <= 1.0f;
64 | }
65 |
66 | PlyLoader::PlyLoader(const char *path) : _isBigEndian(false), _lower(1e30f), _upper(-1e30f) {
67 | PlyFile *file;
68 |
69 | openPly(path, file);
70 | readVertices(file);
71 | rescaleVertices();
72 | readTriangles(file);
73 | ply_close(file);
74 |
75 | std::cout << "Triangle count: " << _tris.size() << ", taking up "
76 | << prettyPrintMemory(_tris.size()*sizeof(Triangle)) << " of memory" << std::endl;
77 |
78 | std::vector().swap(_verts); /* Get rid of vertex data */
79 | }
80 |
81 | void PlyLoader::openPly(const char *path, PlyFile *&file) {
82 | int elemCount, fileType;
83 | char **elemNames;
84 | float version;
85 | file = ply_open_for_reading(path, &elemCount, &elemNames, &fileType, &version);
86 |
87 | ASSERT(file != 0, "Failed to open PLY at %s\n", path);
88 |
89 | _isBigEndian = (file->file_type == PLY_BINARY_BE);
90 |
91 | bool hasVerts = false, hasTris = false;
92 | for (int i = 0; i < elemCount; i++) {
93 | if (!strcmp(elemNames[i], "vertex"))
94 | hasVerts = true;
95 | else if (!strcmp(elemNames[i], "face"))
96 | hasTris = true;
97 | else
98 | DBG("PLY loader", WARN, "Ignoring unknown element %s\n", elemNames[i]);
99 | }
100 |
101 | ASSERT(hasVerts && hasTris, "PLY file has to have triangles and vertices\n");
102 | }
103 |
104 | template
105 | T toHostOrder(T src, bool isBigEndian)
106 | {
107 | if (!isBigEndian)
108 | return src;
109 |
110 | union {
111 | char bytes[sizeof(T)];
112 | T type;
113 | } srcBytes, dstBytes;
114 |
115 | srcBytes.type = src;
116 | for (size_t i = 0; i < sizeof(T); ++i)
117 | dstBytes.bytes[i] = srcBytes.bytes[sizeof(T) - i - 1];
118 |
119 | return dstBytes.type;
120 | }
121 |
122 | void PlyLoader::readVertices(PlyFile *file) {
123 | int vertCount, vertPropCount;
124 | PlyProperty **vertProps = ply_get_element_description(file, "vertex", &vertCount, &vertPropCount);
125 |
126 | _verts.reserve(vertCount);
127 |
128 | const char *vpNames[] = {"x", "y", "z", "nx", "ny", "nz", "red", "green", "blue"};
129 | bool vpAvail[9] = {false};
130 | for (int i = 0; i < vertPropCount; i++) {
131 | for (int t = 0; t < 9; t++) {
132 | if (!strcmp(vertProps[i]->name, vpNames[t])) {
133 | vertProps[i]->internal_type = PLY_FLOAT;
134 | vertProps[i]->offset = t*sizeof(float);
135 | ply_get_property(file, "vertex", vertProps[i]);
136 | vpAvail[t] = true;
137 | break;
138 | }
139 | }
140 | }
141 |
142 | _hasNormals = vpAvail[3] && vpAvail[4] && vpAvail[5];
143 |
144 | float vertData[9], elemData[9];
145 | float vertDefault[] = {
146 | 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 255.0f, 255.0f, 255.0f
147 | };
148 | for (int i = 0; i < vertCount; i++) {
149 | ply_get_element(file, (void *)elemData);
150 |
151 | for (int t = 0; t < 9; t++)
152 | vertData[t] = (vpAvail[t] ? toHostOrder(elemData[t], _isBigEndian) : vertDefault[t]);
153 |
154 | _verts.push_back(Vertex(
155 | Vec3(vertData[0], vertData[1], vertData[2]),
156 | Vec3(vertData[3], vertData[4], vertData[5]),
157 | Vec3(vertData[6], vertData[7], vertData[8])
158 | ));
159 |
160 | for (int t = 0; t < 3; t++) {
161 | _lower.a[t] = std::min(_lower.a[t], vertData[t]);
162 | _upper.a[t] = std::max(_upper.a[t], vertData[t]);
163 | }
164 | }
165 | }
166 |
167 | void PlyLoader::rescaleVertices() {
168 | Vec3 diff = _upper - _lower;
169 | int largestDim = 2;
170 | if (diff.x > diff.y && diff.x > diff.z)
171 | largestDim = 0;
172 | else if (diff.y > diff.z)
173 | largestDim = 1;
174 | float factor = 1.0f/diff.a[largestDim];
175 |
176 | for (unsigned i = 0; i < _verts.size(); i++)
177 | _verts[i].pos = (_verts[i].pos - _lower)*factor;
178 |
179 | _upper *= factor;
180 | _lower *= factor;
181 | }
182 |
183 | void PlyLoader::readTriangles(PlyFile *file) {
184 | int triCount, triPropCount;
185 | PlyProperty **triProps = ply_get_element_description(file, "face", &triCount, &triPropCount);
186 |
187 | _tris.reserve(triCount);
188 |
189 | for (int i = 0; i < triPropCount; i++) {
190 | if (!strcmp(triProps[i]->name, "vertex_indices")) {
191 | triProps[i]->count_internal = PLY_INT;
192 | triProps[i]->internal_type = PLY_INT;
193 | triProps[i]->offset = 0;
194 | triProps[i]->count_offset = sizeof(int*);
195 | ply_get_property(file, "face", triProps[i]);
196 | break;
197 | } else if (i == triPropCount - 1)
198 | FAIL("No face information found\n");
199 | }
200 |
201 | struct { int *elems; int count; } face;
202 | for (int i = 0; i < triCount; i++) {
203 | ply_get_element(file, (void *)&face);
204 |
205 | if (!face.count)
206 | continue;
207 |
208 | int v0 = toHostOrder(face.elems[0], _isBigEndian);
209 | int v1 = toHostOrder(face.elems[1], _isBigEndian);
210 | for (int t = 2; t < face.count; t++) {
211 | int v2 = toHostOrder(face.elems[t], _isBigEndian);
212 | _tris.push_back(Triangle(_verts[v0], _verts[v1], _verts[v2]));
213 | if (!_hasNormals) {
214 | Vec3 n = (_verts[v1].pos - _verts[v0].pos).cross(_verts[v2].pos - _verts[v0].pos).normalize();
215 | _tris.back().v1.normal = n;
216 | _tris.back().v2.normal = n;
217 | _tris.back().v3.normal = n;
218 | }
219 | v1 = v2;
220 | }
221 |
222 | free(face.elems);
223 | }
224 | }
225 |
226 | void PlyLoader::pointToGrid(const Vec3 &p, int &x, int &y, int &z)
227 | {
228 | x = (int)(p.x*(_sideLength - 2) + 1.0f);
229 | y = (int)(p.y*(_sideLength - 2) + 1.0f);
230 | z = (int)(p.z*(_sideLength - 2) + 1.0f);
231 | }
232 |
233 | template
234 | void PlyLoader::iterateOverlappingBlocks(const Triangle &t, LoopBody body)
235 | {
236 | int lx, ly, lz;
237 | int ux, uy, uz;
238 | pointToGrid(t.lower, lx, ly, lz);
239 | pointToGrid(t.upper, ux, uy, uz);
240 | int lgridX = (lx + 0)/_subBlockW, lgridY = (ly + 0)/_subBlockH, lgridZ = (lz + 0)/_subBlockD;
241 | int ugridX = (ux + 1)/_subBlockW, ugridY = (uy + 1)/_subBlockH, ugridZ = (uz + 1)/_subBlockD;
242 |
243 | int maxSide = std::max(ugridX - lgridX, std::max(ugridY - lgridY, ugridZ - lgridZ));
244 |
245 | if (maxSide > 0) {
246 | float hx = _subBlockW/float(_sideLength - 2);
247 | float hy = _subBlockH/float(_sideLength - 2);
248 | float hz = _subBlockD/float(_sideLength - 2);
249 | float triVs[][3] = {
250 | {t.v1.pos.x, t.v1.pos.y, t.v1.pos.z},
251 | {t.v2.pos.x, t.v2.pos.y, t.v2.pos.z},
252 | {t.v3.pos.x, t.v3.pos.y, t.v3.pos.z}
253 | };
254 | float halfSize[] = {0.5f*hx, 0.5f*hy, 0.5f*hz};
255 | float center[3];
256 |
257 | center[2] = (lgridZ + 0.5f)*hz;
258 | for (int z = lgridZ; z <= ugridZ; ++z, center[2] += hz) {
259 | center[1] = (lgridY + 0.5f)*hy;
260 | for (int y = lgridY; y <= ugridY; ++y, center[1] += hy) {
261 | center[0] = (lgridX + 0.5f)*hx;
262 | for (int x = lgridX; x <= ugridX; ++x, center[0] += hx)
263 | if (triBoxOverlap(center, halfSize, triVs))
264 | body(x + _gridW*(y + _gridH*z));
265 | }
266 | }
267 | } else {
268 | body(lgridX + _gridW*(lgridY + _gridH*lgridZ));
269 | }
270 | }
271 |
272 | void PlyLoader::buildBlockLists()
273 | {
274 | _blockOffsets.resize(_gridW*_gridH*_gridD + 1, 0);
275 |
276 | for (size_t i = 0; i < _tris.size(); ++i)
277 | iterateOverlappingBlocks(_tris[i], [&](size_t idx) { _blockOffsets[1 + idx]++; });
278 |
279 | for (size_t i = 1; i < _blockOffsets.size(); ++i)
280 | _blockOffsets[i] += _blockOffsets[i - 1];
281 |
282 | _blockLists.reset(new uint32[_blockOffsets.back()]);
283 |
284 | for (uint32 i = 0; i < _tris.size(); ++i)
285 | iterateOverlappingBlocks(_tris[i], [&](size_t idx) { _blockLists[_blockOffsets[idx]++] = i; });
286 |
287 | for (int i = int(_blockOffsets.size() - 1); i >= 1; --i)
288 | _blockOffsets[i] = _blockOffsets[i - 1];
289 | _blockOffsets[0] = 0;
290 |
291 | std::cout << "PlyLoader block lists take up an additional "
292 | << prettyPrintMemory((_blockOffsets.size() + _blockOffsets.back())*sizeof(uint32))
293 | << " of memory" << std::endl;
294 | }
295 |
296 | void PlyLoader::writeTriangleCell(uint32 *data, int x, int y, int z,
297 | float cx, float cy, float cz, const Triangle &t) {
298 | size_t idx = (x - _bufferX) + size_t(_bufferW)*(y - _bufferY + size_t(_bufferH)*(z - _bufferZ));
299 |
300 | float lambda1, lambda2, lambda3;
301 | if (!t.barycentric(Vec3(cx, cy, cz), lambda1, lambda2)) {
302 | lambda1 = std::min(std::max(lambda1, 0.0f), 1.0f);
303 | lambda2 = std::min(std::max(lambda2, 0.0f), 1.0f);
304 | float tau = lambda1 + lambda2;
305 | if (tau > 1.0f) {
306 | lambda1 /= tau;
307 | lambda2 /= tau;
308 | }
309 | }
310 | lambda3 = 1.0f - lambda1 - lambda2;
311 |
312 | Vec3 normal = (t.v1.normal*lambda1 + t.v2.normal*lambda2 + t.v3.normal*lambda3).normalize();
313 | Vec3 color = t.v1.color*lambda1 + t.v2.color*lambda2 + t.v3.color*lambda3;
314 | /* Only store luminance - we only care about AO anyway */
315 | float shade = color.dot(Vec3(0.2126f, 0.7152f, 0.0722f))*(1.0f/256.0f);
316 |
317 | if (data[idx] == 0) {
318 | _counts[idx] = 1;
319 | data[idx] = compressMaterial(normal, shade);
320 | } else {
321 | float currentRatio = _counts[idx]/(_counts[idx] + 1.0f);
322 | float newRatio = 1.0f - currentRatio;
323 |
324 | Vec3 currentNormal;
325 | float currentShade;
326 | decompressMaterial(data[idx], currentNormal, currentShade);
327 |
328 | Vec3 newNormal = currentNormal*currentRatio + normal*newRatio;
329 | float newShade = currentShade*currentRatio + shade*newRatio;
330 | if (newNormal.dot(newNormal) < 1e-3f)
331 | newNormal = currentNormal;
332 |
333 | data[idx] = compressMaterial(newNormal, newShade);
334 | _counts[idx] = std::min(int(_counts[idx]) + 1, 255);
335 | }
336 | }
337 |
338 | void PlyLoader::triangleToVolume(uint32 *data, const Triangle &t, int offX, int offY, int offZ) {
339 | int lx, ly, lz;
340 | int ux, uy, uz;
341 | pointToGrid(t.lower, lx, ly, lz);
342 | pointToGrid(t.upper, ux, uy, uz);
343 |
344 | lx = std::max(lx, _bufferX + offX);
345 | ly = std::max(ly, _bufferY + offY);
346 | lz = std::max(lz, _bufferZ + offZ);
347 | ux = std::min(ux, _bufferX + std::min(offX + _subBlockW, _bufferW) - 1);
348 | uy = std::min(uy, _bufferY + std::min(offY + _subBlockH, _bufferH) - 1);
349 | uz = std::min(uz, _bufferZ + std::min(offZ + _subBlockD, _bufferD) - 1);
350 |
351 | if (lx > ux || ly > uy || lz > uz)
352 | return;
353 |
354 | float hx = 1.0f/(_sideLength - 2);
355 | float triVs[][3] = {
356 | {t.v1.pos.x, t.v1.pos.y, t.v1.pos.z},
357 | {t.v2.pos.x, t.v2.pos.y, t.v2.pos.z},
358 | {t.v3.pos.x, t.v3.pos.y, t.v3.pos.z}
359 | };
360 | float halfSize[] = {0.5f*hx, 0.5f*hx, 0.5f*hx};
361 | float center[3];
362 |
363 | center[2] = (lz - 0.5f)*hx;
364 | for (int z = lz; z <= uz; z++, center[2] += hx) {
365 | center[1] = (ly - 0.5f)*hx;
366 | for (int y = ly; y <= uy; y++, center[1] += hx) {
367 | center[0] = (lx - 0.5f)*hx;
368 | for (int x = lx; x <= ux; x++, center[0] += hx) {
369 | if (triBoxOverlap(center, halfSize, triVs))
370 | writeTriangleCell(data, x, y, z, center[0], center[1], center[2], t);
371 | }
372 | }
373 | }
374 | }
375 |
376 | size_t PlyLoader::blockMemRequirement(int w, int h, int d) {
377 | size_t elementCost = sizeof(uint8);
378 | return elementCost*size_t(w)*size_t(h)*size_t(d);
379 | }
380 |
381 | void findBestBlockPartition(int &w, int &h, int &d, int numThreads)
382 | {
383 | auto maximum = [&]() -> int& {
384 | if (w > h && w > d) return w; else if (h > d) return h; else return d;
385 | };
386 | auto median = [&]() -> int& {
387 | int max = std::max(w, std::max(h, d));
388 | int min = std::min(w, std::min(h, d));
389 | if (w != min && w != max) return w;
390 | else if (h != min && h != max) return h;
391 | else return d;
392 | };
393 | auto minimum = [&]() -> int& {
394 | if (w < h && w < d) return w; else if (h < d) return h; else return d;
395 | };
396 |
397 | int usedThreads = 1;
398 | while (usedThreads < numThreads) {
399 | if ((maximum() % 2) == 0) maximum() /= 2;
400 | else if (( median() % 2) == 0) median() /= 2;
401 | else if ((minimum() % 2) == 0) minimum() /= 2;
402 | else break;
403 | usedThreads *= 2;
404 | }
405 | }
406 |
407 | void PlyLoader::setupBlockProcessing(int sideLength, int blockW, int blockH, int blockD,
408 | int volumeW, int volumeH, int volumeD) {
409 | _conversionTimer.start();
410 |
411 | size_t elementCount = size_t(blockW)*size_t(blockH)*size_t(blockD);
412 | _counts.reset(new uint8[elementCount]);
413 |
414 | _sideLength = sideLength - 2;
415 | _blockW = _subBlockW = blockW;
416 | _blockH = _subBlockH = blockH;
417 | _blockD = _subBlockD = blockD;
418 | findBestBlockPartition(_subBlockW, _subBlockH, _subBlockD, ThreadUtils::pool->threadCount());
419 | _partitionW = _blockW/_subBlockW;
420 | _partitionH = _blockH/_subBlockH;
421 | _partitionD = _blockD/_subBlockD;
422 | _numPartitions = _partitionW*_partitionH*_partitionD;
423 | std::cout << "Partitioning cache block into " << _partitionW << "x" << _partitionH
424 | << "x" << _partitionD << " over " << _numPartitions << " threads (per thread block is "
425 | << _subBlockW << "x" << _subBlockH << "x" << _subBlockD << ")" << std::endl;
426 | _volumeW = volumeW;
427 | _volumeH = volumeH;
428 | _volumeD = volumeD;
429 | _gridW = _partitionW*(_volumeW + _blockW - 1)/_blockW;
430 | _gridH = _partitionH*(_volumeH + _blockH - 1)/_blockH;
431 | _gridD = _partitionD*(_volumeD + _blockD - 1)/_blockD;
432 |
433 | _processedBlocks = 0;
434 | _numNonZeroBlocks = 0;
435 |
436 | buildBlockLists();
437 | }
438 |
439 | void PlyLoader::processBlock(uint32 *data, int x, int y, int z, int w, int h, int d) {
440 | _bufferX = x;
441 | _bufferY = y;
442 | _bufferZ = z;
443 | _bufferW = w;
444 | _bufferH = h;
445 | _bufferD = d;
446 |
447 | ThreadUtils::pool->enqueue([&](uint32 i, uint32, uint32){
448 | int px = i % _partitionW;
449 | int py = (i/_partitionW) % _partitionH;
450 | int pz = i/(_partitionW*_partitionH);
451 |
452 | int blockIdx = (x/_subBlockW + px) + _gridW*((y/_subBlockH + py) + _gridH*(z/_subBlockD + pz));
453 | int start = _blockOffsets[blockIdx];
454 | int end = _blockOffsets[blockIdx + 1];
455 |
456 | for (int i = start; i < end; ++i)
457 | triangleToVolume(data, _tris[_blockLists[i]], px*_subBlockW, py*_subBlockH, pz*_subBlockD);
458 | }, _numPartitions)->wait();
459 |
460 | _processedBlocks++;
461 |
462 | _conversionTimer.stop();
463 | double elapsed = _conversionTimer.elapsed();
464 |
465 | std::cout << "Processed block " << _processedBlocks << "/" << _numNonZeroBlocks
466 | << " (" << (_processedBlocks*100)/_numNonZeroBlocks << "%) after "
467 | << int(elapsed) << " seconds. ";
468 | if (_processedBlocks < _numNonZeroBlocks)
469 | std::cout << "Approximate time to finish: " << int((_numNonZeroBlocks - _processedBlocks)*elapsed/_processedBlocks)
470 | << " seconds.";
471 | else
472 | std::cout << "All blocks processed! Post processing...";
473 | std::cout << std::endl;
474 | }
475 |
476 | bool PlyLoader::isBlockEmpty(int x, int y, int z)
477 | {
478 | for (int pz = 0; pz < _partitionD; ++pz) {
479 | for (int py = 0; py < _partitionH; ++py) {
480 | for (int px = 0; px < _partitionW; ++px) {
481 | int blockIdx = (x/_subBlockW + px) + _gridW*((y/_subBlockH + py) + _gridH*(z/_subBlockD + pz));
482 | int start = _blockOffsets[blockIdx];
483 | int end = _blockOffsets[blockIdx + 1];
484 |
485 | if (start != end) {
486 | _numNonZeroBlocks++;
487 | return false;
488 | }
489 | }
490 | }
491 | }
492 | return true;
493 | }
494 |
495 | void PlyLoader::teardownBlockProcessing() {
496 | _counts.reset();
497 | }
498 |
499 | void PlyLoader::suggestedDimensions(int sideLength, int &w, int &h, int &d) {
500 | Vec3 sizes = (_upper - _lower)*float(sideLength - 2);
501 | w = int(sizes.x) + 2;
502 | h = int(sizes.y) + 2;
503 | d = int(sizes.z) + 2;
504 | }
505 |
506 | void PlyLoader::convertToVolume(const char *path, int maxSize, size_t memoryBudget) {
507 | FILE *fp = fopen(path, "wb");
508 | if (!fp)
509 | return;
510 |
511 | int w, h, d;
512 | suggestedDimensions(maxSize, w, h, d);
513 |
514 | size_t sliceCost = blockMemRequirement(w, h, 1);
515 | int sliceZ = std::min((int)(memoryBudget/sliceCost), d);
516 | ASSERT(sliceZ != 0, "Not enough memory available for single slice");
517 |
518 | uint32 *data = new uint32[size_t(w)*size_t(h)*size_t(sliceZ)];
519 | setupBlockProcessing(maxSize, w, h, sliceZ, w, h, d);
520 |
521 | fwrite(&w, 4, 1, fp);
522 | fwrite(&h, 4, 1, fp);
523 | fwrite(&d, 4, 1, fp);
524 |
525 | for (int z = 0; z < d; z += sliceZ) {
526 | processBlock(data, 0, 0, z, w, h, sliceZ);
527 |
528 | fwrite(data, sizeof(uint32), size_t(w)*size_t(h)*size_t(std::min(sliceZ, d - z)), fp);
529 | }
530 | fclose(fp);
531 |
532 | teardownBlockProcessing();
533 | delete[] data;
534 | }
535 |
--------------------------------------------------------------------------------
/src/PlyLoader.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef PLYLOADER_HPP_
25 | #define PLYLOADER_HPP_
26 |
27 | #include "math/Vec3.hpp"
28 |
29 | #include "IntTypes.hpp"
30 | #include "Timer.hpp"
31 |
32 | #include
33 | #include
34 |
35 | struct PlyFile;
36 |
37 | struct Vertex {
38 | Vec3 pos, normal, color;
39 |
40 | Vertex() {};
41 | Vertex(const Vec3 &p, const Vec3 &n, const Vec3 &c) :
42 | pos(p), normal(n), color(c) {}
43 | };
44 |
45 | struct Triangle {
46 | Vertex v1, v2, v3;
47 | Vec3 lower, upper;
48 |
49 | bool barycentric(const Vec3 &p, float &lambda1, float &lambda2) const;
50 |
51 | Triangle() {};
52 | Triangle(const Vertex &_v1, const Vertex &_v2, const Vertex &_v3);
53 | };
54 |
55 | class PlyLoader {
56 | bool _hasNormals;
57 | bool _isBigEndian;
58 |
59 | std::vector _verts;
60 | std::vector _tris;
61 | std::vector _blockOffsets;
62 | std::unique_ptr _blockLists;
63 |
64 | Timer _conversionTimer;
65 | int _processedBlocks;
66 | int _numNonZeroBlocks;
67 | Vec3 _lower, _upper;
68 |
69 | std::unique_ptr _counts;
70 | int _sideLength;
71 | int _volumeW, _volumeH, _volumeD;
72 | int _blockW, _blockH, _blockD;
73 | int _subBlockW, _subBlockH, _subBlockD;
74 | int _partitionW, _partitionH, _partitionD;
75 | int _numPartitions;
76 | int _gridW, _gridH, _gridD;
77 | int _bufferX, _bufferY, _bufferZ;
78 | int _bufferW, _bufferH, _bufferD;
79 |
80 | void writeTriangleCell(uint32 *data, int x, int y, int z,
81 | float cx, float cy, float cz, const Triangle &t);
82 | void triangleToVolume(uint32 *data, const Triangle &t, int offX, int offY, int offZ);
83 |
84 | void openPly(const char *path, PlyFile *&file);
85 | void readVertices(PlyFile *file);
86 | void rescaleVertices();
87 | void readTriangles(PlyFile *file);
88 |
89 | void pointToGrid(const Vec3 &p, int &x, int &y, int &z);
90 |
91 | template
92 | void iterateOverlappingBlocks(const Triangle &t, LoopBody body);
93 |
94 | void buildBlockLists();
95 |
96 | public:
97 | PlyLoader(const char *path);
98 |
99 | void suggestedDimensions(int sideLength, int &w, int &h, int &d);
100 |
101 | size_t blockMemRequirement(int w, int h, int d);
102 | void setupBlockProcessing(int sideLength, int blockW, int blockH, int blockD,
103 | int volumeW, int volumeH, int volumeD);
104 | void processBlock(uint32 *data, int x, int y, int z, int w, int h, int d);
105 | bool isBlockEmpty(int x, int y, int z);
106 | void teardownBlockProcessing();
107 |
108 | void convertToVolume(const char *path, int maxSize, size_t memoryBudget);
109 |
110 | const std::vector &tris() const {
111 | return _tris;
112 | }
113 | };
114 |
115 | #endif /* OBJLOADER_HPP_ */
116 |
--------------------------------------------------------------------------------
/src/SDLMain.h:
--------------------------------------------------------------------------------
1 | /* SDLMain.m - main entry point for our Cocoa-ized SDL app
2 | Initial Version: Darrell Walisser
3 | Non-NIB-Code & other changes: Max Horn
4 |
5 | Feel free to customize this file to suit your needs
6 | */
7 |
8 | #ifndef _SDLMain_h_
9 | #define _SDLMain_h_
10 |
11 | #import
12 |
13 | @interface SDLMain : NSObject
14 | @end
15 |
16 | #endif /* _SDLMain_h_ */
17 |
--------------------------------------------------------------------------------
/src/SDLMain.m:
--------------------------------------------------------------------------------
1 | /* SDLMain.m - main entry point for our Cocoa-ized SDL app
2 | Initial Version: Darrell Walisser
3 | Non-NIB-Code & other changes: Max Horn
4 |
5 | Feel free to customize this file to suit your needs
6 | */
7 |
8 | #include
9 | #include "SDLMain.h"
10 | #include /* for MAXPATHLEN */
11 | #include
12 |
13 | /* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
14 | but the method still is there and works. To avoid warnings, we declare
15 | it ourselves here. */
16 | @interface NSApplication(SDL_Missing_Methods)
17 | - (void)setAppleMenu:(NSMenu *)menu;
18 | @end
19 |
20 | /* Use this flag to determine whether we use SDLMain.nib or not */
21 | #define SDL_USE_NIB_FILE 0
22 |
23 | /* Use this flag to determine whether we use CPS (docking) or not */
24 | #define SDL_USE_CPS 1
25 | #ifdef SDL_USE_CPS
26 | /* Portions of CPS.h */
27 | typedef struct CPSProcessSerNum
28 | {
29 | UInt32 lo;
30 | UInt32 hi;
31 | } CPSProcessSerNum;
32 |
33 | extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
34 | extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
35 | extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
36 |
37 | #endif /* SDL_USE_CPS */
38 |
39 | static int gArgc;
40 | static char **gArgv;
41 | static BOOL gFinderLaunch;
42 | static BOOL gCalledAppMainline = FALSE;
43 |
44 | static NSString *getApplicationName(void)
45 | {
46 | const NSDictionary *dict;
47 | NSString *appName = 0;
48 |
49 | /* Determine the application name */
50 | dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
51 | if (dict)
52 | appName = [dict objectForKey: @"CFBundleName"];
53 |
54 | if (![appName length])
55 | appName = [[NSProcessInfo processInfo] processName];
56 |
57 | return appName;
58 | }
59 |
60 | #if SDL_USE_NIB_FILE
61 | /* A helper category for NSString */
62 | @interface NSString (ReplaceSubString)
63 | - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
64 | @end
65 | #endif
66 |
67 | @interface NSApplication (SDLApplication)
68 | @end
69 |
70 | @implementation NSApplication (SDLApplication)
71 | /* Invoked from the Quit menu item */
72 | - (void)terminate:(id)sender
73 | {
74 | /* Post a SDL_QUIT event */
75 | SDL_Event event;
76 | event.type = SDL_QUIT;
77 | SDL_PushEvent(&event);
78 | }
79 | @end
80 |
81 | /* The main class of the application, the application's delegate */
82 | @implementation SDLMain
83 |
84 | /* Set the working directory to the .app's parent directory */
85 | - (void) setupWorkingDirectory:(BOOL)shouldChdir
86 | {
87 | if (shouldChdir)
88 | {
89 | char parentdir[MAXPATHLEN];
90 | CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
91 | CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
92 | if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) {
93 | chdir(parentdir); /* chdir to the binary app's parent */
94 | }
95 | CFRelease(url);
96 | CFRelease(url2);
97 | }
98 | }
99 |
100 | #if SDL_USE_NIB_FILE
101 |
102 | /* Fix menu to contain the real app name instead of "SDL App" */
103 | - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
104 | {
105 | NSRange aRange;
106 | NSEnumerator *enumerator;
107 | NSMenuItem *menuItem;
108 |
109 | aRange = [[aMenu title] rangeOfString:@"SDL App"];
110 | if (aRange.length != 0)
111 | [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
112 |
113 | enumerator = [[aMenu itemArray] objectEnumerator];
114 | while ((menuItem = [enumerator nextObject]))
115 | {
116 | aRange = [[menuItem title] rangeOfString:@"SDL App"];
117 | if (aRange.length != 0)
118 | [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
119 | if ([menuItem hasSubmenu])
120 | [self fixMenu:[menuItem submenu] withAppName:appName];
121 | }
122 | }
123 |
124 | #else
125 |
126 | static void setApplicationMenu(void)
127 | {
128 | /* warning: this code is very odd */
129 | NSMenu *appleMenu;
130 | NSMenuItem *menuItem;
131 | NSString *title;
132 | NSString *appName;
133 |
134 | appName = getApplicationName();
135 | appleMenu = [[NSMenu alloc] initWithTitle:@""];
136 |
137 | /* Add menu items */
138 | title = [@"About " stringByAppendingString:appName];
139 | [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
140 |
141 | [appleMenu addItem:[NSMenuItem separatorItem]];
142 |
143 | title = [@"Hide " stringByAppendingString:appName];
144 | [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
145 |
146 | menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
147 | [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
148 |
149 | [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
150 |
151 | [appleMenu addItem:[NSMenuItem separatorItem]];
152 |
153 | title = [@"Quit " stringByAppendingString:appName];
154 | [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
155 |
156 |
157 | /* Put menu into the menubar */
158 | menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
159 | [menuItem setSubmenu:appleMenu];
160 | [[NSApp mainMenu] addItem:menuItem];
161 |
162 | /* Tell the application object that this is now the application menu */
163 | [NSApp setAppleMenu:appleMenu];
164 |
165 | /* Finally give up our references to the objects */
166 | [appleMenu release];
167 | [menuItem release];
168 | }
169 |
170 | /* Create a window menu */
171 | static void setupWindowMenu(void)
172 | {
173 | NSMenu *windowMenu;
174 | NSMenuItem *windowMenuItem;
175 | NSMenuItem *menuItem;
176 |
177 | windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
178 |
179 | /* "Minimize" item */
180 | menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
181 | [windowMenu addItem:menuItem];
182 | [menuItem release];
183 |
184 | /* Put menu into the menubar */
185 | windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
186 | [windowMenuItem setSubmenu:windowMenu];
187 | [[NSApp mainMenu] addItem:windowMenuItem];
188 |
189 | /* Tell the application object that this is now the window menu */
190 | [NSApp setWindowsMenu:windowMenu];
191 |
192 | /* Finally give up our references to the objects */
193 | [windowMenu release];
194 | [windowMenuItem release];
195 | }
196 |
197 | /* Replacement for NSApplicationMain */
198 | static void CustomApplicationMain (int argc, char **argv)
199 | {
200 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
201 | SDLMain *sdlMain;
202 |
203 | /* Ensure the application object is initialised */
204 | [NSApplication sharedApplication];
205 |
206 | #ifdef SDL_USE_CPS
207 | {
208 | CPSProcessSerNum PSN;
209 | /* Tell the dock about us */
210 | if (!CPSGetCurrentProcess(&PSN))
211 | if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
212 | if (!CPSSetFrontProcess(&PSN))
213 | [NSApplication sharedApplication];
214 | }
215 | #endif /* SDL_USE_CPS */
216 |
217 | /* Set up the menubar */
218 | [NSApp setMainMenu:[[NSMenu alloc] init]];
219 | setApplicationMenu();
220 | setupWindowMenu();
221 |
222 | /* Create SDLMain and make it the app delegate */
223 | sdlMain = [[SDLMain alloc] init];
224 | [NSApp setDelegate:sdlMain];
225 |
226 | /* Start the main event loop */
227 | [NSApp run];
228 |
229 | [sdlMain release];
230 | [pool release];
231 | }
232 |
233 | #endif
234 |
235 |
236 | /*
237 | * Catch document open requests...this lets us notice files when the app
238 | * was launched by double-clicking a document, or when a document was
239 | * dragged/dropped on the app's icon. You need to have a
240 | * CFBundleDocumentsType section in your Info.plist to get this message,
241 | * apparently.
242 | *
243 | * Files are added to gArgv, so to the app, they'll look like command line
244 | * arguments. Previously, apps launched from the finder had nothing but
245 | * an argv[0].
246 | *
247 | * This message may be received multiple times to open several docs on launch.
248 | *
249 | * This message is ignored once the app's mainline has been called.
250 | */
251 | - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
252 | {
253 | const char *temparg;
254 | size_t arglen;
255 | char *arg;
256 | char **newargv;
257 |
258 | if (!gFinderLaunch) /* MacOS is passing command line args. */
259 | return FALSE;
260 |
261 | if (gCalledAppMainline) /* app has started, ignore this document. */
262 | return FALSE;
263 |
264 | temparg = [filename UTF8String];
265 | arglen = SDL_strlen(temparg) + 1;
266 | arg = (char *) SDL_malloc(arglen);
267 | if (arg == NULL)
268 | return FALSE;
269 |
270 | newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
271 | if (newargv == NULL)
272 | {
273 | SDL_free(arg);
274 | return FALSE;
275 | }
276 | gArgv = newargv;
277 |
278 | SDL_strlcpy(arg, temparg, arglen);
279 | gArgv[gArgc++] = arg;
280 | gArgv[gArgc] = NULL;
281 | return TRUE;
282 | }
283 |
284 |
285 | /* Called when the internal event loop has just started running */
286 | - (void) applicationDidFinishLaunching: (NSNotification *) note
287 | {
288 | int status;
289 |
290 | /* Set the working directory to the .app's parent directory */
291 | [self setupWorkingDirectory:gFinderLaunch];
292 |
293 | #if SDL_USE_NIB_FILE
294 | /* Set the main menu to contain the real app name instead of "SDL App" */
295 | [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
296 | #endif
297 |
298 | /* Hand off to main application code */
299 | gCalledAppMainline = TRUE;
300 | status = SDL_main (gArgc, gArgv);
301 |
302 | /* We're done, thank you for playing */
303 | exit(status);
304 | }
305 | @end
306 |
307 |
308 | @implementation NSString (ReplaceSubString)
309 |
310 | - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
311 | {
312 | unsigned int bufferSize;
313 | unsigned int selfLen = [self length];
314 | unsigned int aStringLen = [aString length];
315 | unichar *buffer;
316 | NSRange localRange;
317 | NSString *result;
318 |
319 | bufferSize = selfLen + aStringLen - aRange.length;
320 | buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));
321 |
322 | /* Get first part into buffer */
323 | localRange.location = 0;
324 | localRange.length = aRange.location;
325 | [self getCharacters:buffer range:localRange];
326 |
327 | /* Get middle part into buffer */
328 | localRange.location = 0;
329 | localRange.length = aStringLen;
330 | [aString getCharacters:(buffer+aRange.location) range:localRange];
331 |
332 | /* Get last part into buffer */
333 | localRange.location = aRange.location + aRange.length;
334 | localRange.length = selfLen - localRange.location;
335 | [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
336 |
337 | /* Build output string */
338 | result = [NSString stringWithCharacters:buffer length:bufferSize];
339 |
340 | NSDeallocateMemoryPages(buffer, bufferSize);
341 |
342 | return result;
343 | }
344 |
345 | @end
346 |
347 |
348 |
349 | #ifdef main
350 | # undef main
351 | #endif
352 |
353 |
354 | /* Main entry point to executable - should *not* be SDL_main! */
355 | int main (int argc, char **argv)
356 | {
357 | /* Copy the arguments into a global variable */
358 | /* This is passed if we are launched by double-clicking */
359 | if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
360 | gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
361 | gArgv[0] = argv[0];
362 | gArgv[1] = NULL;
363 | gArgc = 1;
364 | gFinderLaunch = YES;
365 | } else {
366 | int i;
367 | gArgc = argc;
368 | gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
369 | for (i = 0; i <= argc; i++)
370 | gArgv[i] = argv[i];
371 | gFinderLaunch = NO;
372 | }
373 |
374 | #if SDL_USE_NIB_FILE
375 | NSApplicationMain (argc, argv);
376 | #else
377 | CustomApplicationMain (argc, argv);
378 | #endif
379 | return 0;
380 | }
381 |
382 |
--------------------------------------------------------------------------------
/src/ThreadBarrier.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #include "ThreadBarrier.hpp"
25 |
26 | #include
27 |
28 | ThreadBarrier::ThreadBarrier(int numThreads) : _numThreads(numThreads) {
29 | _barrierMutex = SDL_CreateMutex();
30 | _turnstile1 = SDL_CreateSemaphore(0);
31 | _turnstile2 = SDL_CreateSemaphore(0);
32 | _waitCount = 0;
33 | }
34 |
35 | ThreadBarrier::~ThreadBarrier() {
36 | SDL_DestroyMutex(_barrierMutex);
37 | SDL_DestroySemaphore(_turnstile1);
38 | SDL_DestroySemaphore(_turnstile2);
39 | }
40 |
41 | void ThreadBarrier::waitPre() {
42 | SDL_mutexP(_barrierMutex);
43 | if (++_waitCount == _numThreads)
44 | for (int i = 0; i < _numThreads; i++)
45 | SDL_SemPost(_turnstile1);
46 | SDL_mutexV(_barrierMutex);
47 |
48 | SDL_SemWait(_turnstile1);
49 | }
50 |
51 | void ThreadBarrier::waitPost() {
52 | SDL_mutexP(_barrierMutex);
53 | if (--_waitCount == 0)
54 | for (int i = 0; i < _numThreads; i++)
55 | SDL_SemPost(_turnstile2);
56 | SDL_mutexV(_barrierMutex);
57 |
58 | SDL_SemWait(_turnstile2);
59 | }
60 |
61 | void ThreadBarrier::releaseAll() {
62 | for (int i = 0; i < _numThreads; i++) {
63 | SDL_SemPost(_turnstile1);
64 | SDL_SemPost(_turnstile2);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/ThreadBarrier.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef THREADBARRIER_HPP_
25 | #define THREADBARRIER_HPP_
26 |
27 | #include /* Cannot use forward declaration for thread primitives, unfortunately */
28 |
29 | #include
30 |
31 | class ThreadBarrier {
32 | int _numThreads;
33 | std::atomic _waitCount;
34 |
35 | SDL_mutex *_barrierMutex;
36 | SDL_sem *_turnstile1, *_turnstile2;
37 | public:
38 | ThreadBarrier(int numThreads);
39 | ~ThreadBarrier();
40 |
41 | void waitPre();
42 | void waitPost();
43 | void releaseAll();
44 | };
45 |
46 | #endif /* THREADBARRIER_HPP_ */
47 |
--------------------------------------------------------------------------------
/src/Timer.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef TIMER_HPP_
25 | #define TIMER_HPP_
26 |
27 | #include
28 | #include
29 | #include
30 | #if _WIN32
31 | #include
32 | #endif
33 |
34 | // std::chrono::high_resolution_clock has disappointing accuracy on windows
35 | // On windows, we use the WinAPI high performance counter instead
36 | class Timer
37 | {
38 | #if _WIN32
39 | LARGE_INTEGER _pfFrequency;
40 | LARGE_INTEGER _start, _stop;
41 | #else
42 | std::chrono::time_point _start, _stop;
43 | #endif
44 | public:
45 | Timer()
46 | {
47 | #if _WIN32
48 | QueryPerformanceFrequency(&_pfFrequency);
49 | #endif
50 | start();
51 | }
52 |
53 | void start()
54 | {
55 | #if _WIN32
56 | QueryPerformanceCounter(&_start);
57 | #else
58 | _start = std::chrono::high_resolution_clock::now();
59 | #endif
60 | }
61 |
62 | void stop()
63 | {
64 | #if _WIN32
65 | QueryPerformanceCounter(&_stop);
66 | #else
67 | _stop = std::chrono::high_resolution_clock::now();
68 | #endif
69 | }
70 |
71 | void bench(const std::string &s)
72 | {
73 | stop();
74 | std::cout << s << ": " << elapsed() << " s" << std::endl;
75 | }
76 |
77 | double elapsed() const
78 | {
79 | #if _WIN32
80 | return double(_stop.QuadPart - _start.QuadPart)/double(_pfFrequency.QuadPart);
81 | #else
82 | return std::chrono::duration(_stop - _start).count();
83 | #endif
84 | }
85 | };
86 |
87 | #endif /* TIMER_HPP_ */
88 |
--------------------------------------------------------------------------------
/src/Util.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #include "Util.hpp"
25 |
26 | #include
27 |
28 | std::string prettyPrintMemory(uint64 size)
29 | {
30 | const char *unit;
31 | uint64 base;
32 | if (size < 1024) {
33 | base = 1;
34 | unit = " bytes";
35 | } else if (size < 1024*1024) {
36 | base = 1024;
37 | unit = " KB";
38 | } else if (size < uint64(1024)*1024*1024) {
39 | base = 1024*1024;
40 | unit = " MB";
41 | } else {
42 | base = uint64(1024)*1024*1024;
43 | unit = " GB";
44 | }
45 |
46 | std::ostringstream out;
47 |
48 | if (size/base < 10)
49 | out << ((size*100)/base)*0.01;
50 | else if (size/base < 100)
51 | out << ((size*10)/base)*0.1;
52 | else
53 | out << size/base;
54 | out << unit;
55 |
56 | return out.str();
57 | }
58 |
--------------------------------------------------------------------------------
/src/Util.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef UTIL_HPP_
25 | #define UTIL_HPP_
26 |
27 | #include "math/Vec3.hpp"
28 |
29 | #include "IntTypes.hpp"
30 |
31 | #include
32 |
33 | std::string prettyPrintMemory(uint64 size);
34 |
35 | static inline float uintBitsToFloat(uint32 i) {
36 | union { uint32 i; float f; } unionHack;
37 | unionHack.i = i;
38 | return unionHack.f;
39 | }
40 |
41 | static inline uint32 floatBitsToUint(float f) {
42 | union { uint32 i; float f; } unionHack;
43 | unionHack.f = f;
44 | return unionHack.i;
45 | }
46 |
47 | static inline float invSqrt(float x) { //Inverse square root as used in Quake III
48 | float x2 = x*0.5f;
49 | float y = x;
50 |
51 | uint32 i = floatBitsToUint(y);
52 | i = 0x5f3759df - (i >> 1);
53 |
54 | y = uintBitsToFloat(i);
55 | y = y*(1.5f - x2*y*y);
56 |
57 | return y;
58 | }
59 |
60 | static inline void fastNormalization(Vec3 &v) {
61 | v *= invSqrt(v.dot(v));
62 | }
63 |
64 | static inline uint32 compressMaterial(const Vec3 &n, float shade) {
65 | const int32 uScale = (1 << 11) - 1;
66 | const int32 vScale = (1 << 11) - 1;
67 |
68 | uint32 face = 0;
69 | float dominantDir = fabsf(n.x);
70 | if (fabsf(n.y) > dominantDir) dominantDir = fabsf(n.y), face = 1;
71 | if (fabsf(n.z) > dominantDir) dominantDir = fabsf(n.z), face = 2;
72 |
73 | uint32 sign = n.a[face] < 0.0f;
74 |
75 | const int mod3[] = {0, 1, 2, 0, 1};
76 | float n1 = n.a[mod3[face + 1]]/dominantDir;
77 | float n2 = n.a[mod3[face + 2]]/dominantDir;
78 |
79 | uint32 u = std::min((int32)((n1*0.5f + 0.5f)*uScale), 0x7FF);
80 | uint32 v = std::min((int32)((n2*0.5f + 0.5f)*vScale), 0x7FF);
81 | uint32 c = std::min((int32)(shade*127.0f), 0x7F);
82 |
83 | return (sign << 31) | (face << 29) | (u << 18) | v << 7 | c;
84 | }
85 |
86 | static inline void decompressMaterial(uint32 normal, Vec3 &dst, float &shade) {
87 | uint32 sign = (normal & 0x80000000) >> 31;
88 | uint32 face = (normal & 0x60000000) >> 29;
89 | uint32 u = (normal & 0x1FFC0000) >> 18;
90 | uint32 v = (normal & 0x0003FF80) >> 7;
91 | uint32 c = (normal & 0x0000007F);
92 |
93 | const int mod3[] = {0, 1, 2, 0, 1};
94 | dst.a[ face ] = (sign ? -1.0f : 1.0f);
95 | dst.a[mod3[face + 1]] = u*4.8852e-4f*2.0f - 1.0f;
96 | dst.a[mod3[face + 2]] = v*4.8852e-4f*2.0f - 1.0f;
97 |
98 | fastNormalization(dst);
99 | shade = c*1.0f/127.0f;
100 | }
101 |
102 | static inline int roundToPow2(int x) {
103 | int y;
104 | for (y = 1; y < x; y *= 2);
105 | return y;
106 | }
107 |
108 | //See http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
109 | static inline int findHighestBit(uint32 v) {
110 | static const uint32 b[] = {
111 | 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000
112 | };
113 | uint32 r = (v & b[0]) != 0;
114 | for (int i = 4; i > 0; i--)
115 | r |= ((v & b[i]) != 0) << i;
116 | return r;
117 | }
118 |
119 | #endif /* UTIL_H_ */
120 |
--------------------------------------------------------------------------------
/src/VoxelData.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #include "VoxelData.hpp"
25 | #include "PlyLoader.hpp"
26 | #include "Debug.hpp"
27 |
28 | #include "thread/ThreadUtils.hpp"
29 | #include "thread/ThreadPool.hpp"
30 |
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 |
37 | VoxelData::VoxelData(const char *path, size_t mem) : _loader(0) {
38 | _dataStream = fopen(path, "rb");
39 |
40 | if (_dataStream != NULL) {
41 | fread(&_dataW, 4, 1, _dataStream);
42 | fread(&_dataH, 4, 1, _dataStream);
43 | fread(&_dataD, 4, 1, _dataStream);
44 |
45 | init(mem);
46 | buildTopLut();
47 | }
48 | }
49 |
50 | VoxelData::VoxelData(PlyLoader *loader, int sideLength, size_t mem) : _dataStream(0), _loader(loader) {
51 | loader->suggestedDimensions(sideLength, _dataW, _dataH, _dataD);
52 | init(mem);
53 | int size = int(_maxCacheableSize);
54 | loader->setupBlockProcessing(sideLength, size, size, size, _dataW, _dataH, _dataD);
55 | buildTopLut();
56 | }
57 |
58 | VoxelData::~VoxelData() {
59 | if (_dataStream)
60 | fclose(_dataStream);
61 | else if (_loader)
62 | _loader->teardownBlockProcessing();
63 | }
64 |
65 | static uint64 countCellsInHiarchicalGrid(int numLevels)
66 | {
67 | uint64 result = 0;
68 | uint64 size = 1;
69 | for (int i = 0; i < numLevels; ++i) {
70 | result += size;
71 | size *= 8;
72 | }
73 | return result;
74 | }
75 |
76 | static void buildHierarchicalGridLinks(uint8 *base, int numLevels, std::vector &dst)
77 | {
78 | size_t offset = 0;
79 | size_t size = 1;
80 | for (int i = 0; i < numLevels; ++i) {
81 | dst.push_back(base + offset);
82 | offset += size;
83 | size *= 8;
84 | }
85 | }
86 |
87 | template
88 | void VoxelData::upsampleLutLevel(int l) {
89 | int size = 2 << l;
90 |
91 | auto innerBody = [&](int z) {
92 | for (int y = 0; y < size; y += 2) {
93 | for (int x = 0; x < size; x += 2) {
94 | int value =
95 | getLut(l + 1, x, y + 0, z + 0) | getLut(l + 1, x + 1, y + 0, z + 0) |
96 | getLut(l + 1, x, y + 1, z + 0) | getLut(l + 1, x + 1, y + 1, z + 0) |
97 | getLut(l + 1, x, y + 0, z + 1) | getLut(l + 1, x + 1, y + 0, z + 1) |
98 | getLut(l + 1, x, y + 1, z + 1) | getLut(l + 1, x + 1, y + 1, z + 1);
99 |
100 | getLut(l, x >> 1, y >> 1, z >> 1) = (value != 0);
101 | }
102 | }
103 | };
104 |
105 | if (size < 128) {
106 | for (int z = 0; z < size; z += 2)
107 | innerBody(z);
108 | } else {
109 | int threadCount = ThreadUtils::pool->threadCount();
110 | ThreadUtils::pool->enqueue([&](uint32 id, uint32, uint32) {
111 | int start = (((size/2)*id)/threadCount)*2;
112 | int end = (((size/2)*(id + 1))/threadCount)*2;
113 |
114 | for (int z = start; z < end; z += 2)
115 | innerBody(z);
116 | }, threadCount)->wait();
117 | }
118 | }
119 |
120 | void VoxelData::buildTopLutBlock(int cx, int cy, int cz) {
121 | int size = int(_maxCacheableSize);
122 | int bufferW = std::min(size, _dataW - cx);
123 | int bufferH = std::min(size, _dataH - cy);
124 | int bufferD = std::min(size, _dataD - cz);
125 | if (bufferW <= 0 || bufferH <= 0 || bufferD <= 0)
126 | return;
127 |
128 | bool empty;
129 | if (_loader) {
130 | empty = _loader->isBlockEmpty(cx, cy, cz);
131 | } else {
132 | cacheData(cx, cy, cz, bufferW, bufferH, bufferD);
133 |
134 | empty = true;
135 | for (size_t i = 0; i < size_t(bufferW)*size_t(bufferH)*size_t(bufferD); ++i) {
136 | if (_bufferedData[i]) {
137 | empty = false;
138 | break;
139 | }
140 | }
141 | }
142 |
143 | if (!empty)
144 | getTopLut(_topLutLevels - 1, cx >> _lowLutLevels, cy >> _lowLutLevels, cz >> _lowLutLevels) = 1;
145 | }
146 |
147 | void VoxelData::buildTopLut() {
148 | if (_topLutLevels == 0)
149 | return;
150 |
151 | for (int z = 0; z < _virtualDataD; z += int(_maxCacheableSize))
152 | for (int y = 0; y < _virtualDataH; y += int(_maxCacheableSize))
153 | for (int x = 0; x < _virtualDataW; x += int(_maxCacheableSize))
154 | buildTopLutBlock(x, y, z);
155 |
156 | for (int i = _topLutLevels - 2; i >= 0; i--)
157 | upsampleLutLevel(i);
158 | }
159 |
160 | void VoxelData::buildLowLut() {
161 | int threadCount = ThreadUtils::pool->threadCount();
162 | ThreadUtils::pool->enqueue([&](uint32 id, uint32, uint32) {
163 | int start = (((_bufferD/2)*id)/threadCount)*2;
164 | int end = (((_bufferD/2)*(id + 1))/threadCount)*2;
165 |
166 | for (int z = start; z < end; ++z)
167 | for (int y = 0; y < _bufferH; ++y)
168 | for (int x = 0; x < _bufferW; ++x)
169 | if (_bufferedData[x + size_t(_bufferW)*(y + size_t(_bufferH)*z)])
170 | getLowLut(_lowLutLevels - 1, x/2, y/2, z/2) = 1;
171 | }, threadCount)->wait();
172 |
173 | for (int i = _lowLutLevels - 2; i >= 0; i--)
174 | upsampleLutLevel(i);
175 | }
176 |
177 | void VoxelData::cacheData(int x, int y, int z, int w, int h, int d) {
178 | if (_loader) {
179 | _loader->processBlock(_bufferedData.get(), x, y, z, w, h, d);
180 | return;
181 | }
182 |
183 | uint64_t zStride = _dataH*(uint64_t)_dataW;
184 | uint64_t yStride = (uint64_t)_dataW;
185 | uint64_t offsetZ = z*zStride;
186 | uint64_t offsetY = y*yStride;
187 | uint64_t offsetX = x;
188 | uint64_t baseOffset = (offsetX + offsetY + offsetZ)*sizeof(uint32) + 3*sizeof(uint32);
189 | uint64_t offset = 0;
190 |
191 | for (uint64_t voxelZ = 0; voxelZ < (unsigned)d; voxelZ++) {
192 | for (uint64_t voxelY = 0; voxelY < (unsigned)h; voxelY++) {
193 | #ifdef _MSC_VER
194 | _fseeki64(_dataStream, baseOffset + offset, SEEK_SET);
195 | #elif __APPLE__
196 | fseeko(_dataStream, baseOffset + offset, SEEK_SET);
197 | #else
198 | fseeko64(_dataStream, baseOffset + offset, SEEK_SET);
199 | #endif
200 |
201 | fread(_bufferedData.get() + (voxelY + voxelZ*h)*w, sizeof(uint32), w, _dataStream);
202 |
203 | offset += yStride*sizeof(uint32);
204 | }
205 |
206 | baseOffset += zStride*sizeof(uint32);
207 | offset = 0;
208 | }
209 | }
210 |
211 | void VoxelData::init(size_t mem) {
212 | _virtualDataW = roundToPow2(_dataW);
213 | _virtualDataH = roundToPow2(_dataH);
214 | _virtualDataD = roundToPow2(_dataD);
215 | _highestVirtualBit = findHighestBit(std::max(_virtualDataW, std::max(_virtualDataH, _virtualDataD)));
216 |
217 | _cellCost = sizeof(uint32);
218 | if (_loader)
219 | _cellCost += _loader->blockMemRequirement(1, 1, 1);
220 |
221 | auto partitionCost = [&](int level) {
222 | int lowBit = _highestVirtualBit - level;
223 | uint64 topLutCost = countCellsInHiarchicalGrid(level + 1);
224 | uint64 lowLutCost = countCellsInHiarchicalGrid(lowBit);
225 | uint64 gridCost = (uint64(1) << uint64(lowBit*3))*_cellCost;
226 | return topLutCost + lowLutCost + gridCost;
227 | };
228 |
229 | int largestLowerLevel = -1;
230 | uint64 smallestSize = std::numeric_limits::max();
231 | for (int i = _highestVirtualBit; i >= 0; --i) {
232 | if (partitionCost(i) < mem)
233 | largestLowerLevel = _highestVirtualBit - i;
234 | smallestSize = std::min(smallestSize, partitionCost(i));
235 | }
236 | if (largestLowerLevel == -1) {
237 | std::cout << "Not enough memory to convert voxel volume. Require at least "
238 | << prettyPrintMemory(smallestSize) << std::endl;
239 | std::exit(-1);
240 | }
241 |
242 | _lowLutLevels = largestLowerLevel;
243 | _topLutLevels = _highestVirtualBit - largestLowerLevel + 1;
244 | _maxCacheableSize = size_t(1) << largestLowerLevel;
245 |
246 | _topLut.reset(new uint8[countCellsInHiarchicalGrid(_topLutLevels)]());
247 | _lowLut.reset(new uint8[countCellsInHiarchicalGrid(_lowLutLevels)]());
248 | _bufferedData.reset(new uint32[size_t(1) << size_t(largestLowerLevel*3)]());
249 |
250 | std::cout << "Using a cache block of size " << _maxCacheableSize << "^3, taking up "
251 | << prettyPrintMemory(partitionCost(_topLutLevels - 1)) << " in memory.";
252 | if (largestLowerLevel < _highestVirtualBit) {
253 | std::cout << " For the next size of " << _maxCacheableSize*2 << "^3, you would need "
254 | << prettyPrintMemory(partitionCost(_topLutLevels - 2)) << " of memory";
255 | }
256 | std::cout << std::endl;
257 |
258 | buildHierarchicalGridLinks(_topLut.get(), _topLutLevels, _topTable);
259 | buildHierarchicalGridLinks(_lowLut.get(), _lowLutLevels, _lowTable);
260 |
261 | _bufferX = _bufferY = _bufferZ = _bufferW = _bufferH = _bufferD = 0;
262 | }
263 |
264 | void VoxelData::prepareDataAccess(int x, int y, int z, int size) {
265 | int width = std::min(size, _dataW - x);
266 | int height = std::min(size, _dataH - y);
267 | int depth = std::min(size, _dataD - z);
268 |
269 | if (width <= 0 || height <= 0 || depth <= 0)
270 | return;
271 |
272 | if (x >= _bufferX &&
273 | y >= _bufferY &&
274 | z >= _bufferZ &&
275 | x + width <= _bufferX + _bufferW &&
276 | y + height <= _bufferY + _bufferH &&
277 | z + depth <= _bufferZ + _bufferD)
278 | return;
279 |
280 | if (size_t(size) <= _maxCacheableSize) {
281 | _bufferX = x;
282 | _bufferY = y;
283 | _bufferZ = z;
284 | _bufferW = width;
285 | _bufferH = height;
286 | _bufferD = depth;
287 |
288 | cacheData(x, y, z, width, height, depth);
289 | buildLowLut();
290 | }
291 | }
292 |
293 | int VoxelData::sideLength() const {
294 | return std::max(_virtualDataW, std::max(_virtualDataH, _virtualDataD));
295 | }
296 |
297 | Vec3 VoxelData::getCenter() const {
298 | return Vec3(
299 | _dataW*0.5f/sideLength(),
300 | _dataH*0.5f/sideLength(),
301 | _dataD*0.5f/sideLength()
302 | );
303 | }
304 |
--------------------------------------------------------------------------------
/src/VoxelData.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef VOXELDATA_HPP_
25 | #define VOXELDATA_HPP_
26 |
27 | #include "math/Vec3.hpp"
28 |
29 | #include "IntTypes.hpp"
30 | #include "Util.hpp"
31 |
32 | #include
33 | #include
34 | #include
35 |
36 | class PlyLoader;
37 |
38 | class VoxelData {
39 | FILE *_dataStream;
40 | PlyLoader *_loader;
41 |
42 | int _dataW;
43 | int _dataH;
44 | int _dataD;
45 |
46 | int _virtualDataW;
47 | int _virtualDataH;
48 | int _virtualDataD;
49 |
50 | int _highestVirtualBit;
51 | int _lowLutLevels;
52 |
53 | size_t _maxCacheableSize;
54 |
55 | size_t _cellCost;
56 |
57 | std::unique_ptr _topLut, _lowLut;
58 | std::vector _topTable;
59 | std::vector _lowTable;
60 | int _minLutStep;
61 | int _topLutLevels;
62 |
63 | std::unique_ptr _bufferedData;
64 |
65 | int _bufferX, _bufferY, _bufferZ;
66 | int _bufferW, _bufferH, _bufferD;
67 |
68 | template
69 | void upsampleLutLevel(int l);
70 |
71 | void buildTopLutBlock(int x, int y, int z);
72 |
73 | void buildTopLut();
74 | void buildLowLut();
75 |
76 | void cacheData(int x, int y, int z, int w, int h, int d);
77 |
78 | void init(size_t mem);
79 |
80 | inline size_t lutIdx(int l, int x, int y, int z) const {
81 | return x + ((size_t)y << l) + ((size_t)z << 2*l);
82 | }
83 |
84 | inline uint8 &getTopLut(int l, int x, int y, int z) {
85 | return _topTable[l][lutIdx(l, x, y, z)];
86 | }
87 |
88 | inline uint8 &getLowLut(int l, int x, int y, int z) {
89 | return _lowTable[l][lutIdx(l, x, y, z)];
90 | }
91 |
92 | template
93 | inline uint8 &getLut(int l, int x, int y, int z)
94 | {
95 | if (isTop)
96 | return getTopLut(l, x, y, z);
97 | else
98 | return getLowLut(l, x, y, z);
99 | }
100 |
101 | public:
102 | VoxelData(const char *path, size_t mem);
103 | VoxelData(PlyLoader *loader, int sideLength, size_t mem);
104 | ~VoxelData();
105 |
106 | inline uint32 getVoxel(int x, int y, int z) const {
107 | if (x >= _dataW || y >= _dataH || z >= _dataD)
108 | return 0;
109 | size_t idx = size_t(x - _bufferX) + _bufferW*(size_t(y - _bufferY) + _bufferH*size_t(z - _bufferZ));
110 | return _bufferedData[idx];
111 | }
112 |
113 | inline uint32 getVoxelDestructive(int x, int y, int z) {
114 | if (x >= _dataW || y >= _dataH || z >= _dataD)
115 | return 0;
116 | size_t idx = size_t(x - _bufferX) + _bufferW*(size_t(y - _bufferY) + _bufferH*size_t(z - _bufferZ));
117 | uint32 value = _bufferedData[idx];
118 | if (value)
119 | _bufferedData[idx] = 0;
120 | return value;
121 | }
122 |
123 | inline bool cubeContainsVoxelsDestructive(int x, int y, int z, int size) {
124 | if (x >= _dataW || y >= _dataH || z >= _dataD)
125 | return false;
126 |
127 | int bit = findHighestBit(size);
128 | if (size == 1) {
129 | return getVoxel(x, y, z) != 0;
130 | } else if (bit < _lowLutLevels) {
131 | uint8 value = getLowLut(_lowLutLevels - bit, (x - _bufferX) >> bit, (y - _bufferY) >> bit, (z - _bufferZ) >> bit);
132 | if (value != 0)
133 | getLowLut(_lowLutLevels - bit, (x - _bufferX) >> bit, (y - _bufferY) >> bit, (z - _bufferZ) >> bit) = 0;
134 | return value != 0;
135 | } else {
136 | return getTopLut(_highestVirtualBit - bit, x >> bit, y >> bit, z >> bit) != 0;
137 | }
138 | }
139 |
140 | void prepareDataAccess(int x, int y, int z, int size);
141 |
142 | int sideLength() const;
143 | Vec3 getCenter() const;
144 | };
145 |
146 |
147 | #endif /* VOXELDATA_H_ */
148 |
--------------------------------------------------------------------------------
/src/VoxelOctree.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #include "VoxelOctree.hpp"
25 | #include "VoxelData.hpp"
26 | #include "Debug.hpp"
27 | #include "Util.hpp"
28 |
29 | #include "third-party/lz4.h"
30 |
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | static const uint32 BitCount[] = {
37 | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
38 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
39 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
40 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
41 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
42 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
43 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
44 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
45 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
46 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
47 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
48 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
49 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
50 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
51 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
52 | 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
53 | };
54 |
55 | static const size_t CompressionBlockSize = 64*1024*1024;
56 |
57 | VoxelOctree::VoxelOctree(const char *path) : _voxels(0) {
58 | FILE *fp = fopen(path, "rb");
59 |
60 | if (fp) {
61 |
62 | fread(_center.a, sizeof(float), 3, fp);
63 | fread(&_octreeSize, sizeof(uint64), 1, fp);
64 |
65 | _octree.reset(new uint32[_octreeSize]);
66 |
67 | std::unique_ptr buffer(new char[LZ4_compressBound(CompressionBlockSize)]);
68 | char *dst = reinterpret_cast(_octree.get());
69 |
70 | LZ4_streamDecode_t *stream = LZ4_createStreamDecode();
71 | LZ4_setStreamDecode(stream, dst, 0);
72 |
73 | uint64 compressedSize = 0;
74 | for (uint64 offset = 0; offset < _octreeSize*sizeof(uint32); offset += CompressionBlockSize) {
75 | uint64 compSize;
76 | fread(&compSize, sizeof(uint64), 1, fp);
77 | fread(buffer.get(), sizeof(char), size_t(compSize), fp);
78 |
79 | int outSize = std::min(_octreeSize*sizeof(uint32) - offset, CompressionBlockSize);
80 | LZ4_decompress_fast_continue(stream, buffer.get(), dst + offset, outSize);
81 | compressedSize += compSize + 8;
82 | }
83 | LZ4_freeStreamDecode(stream);
84 |
85 | fclose(fp);
86 |
87 | std::cout << "Octree size: " << prettyPrintMemory(_octreeSize*sizeof(uint32))
88 | << " Compressed size: " << prettyPrintMemory(compressedSize) << std::endl;
89 | }
90 | }
91 |
92 | void VoxelOctree::save(const char *path) {
93 | FILE *fp = fopen(path, "wb");
94 |
95 | if (fp) {
96 | fwrite(_center.a, sizeof(float), 3, fp);
97 | fwrite(&_octreeSize, sizeof(uint64), 1, fp);
98 |
99 | LZ4_stream_t *stream = LZ4_createStream();
100 | LZ4_resetStream(stream);
101 |
102 | std::unique_ptr buffer(new char[LZ4_compressBound(CompressionBlockSize)]);
103 | const char *src = reinterpret_cast(_octree.get());
104 |
105 | uint64 compressedSize = 0;
106 | for (uint64 offset = 0; offset < _octreeSize*sizeof(uint32); offset += CompressionBlockSize) {
107 | int outSize = int(std::min(_octreeSize*sizeof(uint32) - offset, uint64(CompressionBlockSize)));
108 | uint64 compSize = LZ4_compress_continue(stream, src + offset, buffer.get(), outSize);
109 |
110 | fwrite(&compSize, sizeof(uint64), 1, fp);
111 | fwrite(buffer.get(), sizeof(char), size_t(compSize), fp);
112 |
113 | compressedSize += compSize + 8;
114 | }
115 |
116 | LZ4_freeStream(stream);
117 |
118 | fclose(fp);
119 |
120 | std::cout << "Octree size: " << prettyPrintMemory(_octreeSize*sizeof(uint32))
121 | << " Compressed size: " << prettyPrintMemory(compressedSize) << std::endl;
122 | }
123 | }
124 |
125 | VoxelOctree::VoxelOctree(VoxelData *voxels)
126 | : _voxels(voxels)
127 | {
128 | std::unique_ptr> octreeAllocator(new ChunkedAllocator());
129 | octreeAllocator->pushBack(0);
130 |
131 | buildOctree(*octreeAllocator, 0, 0, 0, _voxels->sideLength(), 0);
132 | (*octreeAllocator)[0] |= 1 << 18;
133 |
134 | _octreeSize = octreeAllocator->size() + octreeAllocator->insertionCount();
135 | _octree = octreeAllocator->finalize();
136 | _center = _voxels->getCenter();
137 | }
138 |
139 | uint64 VoxelOctree::buildOctree(ChunkedAllocator &allocator, int x, int y, int z, int size, uint64 descriptorIndex) {
140 | _voxels->prepareDataAccess(x, y, z, size);
141 |
142 | int halfSize = size >> 1;
143 |
144 | int posX[] = {x + halfSize, x, x + halfSize, x, x + halfSize, x, x + halfSize, x};
145 | int posY[] = {y + halfSize, y + halfSize, y, y, y + halfSize, y + halfSize, y, y};
146 | int posZ[] = {z + halfSize, z + halfSize, z + halfSize, z + halfSize, z, z, z, z};
147 |
148 | uint64 childOffset = uint64(allocator.size()) - descriptorIndex;
149 |
150 | int childCount = 0;
151 | int childIndices[8];
152 | uint32 childMask = 0;
153 | for (int i = 0; i < 8; i++) {
154 | if (_voxels->cubeContainsVoxelsDestructive(posX[i], posY[i], posZ[i], halfSize)) {
155 | childMask |= 128 >> i;
156 | childIndices[childCount++] = i;
157 | }
158 | }
159 |
160 | bool hasLargeChildren = false;
161 | uint32 leafMask;
162 | if (halfSize == 1) {
163 | leafMask = 0;
164 |
165 | for (int i = 0; i < childCount; i++) {
166 | int idx = childIndices[childCount - i - 1];
167 | allocator.pushBack(_voxels->getVoxelDestructive(posX[idx], posY[idx], posZ[idx]));
168 | }
169 | } else {
170 | leafMask = childMask;
171 | for (int i = 0; i < childCount; i++)
172 | allocator.pushBack(0);
173 |
174 | uint64 grandChildOffsets[8];
175 | uint64 delta = 0;
176 | uint64 insertionCount = allocator.insertionCount();
177 | for (int i = 0; i < childCount; i++) {
178 | int idx = childIndices[childCount - i - 1];
179 | grandChildOffsets[i] = delta + buildOctree(allocator, posX[idx], posY[idx], posZ[idx],
180 | halfSize, descriptorIndex + childOffset + i);
181 | delta += allocator.insertionCount() - insertionCount;
182 | insertionCount = allocator.insertionCount();
183 | if (grandChildOffsets[i] > 0x3FFF)
184 | hasLargeChildren = true;
185 | }
186 |
187 | for (int i = 0; i < childCount; i++) {
188 | uint64 childIndex = descriptorIndex + childOffset + i;
189 | uint64 offset = grandChildOffsets[i];
190 | if (hasLargeChildren) {
191 | offset += childCount - i;
192 | allocator.insert(childIndex + 1, uint32(offset));
193 | allocator[childIndex] |= 0x20000;
194 | offset >>= 32;
195 | }
196 | allocator[childIndex] |= uint32(offset << 18);
197 | }
198 | }
199 |
200 | allocator[descriptorIndex] = (childMask << 8) | leafMask;
201 | if (hasLargeChildren)
202 | allocator[descriptorIndex] |= 0x10000;
203 |
204 | return childOffset;
205 | }
206 |
207 | bool VoxelOctree::raymarch(const Vec3 &o, const Vec3 &d, float rayScale, uint32 &normal, float &t) {
208 | struct StackEntry {
209 | uint64 offset;
210 | float maxT;
211 | };
212 | StackEntry rayStack[MaxScale + 1];
213 |
214 | float ox = o.x, oy = o.y, oz = o.z;
215 | float dx = d.x, dy = d.y, dz = d.z;
216 |
217 | if (std::fabs(dx) < 1e-4f) dx = 1e-4f;
218 | if (std::fabs(dy) < 1e-4f) dy = 1e-4f;
219 | if (std::fabs(dz) < 1e-4f) dz = 1e-4f;
220 |
221 | float dTx = 1.0f/-std::fabs(dx);
222 | float dTy = 1.0f/-std::fabs(dy);
223 | float dTz = 1.0f/-std::fabs(dz);
224 |
225 | float bTx = dTx*ox;
226 | float bTy = dTy*oy;
227 | float bTz = dTz*oz;
228 |
229 | uint8 octantMask = 7;
230 | if (dx > 0.0f) octantMask ^= 1, bTx = 3.0f*dTx - bTx;
231 | if (dy > 0.0f) octantMask ^= 2, bTy = 3.0f*dTy - bTy;
232 | if (dz > 0.0f) octantMask ^= 4, bTz = 3.0f*dTz - bTz;
233 |
234 | float minT = std::max(2.0f*dTx - bTx, std::max(2.0f*dTy - bTy, 2.0f*dTz - bTz));
235 | float maxT = std::min( dTx - bTx, std::min( dTy - bTy, dTz - bTz));
236 | minT = std::max(minT, 0.0f);
237 |
238 | uint32 current = 0;
239 | uint64 parent = 0;
240 | int idx = 0;
241 | float posX = 1.0f;
242 | float posY = 1.0f;
243 | float posZ = 1.0f;
244 | int scale = MaxScale - 1;
245 |
246 | float scaleExp2 = 0.5f;
247 |
248 | if (1.5f*dTx - bTx > minT) idx ^= 1, posX = 1.5f;
249 | if (1.5f*dTy - bTy > minT) idx ^= 2, posY = 1.5f;
250 | if (1.5f*dTz - bTz > minT) idx ^= 4, posZ = 1.5f;
251 |
252 | while (scale < MaxScale) {
253 | if (current == 0)
254 | current = _octree[parent];
255 |
256 | float cornerTX = posX*dTx - bTx;
257 | float cornerTY = posY*dTy - bTy;
258 | float cornerTZ = posZ*dTz - bTz;
259 | float maxTC = std::min(cornerTX, std::min(cornerTY, cornerTZ));
260 |
261 | int childShift = idx ^ octantMask;
262 | uint32 childMasks = current << childShift;
263 |
264 | if ((childMasks & 0x8000) && minT <= maxT) {
265 | if (maxTC*rayScale >= scaleExp2) {
266 | t = maxTC;
267 | return true;
268 | }
269 |
270 | float maxTV = std::min(maxT, maxTC);
271 | float half = scaleExp2*0.5f;
272 | float centerTX = half*dTx + cornerTX;
273 | float centerTY = half*dTy + cornerTY;
274 | float centerTZ = half*dTz + cornerTZ;
275 |
276 | if (minT <= maxTV) {
277 | uint64 childOffset = current >> 18;
278 | if (current & 0x20000)
279 | childOffset = (childOffset << 32) | uint64(_octree[parent + 1]);
280 |
281 | if (!(childMasks & 0x80)) {
282 | normal = _octree[childOffset + parent + BitCount[((childMasks >> (8 + childShift)) << childShift) & 127]];
283 |
284 | break;
285 | }
286 |
287 | rayStack[scale].offset = parent;
288 | rayStack[scale].maxT = maxT;
289 |
290 | uint32 siblingCount = BitCount[childMasks & 127];
291 | parent += childOffset + siblingCount;
292 | if (current & 0x10000)
293 | parent += siblingCount;
294 |
295 | idx = 0;
296 | scale--;
297 | scaleExp2 = half;
298 |
299 | if (centerTX > minT) idx ^= 1, posX += scaleExp2;
300 | if (centerTY > minT) idx ^= 2, posY += scaleExp2;
301 | if (centerTZ > minT) idx ^= 4, posZ += scaleExp2;
302 |
303 | maxT = maxTV;
304 | current = 0;
305 |
306 | continue;
307 | }
308 | }
309 |
310 | int stepMask = 0;
311 | if (cornerTX <= maxTC) stepMask ^= 1, posX -= scaleExp2;
312 | if (cornerTY <= maxTC) stepMask ^= 2, posY -= scaleExp2;
313 | if (cornerTZ <= maxTC) stepMask ^= 4, posZ -= scaleExp2;
314 |
315 | minT = maxTC;
316 | idx ^= stepMask;
317 |
318 | if ((idx & stepMask) != 0) {
319 | int differingBits = 0;
320 | if (stepMask & 1) differingBits |= floatBitsToUint(posX) ^ floatBitsToUint(posX + scaleExp2);
321 | if (stepMask & 2) differingBits |= floatBitsToUint(posY) ^ floatBitsToUint(posY + scaleExp2);
322 | if (stepMask & 4) differingBits |= floatBitsToUint(posZ) ^ floatBitsToUint(posZ + scaleExp2);
323 | scale = (floatBitsToUint((float)differingBits) >> 23) - 127;
324 | scaleExp2 = uintBitsToFloat((scale - MaxScale + 127) << 23);
325 |
326 | parent = rayStack[scale].offset;
327 | maxT = rayStack[scale].maxT;
328 |
329 | int shX = floatBitsToUint(posX) >> scale;
330 | int shY = floatBitsToUint(posY) >> scale;
331 | int shZ = floatBitsToUint(posZ) >> scale;
332 | posX = uintBitsToFloat(shX << scale);
333 | posY = uintBitsToFloat(shY << scale);
334 | posZ = uintBitsToFloat(shZ << scale);
335 | idx = (shX & 1) | ((shY & 1) << 1) | ((shZ & 1) << 2);
336 |
337 | current = 0;
338 | }
339 | }
340 |
341 | if (scale >= MaxScale)
342 | return false;
343 |
344 | t = minT;
345 | return true;
346 | }
347 |
--------------------------------------------------------------------------------
/src/VoxelOctree.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef VOXELOCTREE_HPP_
25 | #define VOXELOCTREE_HPP_
26 |
27 | #include "math/Vec3.hpp"
28 |
29 | #include "ChunkedAllocator.hpp"
30 | #include "IntTypes.hpp"
31 |
32 | #include
33 | #include
34 |
35 | class VoxelData;
36 |
37 | class VoxelOctree {
38 | static const int32 MaxScale = 23;
39 |
40 | uint64 _octreeSize;
41 | std::unique_ptr _octree;
42 |
43 | VoxelData *_voxels;
44 | Vec3 _center;
45 |
46 | uint64 buildOctree(ChunkedAllocator &allocator, int x, int y, int z, int size, uint64 descriptorIndex);
47 |
48 | public:
49 | VoxelOctree(const char *path);
50 | VoxelOctree(VoxelData *voxels);
51 |
52 | void save(const char *path);
53 | bool raymarch(const Vec3 &o, const Vec3 &d, float rayScale, uint32 &normal, float &t);
54 |
55 | Vec3 center() const {
56 | return _center;
57 | }
58 | };
59 |
60 | #endif /* VOXELOCTREE_HPP_ */
61 |
--------------------------------------------------------------------------------
/src/math/Mat4.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #include "Mat4.hpp"
25 |
26 | #include
27 |
28 | #ifndef M_PI
29 | #define M_PI 3.14159265358979323846
30 | #endif
31 |
32 | Mat4::Mat4() {
33 | a12 = a13 = a14 = 0.0f;
34 | a21 = a23 = a24 = 0.0f;
35 | a31 = a32 = a34 = 0.0f;
36 | a41 = a42 = a43 = 0.0f;
37 | a11 = a22 = a33 = a44 = 1.0f;
38 | }
39 |
40 | Mat4::Mat4(
41 | float _a11, float _a12, float _a13, float _a14,
42 | float _a21, float _a22, float _a23, float _a24,
43 | float _a31, float _a32, float _a33, float _a34,
44 | float _a41, float _a42, float _a43, float _a44) :
45 | a11(_a11), a12(_a12), a13(_a13), a14(_a14),
46 | a21(_a21), a22(_a22), a23(_a23), a24(_a24),
47 | a31(_a31), a32(_a32), a33(_a33), a34(_a34),
48 | a41(_a41), a42(_a42), a43(_a43), a44(_a44) {}
49 |
50 | Mat4 Mat4::transpose() const {
51 | return Mat4(
52 | a11, a21, a31, a41,
53 | a12, a22, a32, a42,
54 | a13, a23, a33, a43,
55 | a14, a24, a34, a44
56 | );
57 | }
58 |
59 | Mat4 Mat4::pseudoInvert() const {
60 | Mat4 trans = translate(Vec3(-a14, -a24, -a34));
61 | Mat4 rot = transpose();
62 | rot.a41 = rot.a42 = rot.a43 = 0.0f;
63 |
64 | return rot*trans;
65 | }
66 |
67 | Mat4 Mat4::operator*(const Mat4 &b) const {
68 | Mat4 result;
69 | for (int i = 0; i < 4; i++)
70 | for (int t = 0; t < 4; t++)
71 | result.a[i*4 + t] =
72 | a[i*4 + 0]*b.a[0*4 + t] +
73 | a[i*4 + 1]*b.a[1*4 + t] +
74 | a[i*4 + 2]*b.a[2*4 + t] +
75 | a[i*4 + 3]*b.a[3*4 + t];
76 |
77 | return result;
78 | }
79 |
80 | Vec3 Mat4::operator*(const Vec3 &b) const {
81 | return Vec3(
82 | a11*b.x + a12*b.y + a13*b.z + a14,
83 | a21*b.x + a22*b.y + a23*b.z + a24,
84 | a31*b.x + a32*b.y + a33*b.z + a34
85 | );
86 | }
87 |
88 | Vec3 Mat4::transformVector(const Vec3 &b) const {
89 | return Vec3(
90 | a11*b.x + a12*b.y + a13*b.z,
91 | a21*b.x + a22*b.y + a23*b.z,
92 | a31*b.x + a32*b.y + a33*b.z
93 | );
94 | }
95 |
96 | Mat4 Mat4::translate(const Vec3 &v) {
97 | return Mat4(
98 | 1.0f, 0.0f, 0.0f, v.x,
99 | 0.0f, 1.0f, 0.0f, v.y,
100 | 0.0f, 0.0f, 1.0f, v.z,
101 | 0.0f, 0.0f, 0.0f, 1.0f
102 | );
103 | }
104 |
105 | Mat4 Mat4::scale(const Vec3 &s) {
106 | return Mat4(
107 | s.x, 0.0f, 0.0f, 0.0f,
108 | 0.0f, s.y, 0.0f, 0.0f,
109 | 0.0f, 0.0f, s.z, 0.0f,
110 | 0.0f, 0.0f, 0.0f, 1.0f
111 | );
112 | }
113 |
114 | Mat4 Mat4::rotXYZ(const Vec3 &rot) {
115 | Vec3 r = rot*float(M_PI)/180.0f;
116 | float c[] = {std::cos(r.x), std::cos(r.y), std::cos(r.z)};
117 | float s[] = {std::sin(r.x), std::sin(r.y), std::sin(r.z)};
118 |
119 | return Mat4(
120 | c[1]*c[2], -c[0]*s[2] + s[0]*s[1]*c[2], s[0]*s[2] + c[0]*s[1]*c[2], 0.0f,
121 | c[1]*s[2], c[0]*c[2] + s[0]*s[1]*s[2], -s[0]*c[2] + c[0]*s[1]*s[2], 0.0f,
122 | -s[1], s[0]*c[1], c[0]*c[1], 0.0f,
123 | 0.0f, 0.0f, 0.0f, 1.0f
124 | );
125 | }
126 |
127 | Mat4 Mat4::rotYZX(const Vec3 &rot) {
128 | Vec3 r = rot*float(M_PI)/180.0f;
129 | float c[] = {std::cos(r.x), std::cos(r.y), std::cos(r.z)};
130 | float s[] = {std::sin(r.x), std::sin(r.y), std::sin(r.z)};
131 |
132 | return Mat4(
133 | c[1]*c[2], c[0]*c[1]*s[2] - s[0]*s[1], c[0]*s[1] + c[1]*s[0]*s[2], 0.0f,
134 | -s[2], c[0]*c[2], c[2]*s[0], 0.0f,
135 | -c[2]*s[1], -c[1]*s[0] - c[0]*s[1]*s[2], c[0]*c[1] - s[0]*s[1]*s[2], 0.0f,
136 | 0.0f, 0.0f, 0.0f, 1.0f
137 | );
138 | }
139 |
140 | Mat4 Mat4::rotAxis(const Vec3 &axis, float angle) {
141 | angle *= float(M_PI)/180.0f;
142 | float s = std::sin(angle);
143 | float c = std::cos(angle);
144 | float c1 = 1.0f - c;
145 | float x = axis.x;
146 | float y = axis.y;
147 | float z = axis.z;
148 |
149 | return Mat4(
150 | c + x*x*c1, x*y*c1 - z*s, x*z*c1 + y*s, 0.0f,
151 | y*x*c1 + z*s, c + y*y*c1, y*z*c1 - x*s, 0.0f,
152 | z*x*c1 - y*s, z*y*c1 + x*s, c + z*z*c1, 0.0f,
153 | 0.0f, 0.0f, 0.0f, 1.0f
154 | );
155 | }
156 |
157 | Mat4 Mat4::ortho(float l, float r, float b, float t, float n, float f) {
158 | return Mat4(
159 | 2.0f/(r-l), 0.0f, 0.0f, -(r+l)/(r-l),
160 | 0.0f, 2.0f/(t-b), 0.0f, -(t+b)/(t-b),
161 | 0.0f, 0.0f, -2.0f/(f-n), -(f+n)/(f-n),
162 | 0.0f, 0.0f, 0.0f, 1.0f
163 | );
164 | }
165 |
166 | Mat4 Mat4::perspective(float aov, float ratio, float near, float far) {
167 | float t = 1.0f/std::tan(aov*(float(M_PI)/360.0f));
168 | float a = (far + near)/(far - near);
169 | float b = 2.0f*far*near/(far - near);
170 | float c = t/ratio;
171 |
172 | return Mat4(
173 | c, 0.0f, 0.0f, 0.0f,
174 | 0.0f, t, 0.0f, 0.0f,
175 | 0.0f, 0.0f, -a, -b,
176 | 0.0f, 0.0f, -1.0f, 0.0f
177 | );
178 | }
179 |
180 | Mat4 Mat4::lookAt(const Vec3 &pos, const Vec3 &fwd, const Vec3 &up) {
181 | Vec3 f = fwd.normalize();
182 | Vec3 r = f.cross(up).normalize();
183 | Vec3 u = r.cross(f).normalize();
184 |
185 | return Mat4(
186 | r.x, u.x, f.x, pos.x,
187 | r.y, u.y, f.y, pos.y,
188 | r.z, u.z, f.z, pos.z,
189 | 0.0f, 0.0f, 0.0f, 1.0f
190 | );
191 |
192 | }
193 |
--------------------------------------------------------------------------------
/src/math/Mat4.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef MATH_MAT4_HPP_
25 | #define MATH_MAT4_HPP_
26 |
27 | #include "Vec3.hpp"
28 |
29 | struct Mat4 {
30 | union {
31 | struct {
32 | float a11, a12, a13, a14;
33 | float a21, a22, a23, a24;
34 | float a31, a32, a33, a34;
35 | float a41, a42, a43, a44;
36 | };
37 | float a[16];
38 | };
39 |
40 | Mat4();
41 | Mat4(float _a11, float _a12, float _a13, float _a14,
42 | float _a21, float _a22, float _a23, float _a24,
43 | float _a31, float _a32, float _a33, float _a34,
44 | float _a41, float _a42, float _a43, float _a44);
45 |
46 | Mat4 transpose() const;
47 | Mat4 pseudoInvert() const;
48 |
49 | Mat4 operator*(const Mat4 &b) const;
50 | Vec3 operator*(const Vec3 &b) const;
51 |
52 | Vec3 transformVector(const Vec3 &v) const;
53 |
54 | static Mat4 translate(const Vec3 &v);
55 | static Mat4 scale(const Vec3 &s);
56 | static Mat4 rotXYZ(const Vec3 &rot);
57 | static Mat4 rotYZX(const Vec3 &rot);
58 | static Mat4 rotAxis(const Vec3 &axis, float angle);
59 |
60 | static Mat4 ortho(float l, float r, float b, float t, float near, float far);
61 | static Mat4 perspective(float aov, float ratio, float near, float far);
62 | static Mat4 lookAt(const Vec3 &pos, const Vec3 &fwd, const Vec3 &up);
63 | };
64 |
65 | #endif
66 |
--------------------------------------------------------------------------------
/src/math/MatrixStack.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #include "MatrixStack.hpp"
25 | #include "Debug.hpp"
26 |
27 | #include
28 |
29 | std::stack MatrixStack::_stacks[3] = {
30 | std::stack(std::deque(1, Mat4())),
31 | std::stack(std::deque(1, Mat4())),
32 | std::stack(std::deque(1, Mat4()))
33 | };
34 |
35 | void MatrixStack::set(StackName n, const Mat4 &m) {
36 | ASSERT(n <= VIEW_STACK, "Cannot manipulate virtual stacks\n");
37 | _stacks[n].top() = m;
38 | }
39 |
40 | void MatrixStack::mulR(StackName n, const Mat4 &m) {
41 | ASSERT(n <= VIEW_STACK, "Cannot manipulate virtual stacks\n");
42 | _stacks[n].top() = _stacks[n].top()*m;
43 | }
44 |
45 | void MatrixStack::mulL(StackName n, const Mat4 &m) {
46 | ASSERT(n <= VIEW_STACK, "Cannot manipulate virtual stacks\n");
47 | _stacks[n].top() = m*_stacks[n].top();
48 | }
49 |
50 | void MatrixStack::get(StackName n, Mat4 &m) {
51 | switch(n) {
52 | case PROJECTION_STACK:
53 | case MODEL_STACK:
54 | case VIEW_STACK:
55 | m = _stacks[n].top();
56 | break;
57 | case MODELVIEW_STACK:
58 | m = _stacks[VIEW_STACK].top().pseudoInvert()*_stacks[MODEL_STACK].top();
59 | break;
60 | case MODELVIEWPROJECTION_STACK:
61 | m = _stacks[PROJECTION_STACK].top()*
62 | _stacks[VIEW_STACK].top().pseudoInvert()*
63 | _stacks[MODEL_STACK].top();
64 | break;
65 | case INV_MODEL_STACK:
66 | m = _stacks[MODEL_STACK].top().pseudoInvert();
67 | break;
68 | case INV_VIEW_STACK:
69 | m = _stacks[VIEW_STACK].top().pseudoInvert();
70 | break;
71 | case INV_MODELVIEW_STACK:
72 | m = _stacks[MODEL_STACK].top().pseudoInvert()*_stacks[VIEW_STACK].top();
73 | break;
74 | default:
75 | FAIL("Invalid matrix stack\n");
76 | }
77 | }
78 |
79 | void MatrixStack::copyPush(StackName n) {
80 | ASSERT(n <= VIEW_STACK, "Cannot manipulate virtual stacks\n");
81 | _stacks[n].push(_stacks[n].top());
82 | }
83 |
84 | void MatrixStack::push(StackName n) {
85 | ASSERT(n <= VIEW_STACK, "Cannot manipulate virtual stacks\n");
86 | _stacks[n].push(Mat4());
87 | }
88 |
89 | void MatrixStack::pop(StackName n) {
90 | ASSERT(n <= VIEW_STACK, "Cannot manipulate virtual stacks\n");
91 | _stacks[n].pop();
92 | }
93 |
--------------------------------------------------------------------------------
/src/math/MatrixStack.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef RENDER_MATRIXSTACK_HPP_
25 | #define RENDER_MATRIXSTACK_HPP_
26 |
27 | #include "Mat4.hpp"
28 |
29 | #include
30 |
31 | enum StackName {
32 | PROJECTION_STACK,
33 | MODEL_STACK,
34 | VIEW_STACK,
35 | /* Virtual stacks */
36 | MODELVIEW_STACK,
37 | MODELVIEWPROJECTION_STACK,
38 | INV_MODEL_STACK,
39 | INV_VIEW_STACK,
40 | INV_MODELVIEW_STACK,
41 |
42 | MATRIX_STACK_COUNT
43 | };
44 |
45 | enum StackFlag {
46 | PROJECTION_FLAG = (1 << 0),
47 | MODEL_FLAG = (1 << 1),
48 | VIEW_FLAG = (1 << 2),
49 | /* Virtual stacks */
50 | MODELVIEW_FLAG = (1 << 3),
51 | MODELVIEWPROJECTION_FLAG = (1 << 4),
52 | INV_MODEL_FLAG = (1 << 5),
53 | INV_VIEW_FLAG = (1 << 6),
54 | INV_MODELVIEW_FLAG = (1 << 7)
55 | };
56 |
57 | class MatrixStack {
58 | static std::stack _stacks[];
59 |
60 | MatrixStack();
61 |
62 | public:
63 | static void set(StackName n, const Mat4 &m);
64 | static void mulR(StackName n, const Mat4 &m);
65 | static void mulL(StackName n, const Mat4 &m);
66 | static void get(StackName n, Mat4 &m);
67 |
68 | static void copyPush(StackName n);
69 | static void push(StackName n);
70 | static void pop(StackName n);
71 | };
72 |
73 |
74 | #endif /* RENDER_MATRIXSTACK_HPP_ */
75 |
--------------------------------------------------------------------------------
/src/math/Vec3.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef MATH_VEC3_HPP_
25 | #define MATH_VEC3_HPP_
26 |
27 | #include
28 | #include
29 | #include
30 |
31 | struct Vec3 {
32 | union {
33 | struct { float x, y, z; };
34 | float a[3];
35 | };
36 |
37 | Vec3() : x(0.0f), y(0.0f), z(0.0f) {}
38 | Vec3(float a) : x(a), y(a), z(a) {}
39 | Vec3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
40 |
41 | Vec3 cross(const Vec3 &b) const {
42 | return Vec3(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x);
43 | }
44 |
45 | Vec3 invert() const {
46 | return Vec3(1.0f/x, 1.0f/y, 1.0f/z);
47 | }
48 |
49 | float dot(const Vec3 &b) const {
50 | return x*b.x + y*b.y + z*b.z;
51 | }
52 |
53 | float length() const {
54 | return std::sqrt(x*x + y*y + z*z);
55 | }
56 |
57 | Vec3 normalize() const {
58 | float invSqrt = 1.0f/std::sqrt(x*x + y*y + z*z);
59 |
60 | return Vec3(x*invSqrt, y*invSqrt, z*invSqrt);
61 | }
62 |
63 | Vec3 reflect(const Vec3 &n) const {
64 | float proj = (n.dot(*this))*2.0f;
65 | /* Overloaded operators not defined yet */
66 | return Vec3(
67 | this->x - n.x*proj,
68 | this->y - n.y*proj,
69 | this->z - n.z*proj
70 | );
71 | }
72 |
73 | Vec3 &operator+=(const Vec3 &b) {
74 | x += b.x;
75 | y += b.y;
76 | z += b.z;
77 | return *this;
78 | }
79 |
80 | Vec3 &operator-=(const Vec3 &b) {
81 | x -= b.x;
82 | y -= b.y;
83 | z -= b.z;
84 | return *this;
85 | }
86 |
87 | Vec3 &operator*=(const Vec3 &b) {
88 | x *= b.x;
89 | y *= b.y;
90 | z *= b.z;
91 | return *this;
92 | }
93 |
94 | Vec3 &operator/=(const Vec3 &b) {
95 | x /= b.x;
96 | y /= b.y;
97 | z /= b.z;
98 | return *this;
99 | }
100 |
101 | Vec3 &operator*=(float b) {
102 | x *= b;
103 | y *= b;
104 | z *= b;
105 | return *this;
106 | }
107 |
108 | Vec3 &operator/=(float b) {
109 | x /= b;
110 | y /= b;
111 | z /= b;
112 | return *this;
113 | }
114 |
115 | Vec3 operator-() const {
116 | return Vec3(-x, -y, -z);
117 | }
118 |
119 | Vec3 operator+(const Vec3 &b) const {
120 | return Vec3(x + b.x, y + b.y, z + b.z);
121 | }
122 |
123 | Vec3 operator-(const Vec3 &b) const {
124 | return Vec3(x - b.x, y - b.y, z - b.z);
125 | }
126 |
127 | Vec3 operator*(const Vec3 &b) const {
128 | return Vec3(x*b.x, y*b.y, z*b.z);
129 | }
130 |
131 | Vec3 operator/(const Vec3 &b) const {
132 | return Vec3(x/b.x, y/b.y, z/b.z);
133 | }
134 |
135 | Vec3 operator*(float b) const {
136 | return Vec3(x*b, y*b, z*b);
137 | }
138 |
139 | Vec3 operator/(float b) const {
140 | return Vec3(x/b, y/b, z/b);
141 | }
142 |
143 | bool operator>(const Vec3 &b) const {
144 | return x > b.x && y > b.y && z > b.z;
145 | }
146 |
147 | bool operator<(const Vec3 &b) const {
148 | return x < b.x && y < b.y && z < b.z;
149 | }
150 |
151 | bool operator>=(const Vec3 &b) const {
152 | return x >= b.x && y >= b.y && z >= b.z;
153 | }
154 |
155 | bool operator<=(const Vec3 &b) const {
156 | return x <= b.x && y <= b.y && z <= b.z;
157 | }
158 |
159 | bool operator==(const Vec3 &b) const {
160 | return x == b.x && y == b.y && z == b.z;
161 | }
162 |
163 | bool operator!=(const Vec3 &b) const {
164 | return x != b.x || y != b.y || z != b.z;
165 | }
166 |
167 | friend std::ostream &operator<< (std::ostream &stream, const Vec3 &v) {
168 | return stream << "(" << v.x << ", " << v.y << ", " << v.z << ")";
169 | }
170 | };
171 |
172 | static inline Vec3 operator*(float a, const Vec3 &b) {
173 | return Vec3(a*b.x, a*b.y, a*b.z);
174 | }
175 |
176 | static inline Vec3 operator/(float a, const Vec3 &b) {
177 | return Vec3(a/b.x, a/b.y, a/b.z);
178 | }
179 |
180 | namespace std {
181 |
182 | static inline Vec3 fabs(const Vec3 &v) {
183 | return Vec3(fabs(v.x), fabs(v.y), fabs(v.z));
184 | }
185 |
186 | static inline bool isnan(const Vec3 &v) {
187 | return isnan(v.x) || isnan(v.y) || isnan(v.z);
188 | }
189 |
190 | static inline Vec3 exp(const Vec3 &v) {
191 | return Vec3(
192 | std::exp(v.x),
193 | std::exp(v.y),
194 | std::exp(v.z)
195 | );
196 | }
197 |
198 | static inline Vec3 pow(const Vec3 &v, float p) {
199 | return Vec3(
200 | std::pow(v.x, p),
201 | std::pow(v.y, p),
202 | std::pow(v.z, p)
203 | );
204 | }
205 |
206 | }
207 |
208 | #endif
209 |
--------------------------------------------------------------------------------
/src/third-party/lz4.h:
--------------------------------------------------------------------------------
1 | /*
2 | LZ4 - Fast LZ compression algorithm
3 | Header File
4 | Copyright (C) 2011-2015, Yann Collet.
5 |
6 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
7 |
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions are
10 | met:
11 |
12 | * Redistributions of source code must retain the above copyright
13 | notice, this list of conditions and the following disclaimer.
14 | * Redistributions in binary form must reproduce the above
15 | copyright notice, this list of conditions and the following disclaimer
16 | in the documentation and/or other materials provided with the
17 | distribution.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | You can contact the author at :
32 | - LZ4 source repository : https://github.com/Cyan4973/lz4
33 | - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
34 | */
35 | #pragma once
36 |
37 | #if defined (__cplusplus)
38 | extern "C" {
39 | #endif
40 |
41 | /*
42 | * lz4.h provides block compression functions, and gives full buffer control to programmer.
43 | * If you need to generate inter-operable compressed data (respecting LZ4 frame specification),
44 | * and can let the library handle its own memory, please use lz4frame.h instead.
45 | */
46 |
47 | /**************************************
48 | * Version
49 | **************************************/
50 | #define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
51 | #define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */
52 | #define LZ4_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */
53 | #define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
54 | int LZ4_versionNumber (void);
55 |
56 | /**************************************
57 | * Tuning parameter
58 | **************************************/
59 | /*
60 | * LZ4_MEMORY_USAGE :
61 | * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
62 | * Increasing memory usage improves compression ratio
63 | * Reduced memory usage can improve speed, due to cache effect
64 | * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
65 | */
66 | #define LZ4_MEMORY_USAGE 14
67 |
68 |
69 | /**************************************
70 | * Simple Functions
71 | **************************************/
72 |
73 | int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize);
74 | int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize);
75 |
76 | /*
77 | LZ4_compress_default() :
78 | Compresses 'sourceSize' bytes from buffer 'source'
79 | into already allocated 'dest' buffer of size 'maxDestSize'.
80 | Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize).
81 | It also runs faster, so it's a recommended setting.
82 | If the function cannot compress 'source' into a more limited 'dest' budget,
83 | compression stops *immediately*, and the function result is zero.
84 | As a consequence, 'dest' content is not valid.
85 | This function never writes outside 'dest' buffer, nor read outside 'source' buffer.
86 | sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE
87 | maxDestSize : full or partial size of buffer 'dest' (which must be already allocated)
88 | return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize)
89 | or 0 if compression fails
90 |
91 | LZ4_decompress_safe() :
92 | compressedSize : is the precise full size of the compressed block.
93 | maxDecompressedSize : is the size of destination buffer, which must be already allocated.
94 | return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize)
95 | If destination buffer is not large enough, decoding will stop and output an error code (<0).
96 | If the source stream is detected malformed, the function will stop decoding and return a negative result.
97 | This function is protected against buffer overflow exploits, including malicious data packets.
98 | It never writes outside output buffer, nor reads outside input buffer.
99 | */
100 |
101 |
102 | /**************************************
103 | * Advanced Functions
104 | **************************************/
105 | #define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
106 | #define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
107 |
108 | /*
109 | LZ4_compressBound() :
110 | Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible)
111 | This function is primarily useful for memory allocation purposes (destination buffer size).
112 | Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
113 | Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize)
114 | inputSize : max supported value is LZ4_MAX_INPUT_SIZE
115 | return : maximum output size in a "worst case" scenario
116 | or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE)
117 | */
118 | int LZ4_compressBound(int inputSize);
119 |
120 | /*
121 | LZ4_compress_fast() :
122 | Same as LZ4_compress_default(), but allows to select an "acceleration" factor.
123 | The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
124 | It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
125 | An acceleration value of "1" is the same as regular LZ4_compress_default()
126 | Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1.
127 | */
128 | int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration);
129 |
130 |
131 | /*
132 | LZ4_compress_fast_extState() :
133 | Same compression function, just using an externally allocated memory space to store compression state.
134 | Use LZ4_sizeofState() to know how much memory must be allocated,
135 | and allocate it on 8-bytes boundaries (using malloc() typically).
136 | Then, provide it as 'void* state' to compression function.
137 | */
138 | int LZ4_sizeofState(void);
139 | int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration);
140 |
141 |
142 | /*
143 | LZ4_compress_destSize() :
144 | Reverse the logic, by compressing as much data as possible from 'source' buffer
145 | into already allocated buffer 'dest' of size 'targetDestSize'.
146 | This function either compresses the entire 'source' content into 'dest' if it's large enough,
147 | or fill 'dest' buffer completely with as much data as possible from 'source'.
148 | *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'.
149 | New value is necessarily <= old value.
150 | return : Nb bytes written into 'dest' (necessarily <= targetDestSize)
151 | or 0 if compression fails
152 | */
153 | int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize);
154 |
155 |
156 | /*
157 | LZ4_decompress_fast() :
158 | originalSize : is the original and therefore uncompressed size
159 | return : the number of bytes read from the source buffer (in other words, the compressed size)
160 | If the source stream is detected malformed, the function will stop decoding and return a negative result.
161 | Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes.
162 | note : This function fully respect memory boundaries for properly formed compressed data.
163 | It is a bit faster than LZ4_decompress_safe().
164 | However, it does not provide any protection against intentionally modified data stream (malicious input).
165 | Use this function in trusted environment only (data to decode comes from a trusted source).
166 | */
167 | int LZ4_decompress_fast (const char* source, char* dest, int originalSize);
168 |
169 | /*
170 | LZ4_decompress_safe_partial() :
171 | This function decompress a compressed block of size 'compressedSize' at position 'source'
172 | into destination buffer 'dest' of size 'maxDecompressedSize'.
173 | The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached,
174 | reducing decompression time.
175 | return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize)
176 | Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller.
177 | Always control how many bytes were decoded.
178 | If the source stream is detected malformed, the function will stop decoding and return a negative result.
179 | This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets
180 | */
181 | int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize);
182 |
183 |
184 | /***********************************************
185 | * Streaming Compression Functions
186 | ***********************************************/
187 | #define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4)
188 | #define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long))
189 | /*
190 | * LZ4_stream_t
191 | * information structure to track an LZ4 stream.
192 | * important : init this structure content before first use !
193 | * note : only allocated directly the structure if you are statically linking LZ4
194 | * If you are using liblz4 as a DLL, please use below construction methods instead.
195 | */
196 | typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t;
197 |
198 | /*
199 | * LZ4_resetStream
200 | * Use this function to init an allocated LZ4_stream_t structure
201 | */
202 | void LZ4_resetStream (LZ4_stream_t* streamPtr);
203 |
204 | /*
205 | * LZ4_createStream will allocate and initialize an LZ4_stream_t structure
206 | * LZ4_freeStream releases its memory.
207 | * In the context of a DLL (liblz4), please use these methods rather than the static struct.
208 | * They are more future proof, in case of a change of LZ4_stream_t size.
209 | */
210 | LZ4_stream_t* LZ4_createStream(void);
211 | int LZ4_freeStream (LZ4_stream_t* streamPtr);
212 |
213 | /*
214 | * LZ4_loadDict
215 | * Use this function to load a static dictionary into LZ4_stream.
216 | * Any previous data will be forgotten, only 'dictionary' will remain in memory.
217 | * Loading a size of 0 is allowed.
218 | * Return : dictionary size, in bytes (necessarily <= 64 KB)
219 | */
220 | int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);
221 |
222 | /*
223 | * LZ4_compress_fast_continue
224 | * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio.
225 | * Important : Previous data blocks are assumed to still be present and unmodified !
226 | * 'dst' buffer must be already allocated.
227 | * If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.
228 | * If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero.
229 | */
230 | int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration);
231 |
232 | /*
233 | * LZ4_saveDict
234 | * If previously compressed data block is not guaranteed to remain available at its memory location
235 | * save it into a safer place (char* safeBuffer)
236 | * Note : you don't need to call LZ4_loadDict() afterwards,
237 | * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue()
238 | * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error
239 | */
240 | int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize);
241 |
242 |
243 | /************************************************
244 | * Streaming Decompression Functions
245 | ************************************************/
246 |
247 | #define LZ4_STREAMDECODESIZE_U64 4
248 | #define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
249 | typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t;
250 | /*
251 | * LZ4_streamDecode_t
252 | * information structure to track an LZ4 stream.
253 | * init this structure content using LZ4_setStreamDecode or memset() before first use !
254 | *
255 | * In the context of a DLL (liblz4) please prefer usage of construction methods below.
256 | * They are more future proof, in case of a change of LZ4_streamDecode_t size in the future.
257 | * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure
258 | * LZ4_freeStreamDecode releases its memory.
259 | */
260 | LZ4_streamDecode_t* LZ4_createStreamDecode(void);
261 | int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);
262 |
263 | /*
264 | * LZ4_setStreamDecode
265 | * Use this function to instruct where to find the dictionary.
266 | * Setting a size of 0 is allowed (same effect as reset).
267 | * Return : 1 if OK, 0 if error
268 | */
269 | int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);
270 |
271 | /*
272 | *_continue() :
273 | These decoding functions allow decompression of multiple blocks in "streaming" mode.
274 | Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB)
275 | In the case of a ring buffers, decoding buffer must be either :
276 | - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions)
277 | In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB).
278 | - Larger than encoding buffer, by a minimum of maxBlockSize more bytes.
279 | maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block.
280 | In which case, encoding and decoding buffers do not need to be synchronized,
281 | and encoding ring buffer can have any size, including small ones ( < 64 KB).
282 | - _At least_ 64 KB + 8 bytes + maxBlockSize.
283 | In which case, encoding and decoding buffers do not need to be synchronized,
284 | and encoding ring buffer can have any size, including larger than decoding buffer.
285 | Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer,
286 | and indicate where it is saved using LZ4_setStreamDecode()
287 | */
288 | int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize);
289 | int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize);
290 |
291 |
292 | /*
293 | Advanced decoding functions :
294 | *_usingDict() :
295 | These decoding functions work the same as
296 | a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue()
297 | They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure.
298 | */
299 | int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize);
300 | int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize);
301 |
302 |
303 |
304 | /**************************************
305 | * Obsolete Functions
306 | **************************************/
307 | /* Deprecate Warnings */
308 | /* Should these warnings messages be a problem,
309 | it is generally possible to disable them,
310 | with -Wno-deprecated-declarations for gcc
311 | or _CRT_SECURE_NO_WARNINGS in Visual for example.
312 | You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */
313 | #ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK
314 | # define LZ4_DEPRECATE_WARNING_DEFBLOCK
315 | # define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
316 | # if (LZ4_GCC_VERSION >= 405) || defined(__clang__)
317 | # define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
318 | # elif (LZ4_GCC_VERSION >= 301)
319 | # define LZ4_DEPRECATED(message) __attribute__((deprecated))
320 | # elif defined(_MSC_VER)
321 | # define LZ4_DEPRECATED(message) __declspec(deprecated(message))
322 | # else
323 | # pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler")
324 | # define LZ4_DEPRECATED(message)
325 | # endif
326 | #endif /* LZ4_DEPRECATE_WARNING_DEFBLOCK */
327 |
328 | /* Obsolete compression functions */
329 | /* These functions are planned to start generate warnings by r131 approximately */
330 | int LZ4_compress (const char* source, char* dest, int sourceSize);
331 | int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize);
332 | int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize);
333 | int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
334 | int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);
335 | int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
336 |
337 | /* Obsolete decompression functions */
338 | /* These function names are completely deprecated and must no longer be used.
339 | They are only provided here for compatibility with older programs.
340 | - LZ4_uncompress is the same as LZ4_decompress_fast
341 | - LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe
342 | These function prototypes are now disabled; uncomment them only if you really need them.
343 | It is highly recommended to stop using these prototypes and migrate to maintained ones */
344 | /* int LZ4_uncompress (const char* source, char* dest, int outputSize); */
345 | /* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */
346 |
347 | /* Obsolete streaming functions; use new streaming interface whenever possible */
348 | LZ4_DEPRECATED("use LZ4_createStream() instead") void* LZ4_create (char* inputBuffer);
349 | LZ4_DEPRECATED("use LZ4_createStream() instead") int LZ4_sizeofStreamState(void);
350 | LZ4_DEPRECATED("use LZ4_resetStream() instead") int LZ4_resetStreamState(void* state, char* inputBuffer);
351 | LZ4_DEPRECATED("use LZ4_saveDict() instead") char* LZ4_slideInputBuffer (void* state);
352 |
353 | /* Obsolete streaming decoding functions */
354 | LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);
355 | LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);
356 |
357 |
358 | #if defined (__cplusplus)
359 | }
360 | #endif
361 |
--------------------------------------------------------------------------------
/src/third-party/ply.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Header for PLY polygon files.
4 |
5 | - Greg Turk, March 1994
6 |
7 | A PLY file contains a single polygonal _object_.
8 |
9 | An object is composed of lists of _elements_. Typical elements are
10 | vertices, faces, edges and materials.
11 |
12 | Each type of element for a given object has one or more _properties_
13 | associated with the element type. For instance, a vertex element may
14 | have as properties three floating-point values x,y,z and three unsigned
15 | chars for red, green and blue.
16 |
17 | ---------------------------------------------------------------
18 |
19 | Copyright (c) 1994 The Board of Trustees of The Leland Stanford
20 | Junior University. All rights reserved.
21 |
22 | Permission to use, copy, modify and distribute this software and its
23 | documentation for any purpose is hereby granted without fee, provided
24 | that the above copyright notice and this permission notice appear in
25 | all copies of this software and that you do not sell the software.
26 |
27 | THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
28 | EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
29 | WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
30 |
31 | */
32 |
33 | #ifndef __PLY_H__
34 | #define __PLY_H__
35 |
36 | #ifdef __cplusplus
37 | extern "C" {
38 | #endif
39 |
40 | #include
41 | #include
42 |
43 | #define PLY_ASCII 1 /* ascii PLY file */
44 | #define PLY_BINARY_BE 2 /* binary PLY file, big endian */
45 | #define PLY_BINARY_LE 3 /* binary PLY file, little endian */
46 |
47 | #define PLY_OKAY 0 /* ply routine worked okay */
48 | #define PLY_ERROR -1 /* error in ply routine */
49 |
50 | /* scalar data types supported by PLY format */
51 |
52 | #define PLY_START_TYPE 0
53 | #define PLY_CHAR 1
54 | #define PLY_SHORT 2
55 | #define PLY_INT 3
56 | #define PLY_UCHAR 4
57 | #define PLY_USHORT 5
58 | #define PLY_UINT 6
59 | #define PLY_FLOAT 7
60 | #define PLY_DOUBLE 8
61 | #define PLY_END_TYPE 9
62 |
63 | #define PLY_SCALAR 0
64 | #define PLY_LIST 1
65 |
66 |
67 | typedef struct PlyProperty { /* description of a property */
68 |
69 | char *name; /* property name */
70 | int external_type; /* file's data type */
71 | int internal_type; /* program's data type */
72 | int offset; /* offset bytes of prop in a struct */
73 |
74 | int is_list; /* 1 = list, 0 = scalar */
75 | int count_external; /* file's count type */
76 | int count_internal; /* program's count type */
77 | int count_offset; /* offset byte for list count */
78 |
79 | } PlyProperty;
80 |
81 | typedef struct PlyElement { /* description of an element */
82 | char *name; /* element name */
83 | int num; /* number of elements in this object */
84 | int size; /* size of element (bytes) or -1 if variable */
85 | int nprops; /* number of properties for this element */
86 | PlyProperty **props; /* list of properties in the file */
87 | char *store_prop; /* flags: property wanted by user? */
88 | int other_offset; /* offset to un-asked-for props, or -1 if none*/
89 | int other_size; /* size of other_props structure */
90 | } PlyElement;
91 |
92 | typedef struct PlyOtherProp { /* describes other properties in an element */
93 | char *name; /* element name */
94 | int size; /* size of other_props */
95 | int nprops; /* number of properties in other_props */
96 | PlyProperty **props; /* list of properties in other_props */
97 | } PlyOtherProp;
98 |
99 | typedef struct OtherData { /* for storing other_props for an other element */
100 | void *other_props;
101 | } OtherData;
102 |
103 | typedef struct OtherElem { /* data for one "other" element */
104 | char *elem_name; /* names of other elements */
105 | int elem_count; /* count of instances of each element */
106 | OtherData **other_data; /* actual property data for the elements */
107 | PlyOtherProp *other_props; /* description of the property data */
108 | } OtherElem;
109 |
110 | typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */
111 | int num_elems; /* number of other elements */
112 | OtherElem *other_list; /* list of data for other elements */
113 | } PlyOtherElems;
114 |
115 | typedef struct PlyFile { /* description of PLY file */
116 | FILE *fp; /* file pointer */
117 | int file_type; /* ascii or binary */
118 | float version; /* version number of file */
119 | int nelems; /* number of elements of object */
120 | PlyElement **elems; /* list of elements */
121 | int num_comments; /* number of comments */
122 | char **comments; /* list of comments */
123 | int num_obj_info; /* number of items of object information */
124 | char **obj_info; /* list of object info items */
125 | PlyElement *which_elem; /* which element we're currently writing */
126 | PlyOtherElems *other_elems; /* "other" elements from a PLY file */
127 | } PlyFile;
128 |
129 | /* memory allocation */
130 | extern char *my_alloc();
131 | #define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__)
132 |
133 |
134 | /*** delcaration of routines ***/
135 |
136 | extern PlyFile *ply_write(FILE *, int, char **, int);
137 | extern PlyFile *ply_open_for_writing(char *, int, char **, int, float *);
138 | extern void ply_describe_element(PlyFile *, char *, int, int, PlyProperty *);
139 | extern void ply_describe_property(PlyFile *, char *, PlyProperty *);
140 | extern void ply_element_count(PlyFile *, char *, int);
141 | extern void ply_header_complete(PlyFile *);
142 | extern void ply_put_element_setup(PlyFile *, char *);
143 | extern void ply_put_element(PlyFile *, void *);
144 | extern void ply_put_comment(PlyFile *, char *);
145 | extern void ply_put_obj_info(PlyFile *, char *);
146 | extern PlyFile *ply_read(FILE *, int *, char ***);
147 | extern PlyFile *ply_open_for_reading(const char *, int *, char ***, int *, float *);
148 | extern PlyProperty **ply_get_element_description(PlyFile *, const char *, int*, int*);
149 | extern void ply_get_element_setup( PlyFile *, char *, int, PlyProperty *);
150 | extern void ply_get_property(PlyFile *, const char *, PlyProperty *);
151 | extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int);
152 | extern void ply_get_element(PlyFile *, void *);
153 | extern char **ply_get_comments(PlyFile *, int *);
154 | extern char **ply_get_obj_info(PlyFile *, int *);
155 | extern void ply_close(PlyFile *);
156 | extern void ply_get_info(PlyFile *, float *, int *);
157 | extern PlyOtherElems *ply_get_other_element (PlyFile *, char *, int);
158 | extern void ply_describe_other_elements ( PlyFile *, PlyOtherElems *);
159 | extern void ply_put_other_elements (PlyFile *);
160 | extern void ply_free_other_elements (PlyOtherElems *);
161 |
162 | extern int equal_strings(const char *, const char *);
163 |
164 |
165 | #ifdef __cplusplus
166 | }
167 | #endif
168 | #endif /* !__PLY_H__ */
169 |
170 |
--------------------------------------------------------------------------------
/src/third-party/tribox3.c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tunabrain/sparse-voxel-octrees/c4c2a9d3015056c269c73430f223e69e3b933b83/src/third-party/tribox3.c
--------------------------------------------------------------------------------
/src/third-party/tribox3.h:
--------------------------------------------------------------------------------
1 | #ifndef TRIBOX3_H_
2 | #define TRIBOX3_H_
3 |
4 | #ifdef __cplusplus
5 | extern "C" {
6 | #endif
7 |
8 | int triBoxOverlap(float boxcenter[3],float boxhalfsize[3],float triverts[3][3]);
9 |
10 | #ifdef __cplusplus
11 | }
12 | #endif
13 |
14 | #endif /* TRIBOX3_H_ */
15 |
--------------------------------------------------------------------------------
/src/thread/TaskGroup.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef TASKGROUP_HPP_
25 | #define TASKGROUP_HPP_
26 |
27 | #include "IntTypes.hpp"
28 |
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | class TaskGroup
37 | {
38 | typedef std::function TaskFunc;
39 | typedef std::function Finisher;
40 |
41 | TaskFunc _func;
42 | Finisher _finisher;
43 |
44 | std::exception_ptr _exceptionPtr;
45 | std::atomic _startedSubTasks;
46 | std::atomic _finishedSubTasks;
47 | uint32 _numSubTasks;
48 |
49 | std::mutex _waitMutex;
50 | std::condition_variable _waitCond;
51 | std::atomic _done, _abort;
52 |
53 | void finish()
54 | {
55 | if (_finisher && !_abort)
56 | _finisher();
57 |
58 | _done = true;
59 | _waitCond.notify_all();
60 | }
61 |
62 | public:
63 | TaskGroup(TaskFunc func, Finisher finisher, uint32 numSubTasks)
64 | : _func(std::move(func)),
65 | _finisher(std::move(finisher)),
66 | _startedSubTasks(0),
67 | _finishedSubTasks(0),
68 | _numSubTasks(numSubTasks),
69 | _done(false),
70 | _abort(false)
71 | {
72 | }
73 |
74 | void run(uint32 threadId, uint32 taskId)
75 | {
76 | try {
77 | _func(taskId, _numSubTasks, threadId);
78 | } catch (...) {
79 | _exceptionPtr = std::current_exception();
80 | }
81 |
82 | uint32 num = ++_finishedSubTasks;
83 | if (num == _numSubTasks || (_abort && num == _startedSubTasks))
84 | finish();
85 | }
86 |
87 | void wait()
88 | {
89 | std::unique_lock lock(_waitMutex);
90 | _waitCond.wait(lock, [this]{return _done == true;});
91 |
92 | if (_exceptionPtr)
93 | std::rethrow_exception(_exceptionPtr);
94 | }
95 |
96 | void abort()
97 | {
98 | _abort = true;
99 | _done = _done || _startedSubTasks == 0;
100 | }
101 |
102 | bool isAborting() const
103 | {
104 | return _abort;
105 | }
106 |
107 | bool isDone() const
108 | {
109 | return _done;
110 | }
111 |
112 | uint32 startSubTask()
113 | {
114 | return _startedSubTasks++;
115 | }
116 |
117 | uint32 numSubTasks() const
118 | {
119 | return _numSubTasks;
120 | }
121 | };
122 |
123 | #endif /* TASKGROUP_HPP_ */
124 |
--------------------------------------------------------------------------------
/src/thread/ThreadPool.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #include "ThreadPool.hpp"
25 |
26 | #include
27 |
28 | ThreadPool::ThreadPool(uint32 threadCount)
29 | : _threadCount(threadCount),
30 | _terminateFlag(false)
31 | {
32 | startThreads();
33 | }
34 |
35 | ThreadPool::~ThreadPool()
36 | {
37 | stop();
38 | }
39 |
40 | std::shared_ptr ThreadPool::acquireTask(uint32 &subTaskId)
41 | {
42 | if (_terminateFlag)
43 | return nullptr;
44 | std::shared_ptr task = _tasks.front();
45 | if (task->isAborting()) {
46 | _tasks.pop_front();
47 | return nullptr;
48 | }
49 | subTaskId = task->startSubTask();
50 | if (subTaskId == task->numSubTasks() - 1)
51 | _tasks.pop_front();
52 | return std::move(task);
53 | }
54 |
55 | void ThreadPool::runWorker(uint32 threadId)
56 | {
57 | while (!_terminateFlag) {
58 | uint32 subTaskId;
59 | std::shared_ptr task;
60 | {
61 | std::unique_lock lock(_taskMutex);
62 | _taskCond.wait(lock, [this]{return _terminateFlag || !_tasks.empty();});
63 | task = acquireTask(subTaskId);
64 | }
65 | if (task)
66 | task->run(threadId, subTaskId);
67 | }
68 | }
69 |
70 | void ThreadPool::startThreads()
71 | {
72 | _terminateFlag = false;
73 | for (uint32 i = 0; i < _threadCount; ++i) {
74 | _workers.emplace_back(new std::thread(&ThreadPool::runWorker, this, uint32(_workers.size())));
75 | _idToNumericId.insert(std::make_pair(_workers.back()->get_id(), i));
76 | }
77 | }
78 |
79 | void ThreadPool::yield(TaskGroup &wait)
80 | {
81 | std::chrono::milliseconds waitSpan(10);
82 | uint32 id = _threadCount; // Threads not in the pool get a previously unassigned id
83 |
84 | auto iter = _idToNumericId.find(std::this_thread::get_id());
85 | if (iter != _idToNumericId.end())
86 | id = iter->second;
87 |
88 | while (!wait.isDone() && !_terminateFlag) {
89 | uint32 subTaskId;
90 | std::shared_ptr task;
91 | {
92 | std::unique_lock lock(_taskMutex);
93 | if (!_taskCond.wait_for(lock, waitSpan, [this]{return _terminateFlag || !_tasks.empty();}))
94 | continue;
95 | task = acquireTask(subTaskId);
96 | }
97 | if (task)
98 | task->run(id, subTaskId);
99 | }
100 | }
101 |
102 | void ThreadPool::reset()
103 | {
104 | stop();
105 | _tasks.clear();
106 | startThreads();
107 | }
108 |
109 | void ThreadPool::stop()
110 | {
111 | _terminateFlag = true;
112 | {
113 | std::unique_lock lock(_taskMutex);
114 | _taskCond.notify_all();
115 | }
116 | while (!_workers.empty()) {
117 | _workers.back()->detach();
118 | _workers.pop_back();
119 | }
120 | }
121 |
122 | std::shared_ptr ThreadPool::enqueue(TaskFunc func, int numSubtasks, Finisher finisher)
123 | {
124 | std::shared_ptr task(std::make_shared(std::move(func),
125 | std::move(finisher), numSubtasks));
126 |
127 | {
128 | std::unique_lock lock(_taskMutex);
129 | _tasks.emplace_back(task);
130 | if (numSubtasks == 1)
131 | _taskCond.notify_one();
132 | else
133 | _taskCond.notify_all();
134 | }
135 |
136 | return std::move(task);
137 | }
138 |
--------------------------------------------------------------------------------
/src/thread/ThreadPool.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef THREADPOOL_HPP_
25 | #define THREADPOOL_HPP_
26 |
27 | #include "TaskGroup.hpp"
28 |
29 | #include "IntTypes.hpp"
30 |
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 |
41 | class ThreadPool
42 | {
43 | typedef std::function TaskFunc;
44 | typedef std::function Finisher;
45 |
46 | uint32 _threadCount;
47 | std::vector> _workers;
48 | std::atomic _terminateFlag;
49 |
50 | std::deque> _tasks;
51 | std::mutex _taskMutex;
52 | std::condition_variable _taskCond;
53 |
54 | std::unordered_map _idToNumericId;
55 |
56 | std::shared_ptr acquireTask(uint32 &subTaskId);
57 | void runWorker(uint32 threadId);
58 | void startThreads();
59 |
60 | public:
61 | ThreadPool(uint32 threadCount);
62 | ~ThreadPool();
63 |
64 | void yield(TaskGroup &wait);
65 |
66 | void reset();
67 | void stop();
68 |
69 | std::shared_ptr enqueue(TaskFunc func, int numSubtasks = 1,
70 | Finisher finisher = Finisher());
71 |
72 | uint32 threadCount() const
73 | {
74 | return _threadCount;
75 | }
76 | };
77 |
78 | #endif /* THREADPOOL_HPP_ */
79 |
--------------------------------------------------------------------------------
/src/thread/ThreadUtils.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #include "ThreadPool.hpp"
25 |
26 | #include
27 | #if _WIN32
28 | #include
29 | #else
30 | #include
31 | #endif
32 | #include
33 |
34 | namespace ThreadUtils {
35 |
36 | ThreadPool *pool = nullptr;
37 |
38 | uint32 idealThreadCount()
39 | {
40 | // std::thread::hardware_concurrency support is not great, so let's try
41 | // native APIs first
42 | #if _WIN32
43 | SYSTEM_INFO info;
44 | GetSystemInfo(&info);
45 | if (info.dwNumberOfProcessors > 0)
46 | return info.dwNumberOfProcessors;
47 | #else
48 | int nprocs = sysconf(_SC_NPROCESSORS_ONLN);
49 | if (nprocs > 0)
50 | return nprocs;
51 | #endif
52 | unsigned n = std::thread::hardware_concurrency();
53 | if (n > 0)
54 | return n;
55 |
56 | // All attempts failed. Let's take a guess
57 | return 4;
58 | }
59 |
60 | void startThreads(int numThreads)
61 | {
62 | pool = new ThreadPool(numThreads);
63 | }
64 |
65 | void parallelFor(uint32 start, uint32 end, uint32 partitions, std::function func)
66 | {
67 | auto taskRun = [&func, start, end](uint32 idx, uint32 num, uint32 /*threadId*/)
68 | {
69 | uint32 span = (end - start + num - 1)/num;
70 | uint32 iStart = start + span*idx;
71 | uint32 iEnd = std::min(iStart + span, end);
72 | for (uint32 i = iStart; i < iEnd; ++i)
73 | func(i);
74 | };
75 | if (partitions == 1)
76 | taskRun(0, 1, 0);
77 | else
78 | pool->yield(*pool->enqueue(taskRun, partitions));
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/thread/ThreadUtils.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Benedikt Bitterli
3 |
4 | This software is provided 'as-is', without any express or implied
5 | warranty. In no event will the authors be held liable for any damages
6 | arising from the use of this software.
7 |
8 | Permission is granted to anyone to use this software for any purpose,
9 | including commercial applications, and to alter it and redistribute it
10 | freely, subject to the following restrictions:
11 |
12 | 1. The origin of this software must not be misrepresented; you must not
13 | claim that you wrote the original software. If you use this software
14 | in a product, an acknowledgment in the product documentation would be
15 | appreciated but is not required.
16 |
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 |
20 | 3. This notice may not be removed or altered from any source
21 | distribution.
22 | */
23 |
24 | #ifndef THREADUTILS_HPP_
25 | #define THREADUTILS_HPP_
26 |
27 | #include "IntTypes.hpp"
28 |
29 | #include
30 |
31 | class ThreadPool;
32 |
33 | namespace ThreadUtils {
34 |
35 | extern ThreadPool *pool;
36 |
37 | uint32 idealThreadCount();
38 | void startThreads(int numThreads);
39 |
40 | void parallelFor(uint32 start, uint32 end, uint32 partitions, std::function func);
41 |
42 | }
43 |
44 | #endif /* THREADUTILS_HPP_ */
45 |
--------------------------------------------------------------------------------