├── src ├── vsgXchangeConfig.cmake.in ├── 3DTiles │ ├── build_vars.cmake │ ├── cmpt.cpp │ ├── b3dm.cpp │ └── SceneGraphBuilder.cpp ├── ktx │ ├── build_vars.cmake │ └── ktx_fallback.cpp ├── gltf │ └── build_vars.cmake ├── curl │ ├── build_vars.cmake │ ├── curl_fallback.cpp │ └── curl.cpp ├── gdal │ ├── build_vars.cmake │ ├── GDAL_fallback.cpp │ ├── meta_utils.cpp │ ├── GDAL.cpp │ └── gdal_utils.cpp ├── openexr │ ├── build_vars.cmake │ └── openexr_fallback.cpp ├── freetype │ ├── build_vars.cmake │ └── freetype_fallback.cpp ├── assimp │ ├── build_vars.cmake │ ├── assimp_fallback.cpp │ ├── assimp.cpp │ └── SceneConverter.h ├── images │ └── images.cpp ├── models │ └── models.cpp ├── all │ ├── Version.cpp │ ├── Version.h.in │ └── all.cpp ├── bin │ └── bin.cpp ├── CMakeLists.txt ├── cpp │ └── cpp.cpp ├── stbi │ └── stbi.cpp └── dds │ └── dds.cpp ├── applications └── vsgconv │ └── CMakeLists.txt ├── LICENSE.md ├── .gitignore ├── include └── vsgXchange │ ├── Export.h │ ├── cpp.h │ ├── all.h │ ├── bin.h │ ├── freetype.h │ ├── curl.h │ ├── models.h │ ├── images.h │ ├── gdal.h │ └── 3DTiles.h ├── CMakeLists.txt └── .clang-format /src/vsgXchangeConfig.cmake.in: -------------------------------------------------------------------------------- 1 | include(CMakeFindDependencyMacro) 2 | 3 | @FIND_DEPENDENCY_OUT@ 4 | 5 | include("${CMAKE_CURRENT_LIST_DIR}/vsgXchangeTargets.cmake") 6 | -------------------------------------------------------------------------------- /src/3DTiles/build_vars.cmake: -------------------------------------------------------------------------------- 1 | set(SOURCES ${SOURCES} 2 | 3DTiles/3DTiles.cpp 3 | 3DTiles/i3dm.cpp 4 | 3DTiles/b3dm.cpp 5 | 3DTiles/cmpt.cpp 6 | 3DTiles/SceneGraphBuilder.cpp 7 | ) 8 | -------------------------------------------------------------------------------- /src/ktx/build_vars.cmake: -------------------------------------------------------------------------------- 1 | # add CURL if available 2 | # find_package(ktx) 3 | 4 | find_package(Ktx) 5 | 6 | if(Ktx_FOUND) 7 | OPTION(vsgXchange_ktx "Optional KTX support provided" ON) 8 | endif() 9 | 10 | 11 | if(${vsgXchange_ktx}) 12 | set(SOURCES ${SOURCES} 13 | ktx/ktx.cpp 14 | ) 15 | set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} KTX::ktx) 16 | if(NOT BUILD_SHARED_LIBS) 17 | set(FIND_DEPENDENCY ${FIND_DEPENDENCY} "find_dependency(Ktx)") 18 | endif() 19 | 20 | else() 21 | set(SOURCES ${SOURCES} 22 | ktx/ktx_fallback.cpp 23 | ) 24 | endif() 25 | -------------------------------------------------------------------------------- /src/gltf/build_vars.cmake: -------------------------------------------------------------------------------- 1 | # add draco support if available 2 | find_package(draco) 3 | 4 | if(draco_FOUND) 5 | OPTION(vsgXchange_draco "Optional glTF draco support provided" ON) 6 | endif() 7 | 8 | set(SOURCES ${SOURCES} 9 | gltf/gltf.cpp 10 | gltf/SceneGraphBuilder.cpp 11 | ) 12 | 13 | if (draco_FOUND AND vsgXchange_draco) 14 | set(EXTRA_INCLUDES ${EXTRA_INCLUDES} ${draco_INCLUDE_DIRS}) 15 | set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} draco::draco) 16 | if(NOT BUILD_SHARED_LIBS) 17 | set(FIND_DEPENDENCY ${FIND_DEPENDENCY} "find_dependency(draco)") 18 | endif() 19 | endif() 20 | -------------------------------------------------------------------------------- /applications/vsgconv/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(NOT ANDROID) 2 | find_package(Threads) 3 | endif() 4 | 5 | if (UNIX) 6 | find_library(DL_LIBRARY dl) 7 | endif() 8 | 9 | set(SOURCES 10 | vsgconv.cpp 11 | ) 12 | 13 | add_executable(vsgconv ${SOURCES}) 14 | 15 | target_include_directories(vsgconv PRIVATE 16 | $ 17 | ) 18 | 19 | set_target_properties(vsgconv PROPERTIES OUTPUT_NAME vsgconv DEBUG_POSTFIX "d") 20 | 21 | target_link_libraries(vsgconv 22 | vsgXchange 23 | vsg::vsg 24 | ) 25 | 26 | install(TARGETS vsgconv 27 | RUNTIME DESTINATION bin 28 | ) 29 | -------------------------------------------------------------------------------- /src/curl/build_vars.cmake: -------------------------------------------------------------------------------- 1 | # add CURL if available 2 | find_package(CURL) 3 | 4 | if(CURL_FOUND) 5 | OPTION(vsgXchange_curl "Optional CURL support provided" ON) 6 | endif() 7 | 8 | if(${vsgXchange_curl}) 9 | set(SOURCES ${SOURCES} 10 | curl/curl.cpp 11 | ) 12 | if(TARGET CURL::libcurl) 13 | set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} CURL::libcurl) 14 | else() 15 | set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} ${CURL_LIBRARIES}) 16 | set(EXTRA_INCLUDES ${EXTRA_INCLUDES} ${CURL_INCLUDE_DIR}) 17 | endif() 18 | if(NOT BUILD_SHARED_LIBS) 19 | set(FIND_DEPENDENCY ${FIND_DEPENDENCY} "find_dependency(CURL)") 20 | endif() 21 | else() 22 | set(SOURCES ${SOURCES} 23 | curl/curl_fallback.cpp 24 | ) 25 | endif() 26 | -------------------------------------------------------------------------------- /src/gdal/build_vars.cmake: -------------------------------------------------------------------------------- 1 | # add GDAL if available 2 | find_package(GDAL QUIET) 3 | 4 | if(GDAL_FOUND) 5 | OPTION(vsgXchange_GDAL "GDAL support provided" ON) 6 | endif() 7 | 8 | if(${vsgXchange_GDAL}) 9 | set(SOURCES ${SOURCES} 10 | gdal/gdal_utils.cpp 11 | gdal/meta_utils.cpp 12 | gdal/GDAL.cpp 13 | ) 14 | 15 | if(TARGET GDAL::GDAL) 16 | set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} GDAL::GDAL) 17 | else() 18 | set(EXTRA_INCLUDES ${EXTRA_INCLUDES} ${GDAL_INCLUDE_DIR}) 19 | set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} ${GDAL_LIBRARY}) 20 | endif() 21 | set(EXTRA_DEFINES ${EXTRA_DEFINES} USE_GDAL) 22 | if(NOT BUILD_SHARED_LIBS) 23 | set(FIND_DEPENDENCY ${FIND_DEPENDENCY} "find_dependency(GDAL)") 24 | endif() 25 | else() 26 | set(SOURCES ${SOURCES} 27 | gdal/GDAL_fallback.cpp 28 | ) 29 | endif() 30 | -------------------------------------------------------------------------------- /src/openexr/build_vars.cmake: -------------------------------------------------------------------------------- 1 | # add openexr if available 2 | find_package(OpenEXR QUIET) 3 | 4 | if(OpenEXR_FOUND) 5 | OPTION(vsgXchange_openexr "Optional OpenEXR support provided" ON) 6 | endif() 7 | 8 | if (${vsgXchange_openexr}) 9 | set(SOURCES ${SOURCES} 10 | openexr/openexr.cpp 11 | ) 12 | if(OpenEXR_VERSION VERSION_LESS "3.0") 13 | set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} OpenEXR::IlmImf) 14 | else() 15 | add_compile_definitions(EXRVERSION3) 16 | set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} OpenEXR::OpenEXR) 17 | endif() 18 | set(EXTRA_INCLUDES ${EXTRA_INCLUDES} ${OpenEXR_INCLUDE_DIRS}) 19 | 20 | if(NOT BUILD_SHARED_LIBS) 21 | set(FIND_DEPENDENCY ${FIND_DEPENDENCY} "find_dependency(OpenEXR)") 22 | endif() 23 | else() 24 | set(SOURCES ${SOURCES} 25 | openexr/openexr_fallback.cpp 26 | ) 27 | endif() 28 | -------------------------------------------------------------------------------- /src/freetype/build_vars.cmake: -------------------------------------------------------------------------------- 1 | # add freetype if available 2 | find_package(Freetype) 3 | 4 | if(FREETYPE_FOUND) 5 | OPTION(vsgXchange_freetype "Freetype support provided" ON) 6 | endif() 7 | 8 | if(${vsgXchange_freetype}) 9 | set(SOURCES ${SOURCES} 10 | freetype/freetype.cpp 11 | ) 12 | if(TARGET Freetype::Freetype) 13 | set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} Freetype::Freetype) 14 | else() 15 | set(EXTRA_INCLUDES ${EXTRA_INCLUDES} ${FREETYPE_INCLUDE_DIRS}) 16 | set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} ${FREETYPE_LIBRARIES}) 17 | endif() 18 | set(EXTRA_DEFINES ${EXTRA_DEFINES} USE_FREETYPE) 19 | 20 | if(NOT BUILD_SHARED_LIBS) 21 | set(FIND_DEPENDENCY ${FIND_DEPENDENCY} "find_dependency(Freetype)") 22 | endif() 23 | else() 24 | set(SOURCES ${SOURCES} 25 | freetype/freetype_fallback.cpp 26 | ) 27 | endif() 28 | -------------------------------------------------------------------------------- /src/openexr/openexr_fallback.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace vsgXchange; 4 | 5 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 6 | // 7 | // openEXR ReaderWriter fallback 8 | // 9 | openexr::openexr() 10 | { 11 | } 12 | 13 | vsg::ref_ptr openexr::read(const vsg::Path&, vsg::ref_ptr) const 14 | { 15 | return {}; 16 | } 17 | 18 | vsg::ref_ptr openexr::read(std::istream&, vsg::ref_ptr) const 19 | { 20 | return {}; 21 | } 22 | 23 | vsg::ref_ptr openexr::read(const uint8_t*, size_t, vsg::ref_ptr) const 24 | { 25 | return {}; 26 | } 27 | 28 | bool openexr::write(const vsg::Object*, const vsg::Path&, vsg::ref_ptr) const 29 | { 30 | return false; 31 | } 32 | 33 | bool openexr::write(const vsg::Object*, std::ostream&, vsg::ref_ptr) const 34 | { 35 | return false; 36 | } 37 | 38 | bool openexr::getFeatures(Features&) const 39 | { 40 | return false; 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | cmake_uninstall.cmake 3 | 4 | lib/ 5 | bin/ 6 | 7 | # Autogenerated files 8 | include/vsgXchange/Version.h 9 | 10 | *.pc 11 | *.conf 12 | *.backup 13 | CMakeCache.txt 14 | CMakeFiles 15 | CMakeScripts 16 | Makefile 17 | cmake_install.cmake 18 | install_manifest.txt 19 | CMakeDoxyfile.in 20 | CMakeDoxygenDefaults.cmake 21 | Doxyfile.docs 22 | vsgXchangeConfig.cmake 23 | vsgXchangeConfigVersion.cmake 24 | Doxyfile.docs-vsgXchange 25 | 26 | html/ 27 | 28 | 29 | # Compiled Object files 30 | *.slo 31 | *.lo 32 | *.o 33 | *.obj 34 | 35 | # Precompiled Headers 36 | *.gch 37 | *.pch 38 | 39 | # Compiled Dynamic libraries 40 | *.so 41 | *.dylib 42 | *.dll 43 | 44 | # Fortran module files 45 | *.mod 46 | 47 | # Compiled Static libraries 48 | *.lai 49 | *.la 50 | *.a 51 | *.lib 52 | 53 | # Executables 54 | *.exe 55 | *.out 56 | *.app 57 | 58 | # Visual Studio files 59 | *.sln 60 | *.vcxproj 61 | *.vcxproj.filters 62 | *.vcxproj.user 63 | .vs/ 64 | x64/ 65 | src/vsg/vsg.dir/ 66 | *.pdb 67 | *.tlog 68 | *.log 69 | 70 | # Xcode 71 | DerivedData/ 72 | *.build 73 | *.xcodeproj 74 | 75 | # Gradle 76 | .gradle/ 77 | .idea/ 78 | .externalNativeBuild/ 79 | *.iml 80 | build/ 81 | local.properties 82 | 83 | -------------------------------------------------------------------------------- /src/assimp/build_vars.cmake: -------------------------------------------------------------------------------- 1 | # add assimp if available 2 | find_package(assimp QUIET) 3 | 4 | if(assimp_FOUND) 5 | if (${assimp_VERSION} VERSION_GREATER_EQUAL "5.1") 6 | OPTION(vsgXchange_assimp "Optional Assimp support provided" ON) 7 | endif() 8 | endif() 9 | 10 | if (${vsgXchange_assimp}) 11 | 12 | string(REPLACE "." ";" ASSIMP_VERSION_LIST ${assimp_VERSION}) 13 | list(GET ASSIMP_VERSION_LIST 0 ASSIMP_VERSION_MAJOR) 14 | list(GET ASSIMP_VERSION_LIST 1 ASSIMP_VERSION_MINOR) 15 | list(GET ASSIMP_VERSION_LIST 2 ASSIMP_VERSION_PATCH) 16 | 17 | set(EXTRA_DEFINES ${EXTRA_DEFINES} "ASSIMP_VERSION_MAJOR=${ASSIMP_VERSION_MAJOR}" "ASSIMP_VERSION_MINOR=${ASSIMP_VERSION_MINOR}" "ASSIMP_VERSION_PATCH=${ASSIMP_VERSION_PATCH}" ) 18 | 19 | set(SOURCES ${SOURCES} 20 | assimp/assimp.cpp 21 | assimp/SceneConverter.cpp 22 | ) 23 | set(EXTRA_INCLUDES ${EXTRA_INCLUDES} ${assimp_INCLUDE_DIRS}) 24 | set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} assimp::assimp) 25 | if(NOT BUILD_SHARED_LIBS) 26 | set(FIND_DEPENDENCY ${FIND_DEPENDENCY} "find_dependency(assimp)") 27 | endif() 28 | else() 29 | set(SOURCES ${SOURCES} 30 | assimp/assimp_fallback.cpp 31 | ) 32 | endif() 33 | -------------------------------------------------------------------------------- /src/images/images.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | using namespace vsgXchange; 16 | 17 | images::images() 18 | { 19 | add(stbi::create()); 20 | add(dds::create()); 21 | add(ktx::create()); 22 | } 23 | -------------------------------------------------------------------------------- /src/models/models.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | using namespace vsgXchange; 17 | 18 | models::models() 19 | { 20 | add(gltf::create()); 21 | 22 | #ifdef vsgXchange_assimp 23 | add(assimp::create()); 24 | #endif 25 | 26 | #ifdef vsgXchange_OSG 27 | add(OSG::create()); 28 | #endif 29 | } 30 | -------------------------------------------------------------------------------- /include/vsgXchange/Export.h: -------------------------------------------------------------------------------- 1 | #ifndef VSGXCHANGE_EXPORT_H 2 | #define VSGXCHANGE_EXPORT_H 3 | 4 | /* 5 | 6 | Copyright(c) 2018 Robert Osfield 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 13 | 14 | */ 15 | 16 | #if (defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)) 17 | # if defined(vsgXchange_EXPORTS) 18 | # define VSGXCHANGE_DECLSPEC __declspec(dllexport) 19 | # elif defined(VSGXCHANGE_SHARED_LIBRARY) 20 | # define VSGXCHANGE_DECLSPEC __declspec(dllimport) 21 | # else 22 | # define VSGXCHANGE_DECLSPEC 23 | # endif 24 | #else 25 | # define VSGXCHANGE_DECLSPEC 26 | #endif 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/curl/curl_fallback.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | using namespace vsgXchange; 16 | 17 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 18 | // 19 | // curl ReaderWriter fallback 20 | // 21 | class curl::Implementation 22 | { 23 | }; 24 | curl::curl() : 25 | _implementation(nullptr) 26 | { 27 | } 28 | curl::~curl() 29 | { 30 | } 31 | vsg::ref_ptr curl::read(const vsg::Path&, vsg::ref_ptr) const 32 | { 33 | return {}; 34 | } 35 | bool curl::getFeatures(Features&) const 36 | { 37 | return false; 38 | } 39 | -------------------------------------------------------------------------------- /include/vsgXchange/cpp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 5 | Copyright(c) 2021 Robert Osfield 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | namespace vsgXchange 32 | { 33 | 34 | class VSGXCHANGE_DECLSPEC cpp : public vsg::Inherit 35 | { 36 | public: 37 | cpp(); 38 | 39 | bool write(const vsg::Object* object, const vsg::Path& filename, vsg::ref_ptr options = {}) const override; 40 | 41 | bool getFeatures(Features& features) const override; 42 | 43 | protected: 44 | void write(std::ostream& out, const std::string& str) const; 45 | }; 46 | 47 | } // namespace vsgXchange 48 | 49 | EVSG_type_name(vsgXchange::cpp); 50 | -------------------------------------------------------------------------------- /src/freetype/freetype_fallback.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2020 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | using namespace vsgXchange; 16 | 17 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 18 | // 19 | // freetype ReaderWriter fallback 20 | // 21 | class freetype::Implementation 22 | { 23 | }; 24 | freetype::freetype() : 25 | _implementation(nullptr) 26 | { 27 | } 28 | freetype::~freetype(){}; 29 | vsg::ref_ptr freetype::read(const vsg::Path&, vsg::ref_ptr) const 30 | { 31 | return {}; 32 | } 33 | bool freetype::getFeatures(Features&) const 34 | { 35 | return false; 36 | } 37 | bool freetype::readOptions(vsg::Options&, vsg::CommandLine&) const 38 | { 39 | return false; 40 | } 41 | -------------------------------------------------------------------------------- /include/vsgXchange/all.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 5 | Copyright(c) 2021 Robert Osfield 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | namespace vsgXchange 30 | { 31 | /// initialize any statics, such as registering all the ReaderWriters with vsg::ObjectFactory::instance(), 32 | /// so that any serialization that includes vsgXchange ReaderWriters will be able to load them. 33 | extern VSGXCHANGE_DECLSPEC void init(); 34 | 35 | /// ReaderWriter that has all the ReaderWriter implementations that vsgXchange provides. 36 | class VSGXCHANGE_DECLSPEC all : public vsg::Inherit 37 | { 38 | public: 39 | all(); 40 | }; 41 | } // namespace vsgXchange 42 | 43 | EVSG_type_name(vsgXchange::all); 44 | -------------------------------------------------------------------------------- /src/all/Version.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2018 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | extern "C" 16 | { 17 | 18 | VsgVersion vsgXchangeGetVersion() 19 | { 20 | VsgVersion version; 21 | version.major = VSGXCHANGE_VERSION_MAJOR; 22 | version.minor = VSGXCHANGE_VERSION_MINOR; 23 | version.patch = VSGXCHANGE_VERSION_PATCH; 24 | version.soversion = VSGXCHANGE_SOVERSION; 25 | return version; 26 | } 27 | 28 | const char* vsgXchangeGetVersionString() 29 | { 30 | return VSGXCHANGE_VERSION_STRING; 31 | } 32 | 33 | const char* vsgXchangeGetSOVersionString() 34 | { 35 | return VSGXCHANGE_SOVERSION_STRING; 36 | } 37 | 38 | int vsgXchangeBuiltAsSharedLibrary() 39 | { 40 | #ifdef vsgXchange_EXPORTS 41 | return 1; 42 | #else 43 | return 0; 44 | #endif 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/ktx/ktx_fallback.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2025 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | using namespace vsgXchange; 16 | 17 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 18 | // 19 | // ktx ReaderWriter fallback 20 | // 21 | ktx::ktx() : 22 | _implementation(nullptr) 23 | { 24 | } 25 | 26 | ktx::~ktx() 27 | { 28 | } 29 | 30 | vsg::ref_ptr ktx::read(const vsg::Path&, vsg::ref_ptr) const 31 | { 32 | return {}; 33 | } 34 | 35 | vsg::ref_ptr ktx::read(std::istream&, vsg::ref_ptr) const 36 | { 37 | return {}; 38 | } 39 | 40 | vsg::ref_ptr ktx::read(const uint8_t*, size_t, vsg::ref_ptr) const 41 | { 42 | return {}; 43 | } 44 | 45 | bool ktx::getFeatures(Features&) const 46 | { 47 | return false; 48 | } 49 | -------------------------------------------------------------------------------- /src/gdal/GDAL_fallback.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 16 | // 17 | // GDAL ReaderWriter fallback 18 | // 19 | class vsgXchange::GDAL::Implementation 20 | { 21 | }; 22 | vsgXchange::GDAL::GDAL() : 23 | _implementation(nullptr) 24 | { 25 | } 26 | vsgXchange::GDAL::~GDAL() 27 | { 28 | } 29 | vsg::ref_ptr vsgXchange::GDAL::read(const vsg::Path&, vsg::ref_ptr) const 30 | { 31 | return {}; 32 | } 33 | vsg::ref_ptr vsgXchange::GDAL::read(std::istream&, vsg::ref_ptr) const 34 | { 35 | return {}; 36 | } 37 | vsg::ref_ptr vsgXchange::GDAL::read(const uint8_t*, size_t, vsg::ref_ptr) const 38 | { 39 | return {}; 40 | } 41 | bool vsgXchange::GDAL::getFeatures(Features&) const 42 | { 43 | return false; 44 | } 45 | -------------------------------------------------------------------------------- /src/assimp/assimp_fallback.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | using namespace vsgXchange; 16 | 17 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 18 | // 19 | // assimp ReaderWriter fallback 20 | // 21 | class assimp::Implementation 22 | { 23 | }; 24 | assimp::assimp() : 25 | _implementation(nullptr) 26 | { 27 | } 28 | assimp::~assimp() 29 | { 30 | } 31 | vsg::ref_ptr assimp::read(const vsg::Path&, vsg::ref_ptr) const 32 | { 33 | return {}; 34 | } 35 | vsg::ref_ptr assimp::read(std::istream&, vsg::ref_ptr) const 36 | { 37 | return {}; 38 | } 39 | vsg::ref_ptr assimp::read(const uint8_t*, size_t, vsg::ref_ptr) const 40 | { 41 | return {}; 42 | } 43 | bool assimp::getFeatures(Features&) const 44 | { 45 | return false; 46 | } 47 | bool assimp::readOptions(vsg::Options&, vsg::CommandLine&) const 48 | { 49 | return false; 50 | } 51 | -------------------------------------------------------------------------------- /include/vsgXchange/bin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 5 | Copyright(c) 2025 Robert Osfield 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shimages be included in images 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace vsgXchange 31 | { 32 | 33 | /// .bin ReaderWriter 34 | class VSGXCHANGE_DECLSPEC bin : public vsg::Inherit 35 | { 36 | public: 37 | bin(); 38 | 39 | vsg::ref_ptr read(const vsg::Path&, vsg::ref_ptr) const override; 40 | vsg::ref_ptr read(std::istream&, vsg::ref_ptr) const override; 41 | vsg::ref_ptr read(const uint8_t* ptr, size_t size, vsg::ref_ptr options = {}) const override; 42 | 43 | vsg::ref_ptr _read(std::istream&) const; 44 | 45 | bool supportedExtension(const vsg::Path& ext) const; 46 | 47 | bool getFeatures(Features& features) const override; 48 | }; 49 | 50 | } // namespace vsgXchange 51 | 52 | EVSG_type_name(vsgXchange::bin) 53 | -------------------------------------------------------------------------------- /include/vsgXchange/freetype.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 5 | Copyright(c) 2021 Robert Osfield 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | namespace vsgXchange 32 | { 33 | 34 | class VSGXCHANGE_DECLSPEC freetype : public vsg::Inherit 35 | { 36 | public: 37 | freetype(); 38 | vsg::ref_ptr read(const vsg::Path& filename, vsg::ref_ptr options = {}) const override; 39 | 40 | bool getFeatures(Features& features) const override; 41 | 42 | // vsg::Options::setValue(str, value) supported options: 43 | static constexpr const char* texel_margin_ratio = "texel_margin_ratio"; 44 | static constexpr const char* quad_margin_ratio = "quad_margin_ratio"; 45 | 46 | bool readOptions(vsg::Options& options, vsg::CommandLine& arguments) const override; 47 | 48 | protected: 49 | ~freetype(); 50 | 51 | class Implementation; 52 | Implementation* _implementation; 53 | }; 54 | 55 | } // namespace vsgXchange 56 | 57 | EVSG_type_name(vsgXchange::freetype); 58 | -------------------------------------------------------------------------------- /include/vsgXchange/curl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 5 | Copyright(c) 2021 Robert Osfield 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | namespace vsgXchange 32 | { 33 | 34 | /// optional curl ReaderWriter. 35 | /// depends upon libcurl for reading data from http and https. 36 | class VSGXCHANGE_DECLSPEC curl : public vsg::Inherit 37 | { 38 | public: 39 | curl(); 40 | vsg::ref_ptr read(const vsg::Path& filename, vsg::ref_ptr options = {}) const override; 41 | 42 | bool getFeatures(Features& features) const override; 43 | 44 | // vsg::Options::setValue(str, value) supported options: 45 | static constexpr const char* SSL_OPTIONS = "CURLOPT_SSL_OPTIONS"; /// uint32_t 46 | 47 | /// specify whether libcurl should be initialized and cleaned up by vsgXchange::curl. 48 | static bool s_do_curl_global_init_and_cleanup; // defaults to true 49 | 50 | protected: 51 | ~curl(); 52 | 53 | class Implementation; 54 | mutable std::mutex _mutex; 55 | mutable Implementation* _implementation; 56 | }; 57 | 58 | } // namespace vsgXchange 59 | 60 | EVSG_type_name(vsgXchange::curl); 61 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(vsgXchange 4 | VERSION 1.1.9 5 | DESCRIPTION "VulkanSceneGraph 3rd party data integration library" 6 | LANGUAGES CXX C 7 | ) 8 | set(VSGXCHANGE_SOVERSION 2) 9 | SET(VSGXCHANGE_RELEASE_CANDIDATE 0) 10 | 11 | set(VSGXCHANGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "Root source directory of vsgXchange.") 12 | set(VSGXCHANGE_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE INTERNAL "Root binary directory of vsgXchange.") 13 | 14 | # Find Vulkan and the VSG 15 | if (VULKAN_SDK) 16 | set(ENV{VULKAN_SDK} ${VULKAN_SDK}) 17 | endif() 18 | 19 | set(VSG_MIN_VERSION 1.1.13) 20 | find_package(vsg ${VSG_MIN_VERSION}) 21 | 22 | vsg_setup_dir_vars() 23 | vsg_setup_build_vars() 24 | 25 | # find optional osg2vsg package for loading image/nodes using OpenSceneGraph 26 | find_package(osg2vsg QUIET) 27 | if(osg2vsg_FOUND) 28 | OPTION(vsgXchange_OSG "OSG support provided" ON) 29 | endif() 30 | 31 | if (vsgXchange_OSG) 32 | set(EXTRA_LIBRARIES ${EXTRA_LIBRARIES} osg2vsg::osg2vsg) 33 | if(NOT BUILD_SHARED_LIBS) 34 | set(FIND_DEPENDENCY ${FIND_DEPENDENCY} "find_dependency(osg2vsg)") 35 | endif() 36 | endif() 37 | 38 | # for generated cmake support files 39 | set(FIND_DEPENDENCY ${FIND_DEPENDENCY} "find_dependency(vsg ${VSG_MIN_VERSION} REQUIRED)") 40 | 41 | vsg_add_target_clang_format( 42 | FILES 43 | ${VSGXCHANGE_SOURCE_DIR}/include/*/*.h 44 | ${VSGXCHANGE_SOURCE_DIR}/src/*/*.h 45 | ${VSGXCHANGE_SOURCE_DIR}/src/*/*.cpp 46 | ${VSGXCHANGE_SOURCE_DIR}/applications/*/*.h 47 | ${VSGXCHANGE_SOURCE_DIR}/applications/*/*.cpp 48 | EXCLUDES 49 | ${VSGXCHANGE_SOURCE_DIR}/src/stbi/stb_image.h 50 | ${VSGXCHANGE_SOURCE_DIR}/src/stbi/stb_image_write.h 51 | ${VSGXCHANGE_SOURCE_DIR}/src/dds/tinyddsloader.h 52 | ) 53 | vsg_add_target_clobber() 54 | vsg_add_target_cppcheck( 55 | FILES 56 | ${VSGXCHANGE_SOURCE_DIR}/include/*/*.h 57 | ${VSGXCHANGE_SOURCE_DIR}/src/*/*.h 58 | ${VSGXCHANGE_SOURCE_DIR}/src/*/*.cpp 59 | ${VSGXCHANGE_SOURCE_DIR}/applications/*/*.h 60 | ${VSGXCHANGE_SOURCE_DIR}/applications/*/*.cpp 61 | ) 62 | vsg_add_target_docs( 63 | FILES 64 | ${VSGXCHANGE_SOURCE_DIR}/include 65 | ) 66 | vsg_add_target_uninstall() 67 | 68 | # only provide custom targets if not building as a submodule/FetchContent 69 | if (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR}) 70 | 71 | vsg_add_option_maintainer( 72 | PREFIX v 73 | RCLEVEL ${VSGXCHANGE_RELEASE_CANDIDATE} 74 | ) 75 | 76 | endif() 77 | 78 | # source directory for main vsgXchange library 79 | add_subdirectory(src) 80 | add_subdirectory(applications/vsgconv) 81 | 82 | vsg_add_feature_summary() 83 | -------------------------------------------------------------------------------- /src/all/Version.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" 20 | { 21 | #endif 22 | 23 | #define VSGXCHANGE_VERSION_MAJOR @VSGXCHANGE_VERSION_MAJOR@ 24 | #define VSGXCHANGE_VERSION_MINOR @VSGXCHANGE_VERSION_MINOR@ 25 | #define VSGXCHANGE_VERSION_PATCH @VSGXCHANGE_VERSION_PATCH@ 26 | #define VSGXCHANGE_SOVERSION @VSGXCHANGE_SOVERSION@ 27 | 28 | #define VSGXCHANGE_VERSION_STRING "@VSGXCHANGE_VERSION_MAJOR@.@VSGXCHANGE_VERSION_MINOR@.@VSGXCHANGE_VERSION_PATCH@" 29 | #define VSGXCHANGE_SOVERSION_STRING "@VSGXCHANGE_SOVERSION@" 30 | 31 | extern VSGXCHANGE_DECLSPEC struct VsgVersion vsgXchangeGetVersion(); 32 | extern VSGXCHANGE_DECLSPEC const char* vsgXchangeGetVersionString(); 33 | extern VSGXCHANGE_DECLSPEC const char* vsgXchangeGetSOVersionString(); 34 | 35 | /// return 0 if the linked vsgXchange was built as static library (default), 1 if the linked vsgXchange library was built as shared/dynamic library. 36 | /// When building against a shared library, to ensure the correct selection of VSGXCHANGE_DECLSPEC (provided in vsgXchange/Export.h) one must compile with the define VSGXCHANGE_SHARED_LIBRARY 37 | extern VSGXCHANGE_DECLSPEC int vsgXchangeBuiltAsSharedLibrary(); 38 | 39 | /// standard Features 40 | #define vsgXchange_all 41 | #define vsgXchange_images 42 | #define vsgXchange_models 43 | #define vsgXchange_stbi 44 | #define vsgXchange_dds 45 | #define vsgXchange_ktx 46 | #define vsgXchange_spv 47 | #define vsgXchange_cpp 48 | #define vsgXchange_gltf 49 | #define vsgXchange_3DTiles 50 | 51 | /// optional Features 52 | #cmakedefine vsgXchange_curl 53 | #cmakedefine vsgXchange_draco 54 | #cmakedefine vsgXchange_openexr 55 | #cmakedefine vsgXchange_freetype 56 | #cmakedefine vsgXchange_assimp 57 | #cmakedefine vsgXchange_GDAL 58 | #cmakedefine vsgXchange_OSG 59 | 60 | #ifdef __cplusplus 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /src/bin/bin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2025 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | //#include 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | using namespace vsgXchange; 25 | 26 | bin::bin() 27 | { 28 | } 29 | 30 | vsg::ref_ptr bin::_read(std::istream& fin) const 31 | { 32 | fin.seekg(0, fin.end); 33 | size_t fileSize = fin.tellg(); 34 | 35 | if (fileSize == 0) return {}; 36 | 37 | auto data = vsg::ubyteArray::create(fileSize); 38 | 39 | fin.seekg(0); 40 | fin.read(reinterpret_cast(data->dataPointer()), fileSize); 41 | 42 | return data; 43 | } 44 | 45 | vsg::ref_ptr bin::read(const vsg::Path& filename, vsg::ref_ptr options) const 46 | { 47 | vsg::Path ext = (options && options->extensionHint) ? options->extensionHint : vsg::lowerCaseFileExtension(filename); 48 | if (!supportedExtension(ext)) return {}; 49 | 50 | vsg::Path filenameToUse = vsg::findFile(filename, options); 51 | if (!filenameToUse) return {}; 52 | 53 | std::ifstream fin(filenameToUse, std::ios::ate | std::ios::binary); 54 | return _read(fin); 55 | } 56 | 57 | vsg::ref_ptr bin::read(std::istream& fin, vsg::ref_ptr options) const 58 | { 59 | if (!options || !options->extensionHint) return {}; 60 | if (!supportedExtension(options->extensionHint)) return {}; 61 | 62 | return _read(fin); 63 | } 64 | 65 | vsg::ref_ptr bin::read(const uint8_t* ptr, size_t size, vsg::ref_ptr options) const 66 | { 67 | if (!options || !options->extensionHint) return {}; 68 | if (!supportedExtension(options->extensionHint)) return {}; 69 | 70 | vsg::mem_stream fin(ptr, size); 71 | return _read(fin); 72 | } 73 | 74 | bool bin::supportedExtension(const vsg::Path& ext) const 75 | { 76 | return (ext == ".bin"); 77 | } 78 | 79 | bool bin::getFeatures(Features& features) const 80 | { 81 | vsg::ReaderWriter::FeatureMask supported_features = static_cast(vsg::ReaderWriter::READ_FILENAME | vsg::ReaderWriter::READ_ISTREAM | vsg::ReaderWriter::READ_MEMORY); 82 | features.extensionFeatureMap[".bin"] = supported_features; 83 | 84 | return true; 85 | } 86 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # vars used to enable subdirectories to extend the build of the vsgXchange library in a loosely coupled way 3 | set(EXTRA_DEFINES) 4 | set(EXTRA_INCLUDES) 5 | 6 | SET(HEADER_PATH ${VSGXCHANGE_SOURCE_DIR}/include/vsgXchange) 7 | 8 | set(HEADERS 9 | ${VSGXCHANGE_VERSION_HEADER} 10 | ${HEADER_PATH}/Export.h 11 | ${HEADER_PATH}/all.h 12 | ${HEADER_PATH}/cpp.h 13 | ${HEADER_PATH}/freetype.h 14 | ${HEADER_PATH}/images.h 15 | ${HEADER_PATH}/models.h 16 | ${HEADER_PATH}/gltf.h 17 | ${HEADER_PATH}/3DTiles.h 18 | ) 19 | 20 | set(SOURCES 21 | all/Version.cpp 22 | all/all.cpp 23 | cpp/cpp.cpp 24 | stbi/stbi.cpp 25 | dds/dds.cpp 26 | images/images.cpp 27 | bin/bin.cpp 28 | ) 29 | 30 | # add gltf 31 | include(gltf/build_vars.cmake) 32 | 33 | # add 3D Tiles 34 | include(3DTiles/build_vars.cmake) 35 | 36 | # add freetype if available 37 | include(freetype/build_vars.cmake) 38 | 39 | # add assimp if available 40 | include(assimp/build_vars.cmake) 41 | 42 | # add optional ktx 43 | include(ktx/build_vars.cmake) 44 | 45 | # add optional GDAL component 46 | include(gdal/build_vars.cmake) 47 | 48 | # add optional CURL component 49 | include(curl/build_vars.cmake) 50 | 51 | # add optional OpenEXR component 52 | include(openexr/build_vars.cmake) 53 | 54 | # create the version header 55 | set(VSGXCHANGE_VERSION_HEADER "${VSGXCHANGE_BINARY_DIR}/include/vsgXchange/Version.h") 56 | configure_file("${VSGXCHANGE_SOURCE_DIR}/src/all/Version.h.in" "${VSGXCHANGE_VERSION_HEADER}") 57 | 58 | 59 | # create the vsgXchange library 60 | add_library(vsgXchange ${HEADERS} ${SOURCES}) 61 | 62 | # add definitions to enable building vsgXchange as part of submodule 63 | add_library(vsgXchange::vsgXchange ALIAS vsgXchange) 64 | set(vsgXchange_FOUND TRUE CACHE INTERNAL "vsgXchange found.") 65 | set(CMAKE_DISABLE_FIND_PACKAGE_vsgXchange TRUE CACHE INTERNAL "Disable find_package(vsgXchange) as it's not necessary.") 66 | 67 | 68 | set_property(TARGET vsgXchange PROPERTY VERSION ${VSGXCHANGE_VERSION_MAJOR}.${VSGXCHANGE_VERSION_MINOR}.${VSGXCHANGE_VERSION_PATCH}) 69 | set_property(TARGET vsgXchange PROPERTY SOVERSION ${VSGXCHANGE_SOVERSION}) 70 | set_property(TARGET vsgXchange PROPERTY POSITION_INDEPENDENT_CODE ON) 71 | 72 | target_compile_definitions(vsgXchange PRIVATE ${EXTRA_DEFINES}) 73 | 74 | target_include_directories(vsgXchange 75 | PUBLIC 76 | $ 77 | $ 78 | $ 79 | PRIVATE 80 | ${EXTRA_INCLUDES} 81 | ) 82 | 83 | target_link_libraries(vsgXchange 84 | PUBLIC 85 | vsg::vsg 86 | PRIVATE 87 | ${EXTRA_LIBRARIES} 88 | ) 89 | 90 | install(TARGETS vsgXchange ${INSTALL_TARGETS_DEFAULT_FLAGS}) 91 | 92 | if (BUILD_SHARED_LIBS) 93 | target_compile_definitions(vsgXchange INTERFACE VSGXCHANGE_SHARED_LIBRARY) 94 | endif() 95 | 96 | install(DIRECTORY ${VSGXCHANGE_SOURCE_DIR}/include/vsgXchange DESTINATION include) 97 | if (NOT(${VSGXCHANGE_BINARY_DIR} STREQUAL ${VSGXCHANGE_SOURCE_DIR})) 98 | install(DIRECTORY ${VSGXCHANGE_BINARY_DIR}/include/vsgXchange DESTINATION include) 99 | endif() 100 | 101 | string(REPLACE ";" "\n" FIND_DEPENDENCY_OUT "${FIND_DEPENDENCY}") 102 | vsg_add_cmake_support_files( 103 | CONFIG_TEMPLATE 104 | vsgXchangeConfig.cmake.in 105 | ) 106 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: true 13 | AllowShortCaseLabelsOnASingleLine: true 14 | AllowShortFunctionsOnASingleLine: InlineOnly 15 | AllowShortIfStatementsOnASingleLine: true 16 | AllowShortLoopsOnASingleLine: true 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: false 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: true 25 | AfterControlStatement: true 26 | AfterEnum: true 27 | AfterFunction: true 28 | AfterNamespace: true 29 | AfterObjCDeclaration: true 30 | AfterStruct: true 31 | AfterUnion: true 32 | AfterExternBlock: true 33 | BeforeCatch: true 34 | BeforeElse: true 35 | IndentBraces: false 36 | SplitEmptyFunction: true 37 | SplitEmptyRecord: true 38 | SplitEmptyNamespace: true 39 | BreakBeforeBinaryOperators: None 40 | BreakBeforeBraces: Custom 41 | BreakBeforeInheritanceComma: false 42 | BreakBeforeTernaryOperators: true 43 | BreakConstructorInitializersBeforeComma: true 44 | BreakConstructorInitializers: AfterColon 45 | BreakAfterJavaFieldAnnotations: false 46 | BreakStringLiterals: true 47 | ColumnLimit: 0 48 | CommentPragmas: '^ IWYU pragma:' 49 | CompactNamespaces: false 50 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 51 | ConstructorInitializerIndentWidth: 4 52 | ContinuationIndentWidth: 4 53 | Cpp11BracedListStyle: true 54 | DerivePointerAlignment: false 55 | DisableFormat: false 56 | ExperimentalAutoDetectBinPacking: false 57 | FixNamespaceComments: true 58 | ForEachMacros: 59 | - foreach 60 | - Q_FOREACH 61 | - BOOST_FOREACH 62 | IncludeBlocks: Preserve 63 | IncludeCategories: 64 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 65 | Priority: 2 66 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 67 | Priority: 3 68 | - Regex: '.*' 69 | Priority: 1 70 | IncludeIsMainRegex: '(Test)?$' 71 | IndentCaseLabels: false 72 | IndentPPDirectives: AfterHash 73 | IndentWidth: 4 74 | IndentWrappedFunctionNames: false 75 | JavaScriptQuotes: Leave 76 | JavaScriptWrapImports: true 77 | KeepEmptyLinesAtTheStartOfBlocks: true 78 | MacroBlockBegin: '' 79 | MacroBlockEnd: '' 80 | MaxEmptyLinesToKeep: 1 81 | NamespaceIndentation: All 82 | ObjCBlockIndentWidth: 4 83 | ObjCSpaceAfterProperty: false 84 | ObjCSpaceBeforeProtocolList: true 85 | PenaltyBreakAssignment: 2 86 | PenaltyBreakBeforeFirstCallParameter: 19 87 | PenaltyBreakComment: 300 88 | PenaltyBreakFirstLessLess: 120 89 | PenaltyBreakString: 1000 90 | PenaltyExcessCharacter: 1000000 91 | PenaltyReturnTypeOnItsOwnLine: 60 92 | PointerAlignment: Left 93 | ReflowComments: false 94 | SortIncludes: true 95 | SortUsingDeclarations: true 96 | SpaceAfterCStyleCast: false 97 | SpaceAfterTemplateKeyword: false 98 | SpaceBeforeAssignmentOperators: true 99 | SpaceBeforeParens: ControlStatements 100 | SpaceInEmptyParentheses: false 101 | SpacesBeforeTrailingComments: 1 102 | SpacesInAngles: false 103 | SpacesInContainerLiterals: true 104 | SpacesInCStyleCastParentheses: false 105 | SpacesInParentheses: false 106 | SpacesInSquareBrackets: false 107 | Standard: Cpp11 108 | TabWidth: 8 109 | UseTab: Never 110 | ... 111 | 112 | -------------------------------------------------------------------------------- /include/vsgXchange/models.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 5 | Copyright(c) 2021 Robert Osfield 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shimages be included in images 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | namespace vsgXchange 32 | { 33 | /// Composite ReaderWriter that holds the used 3rd party model format loaders. 34 | class VSGXCHANGE_DECLSPEC models : public vsg::Inherit 35 | { 36 | public: 37 | models(); 38 | }; 39 | 40 | /// optional assimp ReaderWriter 41 | class VSGXCHANGE_DECLSPEC assimp : public vsg::Inherit 42 | { 43 | public: 44 | assimp(); 45 | vsg::ref_ptr read(const vsg::Path&, vsg::ref_ptr) const override; 46 | vsg::ref_ptr read(std::istream&, vsg::ref_ptr) const override; 47 | vsg::ref_ptr read(const uint8_t* ptr, size_t size, vsg::ref_ptr options = {}) const override; 48 | 49 | bool getFeatures(Features& features) const override; 50 | 51 | // vsg::Options::setValue(str, value) supported options: 52 | static constexpr const char* generate_smooth_normals = "generate_smooth_normals"; 53 | static constexpr const char* generate_sharp_normals = "generate_sharp_normals"; 54 | static constexpr const char* crease_angle = "crease_angle"; /// float 55 | static constexpr const char* two_sided = "two_sided"; /// bool 56 | static constexpr const char* discard_empty_nodes = "discard_empty_nodes"; /// bool 57 | static constexpr const char* print_assimp = "print_assimp"; /// int 58 | static constexpr const char* external_textures = "external_textures"; /// bool 59 | static constexpr const char* external_texture_format = "external_texture_format"; /// TextureFormat enum 60 | static constexpr const char* culling = "culling"; /// bool, insert cull nodes, defaults to true 61 | static constexpr const char* vertex_color_space = "vertex_color_space"; /// CoordinateSpace {sRGB or LINEAR} to assume when reading vertex colors 62 | static constexpr const char* material_color_space = "material_color_space"; /// CoordinateSpace {sRGB or LINEAR} to assume when reading materials colors 63 | 64 | bool readOptions(vsg::Options& options, vsg::CommandLine& arguments) const override; 65 | 66 | protected: 67 | ~assimp(); 68 | 69 | class Implementation; 70 | Implementation* _implementation; 71 | }; 72 | 73 | } // namespace vsgXchange 74 | 75 | EVSG_type_name(vsgXchange::models); 76 | EVSG_type_name(vsgXchange::assimp); 77 | -------------------------------------------------------------------------------- /src/all/all.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #ifdef vsgXchange_OSG 32 | # include 33 | #endif 34 | 35 | using namespace vsgXchange; 36 | 37 | void vsgXchange::init() 38 | { 39 | static bool s_vsgXchange_initialized = false; 40 | if (s_vsgXchange_initialized) return; 41 | s_vsgXchange_initialized = true; 42 | 43 | vsg::debug("vsgXchange::init()"); 44 | 45 | vsg::ObjectFactory::instance()->add(); 46 | vsg::ObjectFactory::instance()->add(); 47 | 48 | vsg::ObjectFactory::instance()->add(); 49 | 50 | vsg::ObjectFactory::instance()->add(); 51 | vsg::ObjectFactory::instance()->add(); 52 | vsg::ObjectFactory::instance()->add(); 53 | 54 | vsg::ObjectFactory::instance()->add(); 55 | vsg::ObjectFactory::instance()->add(); 56 | vsg::ObjectFactory::instance()->add(); 57 | 58 | vsg::ObjectFactory::instance()->add(); 59 | vsg::ObjectFactory::instance()->add(); 60 | vsg::ObjectFactory::instance()->add(); 61 | vsg::ObjectFactory::instance()->add(); 62 | // vsg::ObjectFactory::instance()->add(); 63 | } 64 | 65 | all::all() 66 | { 67 | // for convenience make sure the init() method is called 68 | vsgXchange::init(); 69 | 70 | #ifdef vsgXchange_curl 71 | add(curl::create()); 72 | #endif 73 | 74 | add(vsg::VSG::create()); 75 | add(vsg::spirv::create()); 76 | add(vsg::glsl::create()); 77 | 78 | add(bin::create()); 79 | add(gltf::create()); 80 | add(Tiles3D::create()); 81 | 82 | add(vsg::json::create()); 83 | 84 | add(cpp::create()); 85 | 86 | add(vsg::txt::create()); 87 | 88 | add(stbi::create()); 89 | add(dds::create()); 90 | 91 | #ifdef vsgXchange_ktx 92 | add(ktx::create()); 93 | #endif 94 | 95 | #ifdef vsgXchange_openexr 96 | add(openexr::create()); 97 | #endif 98 | 99 | #ifdef vsgXchange_freetype 100 | add(freetype::create()); 101 | #endif 102 | 103 | #ifdef vsgXchange_assimp 104 | add(assimp::create()); 105 | #endif 106 | 107 | #ifdef vsgXchange_GDAL 108 | add(GDAL::create()); 109 | #endif 110 | 111 | #ifdef vsgXchange_OSG 112 | add(osg2vsg::OSG::create()); 113 | #endif 114 | } 115 | -------------------------------------------------------------------------------- /src/gdal/meta_utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | */ 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | 31 | using namespace vsgXchange; 32 | 33 | bool vsgXchange::getEXIF_LatitudeLongitudeAlititude(GDALDataset& dataset, double& latitude, double& longitude, double& altitude) 34 | { 35 | auto metaData = dataset.GetMetadata(); 36 | if (!metaData) return false; 37 | 38 | auto match = [](const char* lhs, const char* rhs) -> const char* { 39 | auto len = std::strlen(rhs); 40 | if (strncmp(lhs, rhs, len) == 0) 41 | return lhs + len; 42 | else 43 | return nullptr; 44 | }; 45 | 46 | bool success = false; 47 | 48 | const char* value_str = nullptr; 49 | std::stringstream str; 50 | str.imbue(std::locale::classic()); 51 | 52 | for (auto ptr = metaData; *ptr != 0; ++ptr) 53 | { 54 | if (value_str = match(*ptr, "EXIF_GPSLatitude="); value_str) 55 | { 56 | str.clear(); 57 | str.str(value_str); 58 | str >> vsgXchange::dms_in_brackets(latitude); 59 | success = true; 60 | } 61 | else if (value_str = match(*ptr, "EXIF_GPSLongitude="); value_str) 62 | { 63 | str.clear(); 64 | str.str(value_str); 65 | str >> vsgXchange::dms_in_brackets(longitude); 66 | success = true; 67 | } 68 | else if (value_str = match(*ptr, "EXIF_GPSAltitude="); value_str) 69 | { 70 | str.clear(); 71 | str.str(value_str); 72 | str >> vsgXchange::dms_in_brackets(altitude); 73 | success = true; 74 | } 75 | } 76 | 77 | return success; 78 | } 79 | 80 | bool vsgXchange::getEXIF_LatitudeLongitudeAlititude(const vsg::Object& object, double& latitude, double& longitude, double& altitude) 81 | { 82 | bool success = false; 83 | 84 | std::string value_str; 85 | std::stringstream str; 86 | str.imbue(std::locale::classic()); 87 | 88 | if (object.getValue("EXIF_GPSLatitude", value_str)) 89 | { 90 | str.clear(); 91 | str.str(value_str); 92 | str >> vsgXchange::dms_in_brackets(latitude); 93 | vsg::info("vsgXchange::getEXIF_.. EXIF_GPSLatitude = ", value_str, " degrees = ", latitude); 94 | success = true; 95 | } 96 | if (object.getValue("EXIF_GPSLongitude", value_str)) 97 | { 98 | str.clear(); 99 | str.str(value_str); 100 | str >> vsgXchange::dms_in_brackets(longitude); 101 | vsg::info("vsgXchange::getEXIF_.. EXIF_GPSLongitude = ", value_str, " degrees = ", longitude); 102 | success = true; 103 | } 104 | if (object.getValue("EXIF_GPSAltitude", value_str)) 105 | { 106 | str.clear(); 107 | str.str(value_str); 108 | str >> vsgXchange::in_brackets(altitude); 109 | vsg::info("vsgXchange::getEXIF_.. EXIF_GPSAltitude = ", value_str, " altitude = ", altitude); 110 | success = true; 111 | } 112 | return success; 113 | } 114 | -------------------------------------------------------------------------------- /src/cpp/cpp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2018 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | using namespace vsgXchange; 22 | 23 | cpp::cpp() 24 | { 25 | } 26 | 27 | bool cpp::write(const vsg::Object* object, const vsg::Path& filename, vsg::ref_ptr options) const 28 | { 29 | auto ext = vsg::lowerCaseFileExtension(filename); 30 | if (ext != ".cpp") return false; 31 | 32 | std::cout << "cpp::write(" << object->className() << ", " << filename << ")" << std::endl; 33 | 34 | auto funcname = vsg::simpleFilename(filename); 35 | 36 | bool binary = options ? (options->extensionHint == ".vsgb") : false; 37 | 38 | auto local_options = vsg::Options::create(); 39 | local_options->extensionHint = binary ? ".vsgb" : ".vsgt"; 40 | 41 | // serialize object(s) to string 42 | std::ostringstream str; 43 | vsg::VSG io; 44 | io.write(object, str, local_options); 45 | std::string s = str.str(); 46 | 47 | std::ofstream fout(filename); 48 | fout << "#include \n"; 49 | fout << "#include \n"; 50 | fout << "static auto " << funcname << " = []() {\n"; 51 | 52 | if (binary || s.size() > 65535) 53 | { 54 | // long string has to be handled as a byte array as VisualStudio can't handle long strings. 55 | fout << "static const uint8_t data[] = {\n"; 56 | fout << uint32_t(uint8_t(s[0])); 57 | for (size_t i = 1; i < s.size(); ++i) 58 | { 59 | if ((i % 32) == 0) 60 | fout << ",\n"; 61 | else 62 | fout << ", "; 63 | fout << uint32_t(uint8_t(s[i])); 64 | } 65 | fout << " };\n"; 66 | //fout<<"vsg::mem_stream str(data, sizeof(data));\n"; 67 | fout << "vsg::VSG io;\n"; 68 | fout << "return io.read_cast<" << object->className() << ">(data, sizeof(data));\n"; 69 | } 70 | else 71 | { 72 | fout << "static const char str[] = \n"; 73 | write(fout, str.str()); 74 | fout << ";\n"; 75 | fout << "vsg::VSG io;\n"; 76 | fout << "return io.read_cast<" << object->className() << ">(reinterpret_cast(str), sizeof(str));\n"; 77 | } 78 | 79 | fout << "};\n"; 80 | fout.close(); 81 | 82 | return true; 83 | } 84 | 85 | void cpp::write(std::ostream& out, const std::string& str) const 86 | { 87 | std::size_t max_string_literal_length = 16360; 88 | if (str.size() > max_string_literal_length) 89 | { 90 | std::size_t n = 0; 91 | while ((n + max_string_literal_length) < str.size()) 92 | { 93 | auto pos_previous_end_of_line = str.find_last_of("\n", n + max_string_literal_length); 94 | if (pos_previous_end_of_line > n) 95 | { 96 | out << "R\"(" << str.substr(n, pos_previous_end_of_line + 1 - n) << ")\"\n"; 97 | n = pos_previous_end_of_line + 1; 98 | } 99 | else 100 | { 101 | out << "R\"(" << str.substr(n, max_string_literal_length) << ")\" "; 102 | n += max_string_literal_length; 103 | } 104 | } 105 | 106 | if (n < str.size()) 107 | { 108 | out << "R\"(" << str.substr(n, std::string::npos) << ")\""; 109 | } 110 | } 111 | else 112 | { 113 | out << "R\"(" << str << ")\""; 114 | } 115 | } 116 | 117 | bool cpp::getFeatures(Features& features) const 118 | { 119 | features.extensionFeatureMap[".cpp"] = vsg::ReaderWriter::WRITE_FILENAME; 120 | return true; 121 | } 122 | -------------------------------------------------------------------------------- /src/3DTiles/cmpt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2025 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | using namespace vsgXchange; 28 | 29 | vsg::ref_ptr Tiles3D::read_cmpt(std::istream& fin, vsg::ref_ptr options, const vsg::Path& filename) const 30 | { 31 | fin.seekg(0); 32 | 33 | // https://github.com/CesiumGS/3d-tiles/blob/main/specification/TileFormats/Composite/README.adoc 34 | struct Header 35 | { 36 | char magic[4] = {0, 0, 0, 0}; 37 | uint32_t version = 0; 38 | uint32_t byteLength = 0; 39 | uint32_t tilesLength = 0; 40 | }; 41 | 42 | struct InnerHeader 43 | { 44 | char magic[4] = {0, 0, 0, 0}; 45 | uint32_t version = 0; 46 | uint32_t byteLength = 0; 47 | }; 48 | 49 | Header header; 50 | fin.read(reinterpret_cast(&header), sizeof(Header)); 51 | 52 | if (!fin.good()) 53 | { 54 | vsg::warn("IO error reading cmpt file."); 55 | return {}; 56 | } 57 | 58 | if (strncmp(header.magic, "cmpt", 4) != 0) 59 | { 60 | vsg::warn("magic number not cmpt"); 61 | return {}; 62 | } 63 | 64 | uint32_t sizeOfTiles = header.byteLength - sizeof(Header); 65 | std::string binary; 66 | binary.resize(sizeOfTiles); 67 | fin.read(binary.data(), sizeOfTiles); 68 | if (!fin.good()) 69 | { 70 | vsg::warn("IO error reading cmpt file."); 71 | return {}; 72 | } 73 | 74 | auto group = vsg::Group::create(); 75 | std::list innerHeaders; 76 | uint32_t pos = 0; 77 | for (uint32_t i = 0; i < header.tilesLength; ++i) 78 | { 79 | InnerHeader* tile = reinterpret_cast(&binary[pos]); 80 | innerHeaders.push_back(*tile); 81 | 82 | vsg::mem_stream binary_fin(reinterpret_cast(&binary[pos]), tile->byteLength); 83 | pos += tile->byteLength; 84 | 85 | std::string ext = "."; 86 | for (int c = 0; c < 4; ++c) 87 | { 88 | if (tile->magic[c] != 0) 89 | ext.push_back(tile->magic[c]); 90 | else 91 | break; 92 | } 93 | 94 | auto opt = vsg::clone(options); 95 | opt->extensionHint = ext; 96 | 97 | #if 0 98 | // force axis to Z up. 99 | auto upAxis = vsg::CoordinateConvention::Z_UP; 100 | opt->formatCoordinateConventions[".gltf"] = upAxis; 101 | opt->formatCoordinateConventions[".glb"] = upAxis; 102 | #endif 103 | 104 | if (auto model = vsg::read_cast(binary_fin, opt)) 105 | { 106 | group->addChild(model); 107 | } 108 | } 109 | 110 | if (vsg::value(false, gltf::report, options)) 111 | { 112 | vsg::LogOutput output; 113 | 114 | output("Tiles3D::read_cmpt(..)"); 115 | output("magic = ", header.magic); 116 | output("version = ", header.version); 117 | output("byteLength = ", header.byteLength); 118 | output("tilesLength = ", header.tilesLength); 119 | 120 | output("innerHeaders.size() = ", innerHeaders.size()); 121 | for (auto& innerHeader : innerHeaders) 122 | { 123 | output(" {", innerHeader.magic, ", ", innerHeader.version, ", ", innerHeader.byteLength, " }"); 124 | } 125 | } 126 | 127 | vsg::ref_ptr model; 128 | 129 | if (group->children.size() == 1) 130 | model = group->children[0]; 131 | else if (!group->children.empty()) 132 | model = group; 133 | 134 | if (model && filename) model->setValue("b3dm", filename); 135 | 136 | return model; 137 | } 138 | -------------------------------------------------------------------------------- /include/vsgXchange/images.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 5 | Copyright(c) 2021 Robert Osfield 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shimages be included in images 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | namespace vsgXchange 33 | { 34 | /// Composite ReaderWriter that holds the used 3rd party image format loaders. 35 | /// By default utilizes the stbi, dds and ktx ReaderWriters so that users only need to create vsgXchange::images::create() to utilize them all. 36 | class VSGXCHANGE_DECLSPEC images : public vsg::Inherit 37 | { 38 | public: 39 | images(); 40 | }; 41 | 42 | /// add png, jpeg and gif support using local build of stbi. 43 | class VSGXCHANGE_DECLSPEC stbi : public vsg::Inherit 44 | { 45 | public: 46 | stbi(); 47 | 48 | vsg::ref_ptr read(const vsg::Path& filename, vsg::ref_ptr options = {}) const override; 49 | vsg::ref_ptr read(std::istream& fin, vsg::ref_ptr options = {}) const override; 50 | vsg::ref_ptr read(const uint8_t* ptr, size_t size, vsg::ref_ptr options = {}) const override; 51 | bool write(const vsg::Object* object, const vsg::Path& filename, vsg::ref_ptr = {}) const override; 52 | bool write(const vsg::Object* object, std::ostream& stream, vsg::ref_ptr = {}) const override; 53 | 54 | bool getFeatures(Features& features) const override; 55 | 56 | // vsg::Options::setValue(str, value) supported options: 57 | static constexpr const char* jpeg_quality = "jpeg_quality"; /// set the int quality value when writing out to image as jpeg file. 58 | static constexpr const char* image_format = "image_format"; /// Override read image format (8bit RGB/RGBA default to sRGB) to be specified class of CoordinateSpace (sRGB or LINEAR). 59 | 60 | bool readOptions(vsg::Options& options, vsg::CommandLine& arguments) const override; 61 | 62 | private: 63 | std::set _supportedExtensions; 64 | }; 65 | 66 | /// add dds support using local build of tinydds. 67 | class VSGXCHANGE_DECLSPEC dds : public vsg::Inherit 68 | { 69 | public: 70 | dds(); 71 | 72 | vsg::ref_ptr read(const vsg::Path& filename, vsg::ref_ptr options = {}) const override; 73 | vsg::ref_ptr read(std::istream& fin, vsg::ref_ptr options = {}) const override; 74 | vsg::ref_ptr read(const uint8_t* ptr, size_t size, vsg::ref_ptr options = {}) const override; 75 | 76 | bool getFeatures(Features& features) const override; 77 | 78 | // vsg::Options::setValue(str, value) supported options: 79 | static constexpr const char* image_format = "image_format"; /// Override read image format (8bit RGB/RGBA default to sRGB) to be specified class of CoordinateSpace (sRGB or LINEAR). 80 | 81 | bool readOptions(vsg::Options& options, vsg::CommandLine& arguments) const override; 82 | 83 | private: 84 | std::set _supportedExtensions; 85 | }; 86 | 87 | /// add ktx using using local build of libktx 88 | class VSGXCHANGE_DECLSPEC ktx : public vsg::Inherit 89 | { 90 | public: 91 | ktx(); 92 | 93 | vsg::ref_ptr read(const vsg::Path& filename, vsg::ref_ptr options = {}) const override; 94 | vsg::ref_ptr read(std::istream& fin, vsg::ref_ptr options = {}) const override; 95 | vsg::ref_ptr read(const uint8_t* ptr, size_t size, vsg::ref_ptr options = {}) const override; 96 | 97 | bool getFeatures(Features& features) const override; 98 | 99 | private: 100 | ~ktx(); 101 | 102 | class Implementation; 103 | Implementation* _implementation; 104 | }; 105 | 106 | /// optional .exr support using OpenEXR library 107 | class openexr : public vsg::Inherit 108 | { 109 | public: 110 | openexr(); 111 | 112 | vsg::ref_ptr read(const vsg::Path& filename, vsg::ref_ptr options = {}) const override; 113 | vsg::ref_ptr read(std::istream& fin, vsg::ref_ptr options = {}) const override; 114 | vsg::ref_ptr read(const uint8_t* ptr, size_t size, vsg::ref_ptr options = {}) const override; 115 | 116 | bool write(const vsg::Object* object, const vsg::Path& filename, vsg::ref_ptr = {}) const override; 117 | bool write(const vsg::Object* object, std::ostream& fout, vsg::ref_ptr = {}) const override; 118 | 119 | bool getFeatures(Features& features) const override; 120 | 121 | private: 122 | std::set _supportedExtensions; 123 | }; 124 | 125 | } // namespace vsgXchange 126 | 127 | EVSG_type_name(vsgXchange::images); 128 | EVSG_type_name(vsgXchange::stbi); 129 | EVSG_type_name(vsgXchange::dds); 130 | EVSG_type_name(vsgXchange::ktx); 131 | EVSG_type_name(vsgXchange::openexr); 132 | -------------------------------------------------------------------------------- /src/3DTiles/b3dm.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2025 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | using namespace vsgXchange; 28 | 29 | // b3dm_FeatureTable 30 | // 31 | void Tiles3D::b3dm_FeatureTable::read_array(vsg::JSONParser& parser, const std::string_view& property) 32 | { 33 | if (property == "RTC_CENTER") 34 | parser.read_array(RTC_CENTER); 35 | else 36 | parser.warning(); 37 | } 38 | 39 | void Tiles3D::b3dm_FeatureTable::read_object(vsg::JSONParser& parser, const std::string_view& property) 40 | { 41 | if (property == "RTC_CENTER") 42 | parser.read_object(RTC_CENTER); 43 | else 44 | parser.warning(); 45 | } 46 | 47 | void Tiles3D::b3dm_FeatureTable::read_number(vsg::JSONParser& parser, const std::string_view& property, std::istream& input) 48 | { 49 | if (property == "BATCH_LENGTH") 50 | input >> BATCH_LENGTH; 51 | else 52 | parser.warning(); 53 | } 54 | 55 | void Tiles3D::b3dm_FeatureTable::convert() 56 | { 57 | if (!binary) return; 58 | 59 | RTC_CENTER.assign(*binary, 3); 60 | } 61 | 62 | void Tiles3D::b3dm_FeatureTable::report(vsg::LogOutput& output) 63 | { 64 | output("b3dm_FeatureTable { "); 65 | output(" RTC_CENTER ", RTC_CENTER.values); 66 | output(" BATCH_LENGTH ", BATCH_LENGTH); 67 | output("}"); 68 | } 69 | 70 | //////////////////////////////////////////////////////////////////////////////////////////////////// 71 | // 72 | // read_b3dm 73 | // 74 | vsg::ref_ptr Tiles3D::read_b3dm(std::istream& fin, vsg::ref_ptr options, const vsg::Path& filename) const 75 | { 76 | 77 | fin.seekg(0); 78 | 79 | // https://github.com/CesiumGS/3d-tiles/tree/1.0/specification/TileFormats/Batched3DModel 80 | struct Header 81 | { 82 | char magic[4] = {0, 0, 0, 0}; 83 | uint32_t version = 0; 84 | uint32_t byteLength = 0; 85 | uint32_t featureTableJSONByteLength = 0; 86 | uint32_t featureTableBinaryByteLength = 0; 87 | uint32_t batchTableJSONByteLength = 0; 88 | uint32_t batchTableBinaryLength = 0; 89 | }; 90 | 91 | Header header; 92 | fin.read(reinterpret_cast(&header), sizeof(Header)); 93 | 94 | if (!fin.good()) 95 | { 96 | vsg::warn("IO error reading bd3m file."); 97 | return {}; 98 | } 99 | 100 | if (strncmp(header.magic, "b3dm", 4) != 0) 101 | { 102 | vsg::warn("magic number not b3dm"); 103 | return {}; 104 | } 105 | 106 | // Feature table 107 | // Batch table 108 | // Binary glTF 109 | 110 | vsg::ref_ptr featureTable = b3dm_FeatureTable::create(); 111 | if (header.featureTableJSONByteLength > 0) 112 | { 113 | featureTable = b3dm_FeatureTable::create(); 114 | 115 | vsg::JSONParser parser; 116 | parser.buffer.resize(header.featureTableJSONByteLength); 117 | fin.read(parser.buffer.data(), header.featureTableJSONByteLength); 118 | 119 | if (header.featureTableBinaryByteLength > 0) 120 | { 121 | featureTable->binary = vsg::ubyteArray::create(header.featureTableBinaryByteLength); 122 | fin.read(reinterpret_cast(featureTable->binary->dataPointer()), header.featureTableBinaryByteLength); 123 | } 124 | 125 | parser.read_object(*featureTable); 126 | } 127 | 128 | vsg::ref_ptr batchTable = BatchTable::create(); 129 | 130 | if (header.batchTableJSONByteLength > 0) 131 | { 132 | vsg::JSONParser parser; 133 | parser.buffer.resize(header.batchTableJSONByteLength); 134 | fin.read(parser.buffer.data(), header.batchTableJSONByteLength); 135 | 136 | if (header.batchTableBinaryLength > 0) 137 | { 138 | batchTable->binary = vsg::ubyteArray::create(header.batchTableBinaryLength); 139 | fin.read(reinterpret_cast(batchTable->binary->dataPointer()), header.batchTableBinaryLength); 140 | } 141 | 142 | parser.read_object(*batchTable); 143 | 144 | batchTable->length = featureTable->BATCH_LENGTH; 145 | batchTable->convert(); 146 | } 147 | 148 | if (vsg::value(false, gltf::report, options)) 149 | { 150 | vsg::LogOutput output; 151 | 152 | output("Tiles3D::read_b3dm()"); 153 | output("magic = ", header.magic); 154 | output("version = ", header.version); 155 | output("byteLength = ", header.byteLength); 156 | output("featureTableJSONByteLength = ", header.featureTableJSONByteLength); 157 | output("featureTableBinaryByteLength = ", header.featureTableBinaryByteLength); 158 | output("batchTableJSONByteLength = ", header.batchTableJSONByteLength); 159 | output("batchTableBinaryLength = ", header.batchTableBinaryLength); 160 | 161 | vsg::LogOutput log; 162 | 163 | if (featureTable) featureTable->report(output); 164 | if (batchTable) batchTable->report(output); 165 | } 166 | 167 | uint32_t size_of_feature_and_batch_tables = header.featureTableJSONByteLength + header.featureTableBinaryByteLength + header.batchTableJSONByteLength + header.batchTableBinaryLength; 168 | uint32_t size_of_gltfField = header.byteLength - sizeof(Header) - size_of_feature_and_batch_tables; 169 | 170 | // TODO: need to modify glTF loader to handle batched value assessor. 171 | // https://github.com/CesiumGS/3d-tiles/tree/1.0/specification/TileFormats/Batched3DModel#batch-table 172 | 173 | std::string binary; 174 | binary.resize(size_of_gltfField); 175 | fin.read(binary.data(), size_of_gltfField); 176 | 177 | vsg::mem_stream binary_fin(reinterpret_cast(binary.data()), binary.size()); 178 | 179 | auto opt = vsg::clone(options); 180 | opt->extensionHint = ".glb"; 181 | 182 | auto model = vsg::read_cast(binary_fin, opt); 183 | 184 | if (featureTable && featureTable->RTC_CENTER && featureTable->RTC_CENTER.values.size() == 3) 185 | { 186 | vsg::dvec3 rtc_center; 187 | rtc_center.x = featureTable->RTC_CENTER.values[0]; 188 | rtc_center.y = featureTable->RTC_CENTER.values[1]; 189 | rtc_center.z = featureTable->RTC_CENTER.values[2]; 190 | 191 | auto transform = vsg::MatrixTransform::create(); 192 | transform->matrix = vsg::translate(rtc_center); 193 | transform->addChild(model); 194 | 195 | model = transform; 196 | } 197 | 198 | if (model && filename) model->setValue("b3dm", filename); 199 | 200 | return model; 201 | } 202 | -------------------------------------------------------------------------------- /include/vsgXchange/gdal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 5 | Copyright(c) 2021 Robert Osfield 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shimages be included in images 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | namespace vsgXchange 34 | { 35 | /// optional GDAL ReaderWriter 36 | class VSGXCHANGE_DECLSPEC GDAL : public vsg::Inherit 37 | { 38 | public: 39 | GDAL(); 40 | vsg::ref_ptr read(const vsg::Path& filename, vsg::ref_ptr options) const override; 41 | vsg::ref_ptr read(std::istream& fin, vsg::ref_ptr options = {}) const override; 42 | vsg::ref_ptr read(const uint8_t* ptr, size_t size, vsg::ref_ptr options = {}) const override; 43 | 44 | bool getFeatures(Features& features) const override; 45 | 46 | protected: 47 | ~GDAL(); 48 | 49 | class Implementation; 50 | Implementation* _implementation; 51 | }; 52 | 53 | } // namespace vsgXchange 54 | 55 | EVSG_type_name(vsgXchange::GDAL); 56 | 57 | #ifdef vsgXchange_GDAL 58 | 59 | # include "gdal_priv.h" 60 | # include "ogr_spatialref.h" 61 | 62 | # include 63 | # include 64 | # include 65 | 66 | # include 67 | # include 68 | 69 | namespace vsgXchange 70 | { 71 | /// call GDALAllRegister() etc. if it hasn't already been called. Return true if this call to initGDAL() invoked GDAL setup, or false if it has previously been done. 72 | extern VSGXCHANGE_DECLSPEC bool initGDAL(); 73 | 74 | /// Call GDALOpen(..) to open specified file returning a std::shared_ptr to reboustly manage the lifetime of the GDALDataSet, automatiically call GDALClose. 75 | inline std::shared_ptr openDataSet(const vsg::Path& filename, GDALAccess access) 76 | { 77 | // GDAL doesn't support wide string filenames so convert vsg::Path to std::string and then pass to GDALOpen 78 | return std::shared_ptr(static_cast(GDALOpen(filename.string().c_str(), access)), [](GDALDataset* dataset) { GDALClose(dataset); }); 79 | } 80 | 81 | /// Call GDALOpenShared(..) to open specified file returning a std::shared_ptr to reboustly manage the lifetime of the GDALDataSet, automatiically call GDALClose. 82 | inline std::shared_ptr openSharedDataSet(const vsg::Path& filename, GDALAccess access) 83 | { 84 | // GDAL doesn't support wide string filenames so convert vsg::Path to std::string and then pass to GDALOpenShared 85 | return std::shared_ptr(static_cast(GDALOpenShared(filename.string().c_str(), access)), [](GDALDataset* dataset) { GDALClose(dataset); }); 86 | } 87 | 88 | /// return true if two GDALDataset has the same projection reference string/ 89 | extern VSGXCHANGE_DECLSPEC bool compatibleDatasetProjections(const GDALDataset& lhs, const GDALDataset& rhs); 90 | 91 | /// return true if two GDALDataset has the same projection, geo transform and dimensions indicating they are perfectly pixel aliged and matched in size. 92 | extern VSGXCHANGE_DECLSPEC bool compatibleDatasetProjectionsTransformAndSizes(const GDALDataset& lhs, const GDALDataset& rhs); 93 | 94 | /// create a vsg::Image2D of the approrpiate type that maps to specified dimensions and GDALDataType 95 | extern VSGXCHANGE_DECLSPEC vsg::ref_ptr createImage2D(int width, int height, int numComponents, GDALDataType dataType, vsg::dvec4 def = {0.0, 0.0, 0.0, 1.0}); 96 | 97 | /// copy a RasterBand onto a target RGBA component of a vsg::Data. Dimensions and datatypes must be compatble between RasterBand and vsg::Data. Return true on success, false on failure to copy. 98 | extern VSGXCHANGE_DECLSPEC bool copyRasterBandToImage(GDALRasterBand& band, vsg::Data& image, int component); 99 | 100 | /// assign GDAL MetaData mapping the "key=value" entries to vsg::Object as setValue(key, std::string(value)). 101 | extern VSGXCHANGE_DECLSPEC bool assignMetaData(GDALDataset& dataset, vsg::Object& object); 102 | 103 | /// call binary comparison operators on dereferenced items in specified range. 104 | template 105 | bool all_equal(Iterator first, Iterator last, BinaryPredicate compare) 106 | { 107 | if (first == last) return true; 108 | Iterator itr = first; 109 | ++itr; 110 | 111 | for (; itr != last; ++itr) 112 | { 113 | if (!compare(**first, **itr)) return false; 114 | } 115 | 116 | return true; 117 | } 118 | 119 | /// collect the set of GDALDataType of all the RansterBand is the specified GDALDataset 120 | inline std::set dataTypes(GDALDataset& dataset) 121 | { 122 | std::set types; 123 | for (int i = 1; i <= dataset.GetRasterCount(); ++i) 124 | { 125 | GDALRasterBand* band = dataset.GetRasterBand(i); 126 | types.insert(band->GetRasterDataType()); 127 | } 128 | 129 | return types; 130 | } 131 | 132 | /// collect the set of GDALDataType of all the RansterBand is the specified range of GDALDataset 133 | template 134 | std::set dataTypes(Iterator first, Iterator last) 135 | { 136 | std::set types; 137 | for (Iterator itr = first; itr != last; ++itr) 138 | { 139 | GDALDataset& dataset = **itr; 140 | for (int i = 1; i <= dataset.GetRasterCount(); ++i) 141 | { 142 | GDALRasterBand* band = dataset.GetRasterBand(i); 143 | types.insert(band->GetRasterDataType()); 144 | } 145 | } 146 | return types; 147 | } 148 | 149 | /// get the latitude, longitude and altitude values from the GDALDataSet's EXIF_GPSLatitude, EXIF_GPSLongitude and EXIF_GPSAltitude meta data fields, return true on success, 150 | extern VSGXCHANGE_DECLSPEC bool getEXIF_LatitudeLongitudeAlititude(GDALDataset& dataset, double& latitude, double& longitude, double& altitude); 151 | 152 | /// get the latitude, longitude and altitude values from the vsg::Object's EXIF_GPSLatitude, EXIF_GPSLongitude and EXIF_GPSAltitude meta data fields, return true on success, 153 | extern VSGXCHANGE_DECLSPEC bool getEXIF_LatitudeLongitudeAlititude(const vsg::Object& object, double& latitude, double& longitude, double& altitude); 154 | 155 | template 156 | struct in_brackets 157 | { 158 | in_brackets(T& v) : 159 | value(v) {} 160 | T& value; 161 | }; 162 | 163 | template 164 | std::istream& operator>>(std::istream& input, in_brackets field) 165 | { 166 | while (input.peek() == ' ') input.get(); 167 | 168 | std::string str; 169 | if (input.peek() == '(') 170 | { 171 | input.ignore(); 172 | 173 | input >> field.value; 174 | 175 | if constexpr (std::is_same_v) 176 | { 177 | if (!field.value.empty() && field.value[field.value.size() - 1] == ')') 178 | { 179 | field.value.erase(field.value.size() - 1); 180 | return input; 181 | } 182 | else 183 | { 184 | while (input.peek() != ')') 185 | { 186 | int c = input.get(); 187 | if (input.eof()) return input; 188 | 189 | field.value.push_back(c); 190 | } 191 | } 192 | } 193 | 194 | if (input.peek() == ')') 195 | { 196 | input.ignore(); 197 | } 198 | } 199 | else 200 | { 201 | input >> field.value; 202 | } 203 | 204 | return input; 205 | } 206 | 207 | /// helper class for reading decimal degree in the form of (degrees) (minutes) (seconds) as used with EXIF_GPSLatitude and EXIF_GPSLongitude tags. 208 | /// usage: 209 | /// std::stringstream str(EXIF_GPSLatitude_String); 210 | /// double latitude; 211 | /// str >> dms_in_brackets(latitude); 212 | struct dms_in_brackets 213 | { 214 | dms_in_brackets(double& angle) : 215 | value(angle) {} 216 | double& value; 217 | }; 218 | 219 | inline std::istream& operator>>(std::istream& input, dms_in_brackets field) 220 | { 221 | double degrees = 0.0, minutes = 0.0, seconds = 0.0; 222 | input >> in_brackets(degrees) >> in_brackets(minutes) >> in_brackets(seconds); 223 | field.value = degrees + (minutes + seconds / 60.0) / 60.0; 224 | return input; 225 | } 226 | 227 | } // namespace vsgXchange 228 | 229 | #endif 230 | -------------------------------------------------------------------------------- /src/gdal/GDAL.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | namespace vsgXchange 20 | { 21 | 22 | class vsgXchange::GDAL::Implementation 23 | { 24 | public: 25 | Implementation(); 26 | 27 | vsg::ref_ptr read(const vsg::Path& filename, vsg::ref_ptr options = {}) const; 28 | vsg::ref_ptr read(std::istream& fin, vsg::ref_ptr options) const; 29 | vsg::ref_ptr read(const uint8_t* ptr, size_t size, vsg::ref_ptr options) const; 30 | 31 | protected: 32 | }; 33 | 34 | } // namespace vsgXchange 35 | 36 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 37 | // 38 | // GDAL ReaderWriter facade 39 | // 40 | vsgXchange::GDAL::GDAL() : 41 | _implementation(new vsgXchange::GDAL::Implementation()) 42 | { 43 | } 44 | 45 | vsgXchange::GDAL::~GDAL() 46 | { 47 | delete _implementation; 48 | } 49 | 50 | vsg::ref_ptr vsgXchange::GDAL::read(const vsg::Path& filename, vsg::ref_ptr options) const 51 | { 52 | return _implementation->read(filename, options); 53 | } 54 | 55 | vsg::ref_ptr vsgXchange::GDAL::read(std::istream& fin, vsg::ref_ptr options) const 56 | { 57 | return _implementation->read(fin, options); 58 | } 59 | vsg::ref_ptr vsgXchange::GDAL::read(const uint8_t* ptr, size_t size, vsg::ref_ptr options) const 60 | { 61 | return _implementation->read(ptr, size, options); 62 | } 63 | 64 | bool vsgXchange::GDAL::getFeatures(Features& features) const 65 | { 66 | vsgXchange::initGDAL(); 67 | 68 | auto driverManager = GetGDALDriverManager(); 69 | int driverCount = driverManager->GetDriverCount(); 70 | 71 | vsg::ReaderWriter::FeatureMask rasterFeatureMask = vsg::ReaderWriter::READ_FILENAME; 72 | 73 | const std::string dotPrefix = "."; 74 | 75 | for (int i = 0; i < driverCount; ++i) 76 | { 77 | auto driver = driverManager->GetDriver(i); 78 | auto raster_meta = driver->GetMetadataItem(GDAL_DCAP_RASTER); 79 | auto extensions_meta = driver->GetMetadataItem(GDAL_DMD_EXTENSIONS); 80 | // auto longname_meta = driver->GetMetadataItem( GDAL_DMD_LONGNAME ); 81 | if (raster_meta && extensions_meta) 82 | { 83 | std::string extensions = extensions_meta; 84 | std::string ext; 85 | 86 | std::string::size_type start_pos = 0; 87 | for (;;) 88 | { 89 | start_pos = extensions.find_first_not_of(" .", start_pos); 90 | if (start_pos == std::string::npos) break; 91 | 92 | std::string::size_type delimiter_pos = extensions.find_first_of(" /", start_pos); 93 | if (delimiter_pos != std::string::npos) 94 | { 95 | ext = extensions.substr(start_pos, delimiter_pos - start_pos); 96 | features.extensionFeatureMap[dotPrefix + ext] = rasterFeatureMask; 97 | start_pos = delimiter_pos + 1; 98 | if (start_pos == extensions.length()) break; 99 | } 100 | else 101 | { 102 | ext = extensions.substr(start_pos, std::string::npos); 103 | features.extensionFeatureMap[dotPrefix + ext] = rasterFeatureMask; 104 | break; 105 | } 106 | } 107 | } 108 | } 109 | 110 | return true; 111 | } 112 | 113 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 114 | // 115 | // GDAL ReaderWriter implementation 116 | // 117 | vsgXchange::GDAL::Implementation::Implementation() 118 | { 119 | } 120 | 121 | vsg::ref_ptr vsgXchange::GDAL::Implementation::read(const vsg::Path& filename, vsg::ref_ptr options) const 122 | { 123 | // GDAL tries to load all datatypes so up front catch VSG and OSG native formats. 124 | vsg::Path ext = vsg::lowerCaseFileExtension(filename); 125 | if (ext == ".vsgb" || ext == ".vsgt" || ext == ".osgb" || ext == ".osgt" || ext == ".osg" || ext == ".tile") return {}; 126 | 127 | vsg::Path filenameToUse = (vsg::filePath(filename) == "/vsimem") ? filename : vsg::findFile(filename, options); 128 | 129 | if (!filenameToUse) return {}; 130 | 131 | vsgXchange::initGDAL(); 132 | 133 | auto dataset = vsgXchange::openSharedDataSet(filenameToUse, GA_ReadOnly); 134 | if (!dataset) 135 | { 136 | return {}; 137 | } 138 | 139 | auto types = vsgXchange::dataTypes(*dataset); 140 | if (types.size() > 1) 141 | { 142 | vsg::info("GDAL::read(", filename, ") multiple input data types not supported."); 143 | for (auto& type : types) 144 | { 145 | vsg::info(" GDALDataType ", GDALGetDataTypeName(type)); 146 | } 147 | return {}; 148 | } 149 | if (types.empty()) 150 | { 151 | vsg::info("GDAL::read(", filename, ") types set empty."); 152 | 153 | return {}; 154 | } 155 | 156 | GDALDataType dataType = *types.begin(); 157 | 158 | std::vector rasterBands; 159 | for (int i = 1; i <= dataset->GetRasterCount(); ++i) 160 | { 161 | GDALRasterBand* band = dataset->GetRasterBand(i); 162 | GDALColorInterp classification = band->GetColorInterpretation(); 163 | 164 | if (classification != GCI_Undefined) 165 | { 166 | rasterBands.push_back(band); 167 | } 168 | else 169 | { 170 | vsg::info("GDAL::read(", filename, ") Undefined classification on raster band ", i); 171 | } 172 | } 173 | 174 | int numComponents = static_cast(rasterBands.size()); 175 | if (numComponents == 0) 176 | { 177 | vsg::info("GDAL::read(", filename, ") failed numComponents = ", numComponents); 178 | return {}; 179 | } 180 | 181 | bool mapRGBtoRGBAHint = !options || options->mapRGBtoRGBAHint; 182 | if (mapRGBtoRGBAHint && numComponents == 3) 183 | { 184 | //std::cout<<"Remapping RGB to RGBA "< 4) 189 | { 190 | vsg::info("GDAL::read(", filename, ") Too many raster bands to merge into a single output, maximum of 4 raster bands supported."); 191 | return {}; 192 | } 193 | 194 | int width = dataset->GetRasterXSize(); 195 | int height = dataset->GetRasterYSize(); 196 | 197 | auto image = vsgXchange::createImage2D(width, height, numComponents, dataType, vsg::dvec4(0.0, 0.0, 0.0, 1.0)); 198 | if (!image) return {}; 199 | 200 | for (int component = 0; component < static_cast(rasterBands.size()); ++component) 201 | { 202 | vsgXchange::copyRasterBandToImage(*rasterBands[component], *image, component); 203 | } 204 | 205 | vsgXchange::assignMetaData(*dataset, *image); 206 | 207 | if (dataset->GetProjectionRef() && std::strlen(dataset->GetProjectionRef()) > 0) 208 | { 209 | image->setValue("ProjectionRef", std::string(dataset->GetProjectionRef())); 210 | } 211 | 212 | auto transform = vsg::doubleArray::create(6); 213 | if (dataset->GetGeoTransform(transform->data()) == CE_None) 214 | { 215 | image->setObject("GeoTransform", transform); 216 | } 217 | 218 | return image; 219 | } 220 | 221 | vsg::ref_ptr vsgXchange::GDAL::Implementation::read(std::istream& fin, vsg::ref_ptr options) const 222 | { 223 | // if (!vsg::compatibleExtension(options, _supportedExtensions)) return {}; 224 | 225 | std::string input; 226 | std::stringstream* sstr = dynamic_cast(&fin); 227 | if (sstr) 228 | { 229 | input = sstr->str(); 230 | } 231 | else 232 | { 233 | std::string buffer(1 << 16, 0); // 64kB 234 | while (!fin.eof()) 235 | { 236 | fin.read(&buffer[0], buffer.size()); 237 | const auto bytes_readed = fin.gcount(); 238 | input.append(&buffer[0], bytes_readed); 239 | } 240 | } 241 | 242 | return read(reinterpret_cast(input.data()), input.size(), options); 243 | } 244 | 245 | vsg::ref_ptr vsgXchange::GDAL::Implementation::read(const uint8_t* ptr, size_t size, vsg::ref_ptr options) const 246 | { 247 | std::string temp_filename("/vsimem/temp"); 248 | temp_filename.append(options->extensionHint.string()); 249 | 250 | // create a GDAL Virtual File for memory block. 251 | VSILFILE* vsFile = VSIFileFromMemBuffer(temp_filename.c_str(), static_cast(const_cast(ptr)), static_cast(size), 0); 252 | 253 | auto result = vsgXchange::GDAL::Implementation::read(temp_filename, options); 254 | 255 | VSIFCloseL(vsFile); 256 | 257 | return result; 258 | } 259 | -------------------------------------------------------------------------------- /src/curl/curl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace vsgXchange; 23 | 24 | namespace vsgXchange 25 | { 26 | 27 | bool containsServerAddress(const vsg::Path& filename) 28 | { 29 | return filename.compare(0, 7, "http://") == 0 || filename.compare(0, 8, "https://") == 0; 30 | } 31 | 32 | std::pair getServerPathAndFilename(const vsg::Path& filename) 33 | { 34 | auto pos = filename.find("://"); 35 | if (pos != vsg::Path::npos) 36 | { 37 | auto pos_slash = filename.find_first_of('/', pos + 3); 38 | if (pos_slash != vsg::Path::npos) 39 | { 40 | return {filename.substr(pos + 3, pos_slash - pos - 3), filename.substr(pos_slash + 1, vsg::Path::npos)}; 41 | } 42 | else 43 | { 44 | return {filename.substr(pos + 3, vsg::Path::npos), ""}; 45 | } 46 | } 47 | return {}; 48 | } 49 | 50 | vsg::Path getFileCachePath(const vsg::Path& fileCache, const vsg::Path& filename) 51 | { 52 | auto pos = filename.find("://"); 53 | if (pos != vsg::Path::npos) 54 | { 55 | return fileCache / filename.substr(pos + 3, vsg::Path::npos); 56 | } 57 | return {}; 58 | } 59 | 60 | class curl::Implementation 61 | { 62 | public: 63 | Implementation(); 64 | virtual ~Implementation(); 65 | 66 | vsg::ref_ptr read(const vsg::Path& filename, vsg::ref_ptr options = {}) const; 67 | 68 | protected: 69 | }; 70 | 71 | } // namespace vsgXchange 72 | 73 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 74 | // 75 | // CURL ReaderWriter facade 76 | // 77 | curl::curl() : 78 | _implementation(nullptr) 79 | { 80 | } 81 | curl::~curl() 82 | { 83 | delete _implementation; 84 | } 85 | vsg::ref_ptr curl::read(const vsg::Path& filename, vsg::ref_ptr options) const 86 | { 87 | vsg::Path serverFilename = filename; 88 | 89 | bool contains_serverAddress = containsServerAddress(filename); 90 | 91 | if (options) 92 | { 93 | if (!contains_serverAddress && !options->paths.empty()) 94 | { 95 | contains_serverAddress = containsServerAddress(options->paths.front()); 96 | if (contains_serverAddress) 97 | { 98 | serverFilename = options->paths.front() / filename; 99 | } 100 | } 101 | 102 | if (contains_serverAddress && options->fileCache) 103 | { 104 | auto fileCachePath = getFileCachePath(options->fileCache, serverFilename); 105 | if (vsg::fileExists(fileCachePath)) 106 | { 107 | auto local_options = vsg::clone(options); 108 | 109 | local_options->paths.insert(local_options->paths.begin(), vsg::filePath(serverFilename)); 110 | local_options->extensionHint = vsg::lowerCaseFileExtension(filename); 111 | 112 | std::ifstream fin(fileCachePath, std::ios::in | std::ios::binary); 113 | auto object = vsg::read(fin, local_options); // do we need to remove any http URL? 114 | if (object) 115 | { 116 | return object; 117 | } 118 | } 119 | } 120 | } 121 | 122 | if (contains_serverAddress) 123 | { 124 | { 125 | std::scoped_lock lock(_mutex); 126 | if (!_implementation) _implementation = new curl::Implementation(); 127 | } 128 | 129 | return _implementation->read(serverFilename, options); 130 | } 131 | else 132 | { 133 | return {}; 134 | } 135 | } 136 | 137 | bool curl::getFeatures(Features& features) const 138 | { 139 | features.protocolFeatureMap["http"] = vsg::ReaderWriter::READ_FILENAME; 140 | features.protocolFeatureMap["https"] = vsg::ReaderWriter::READ_FILENAME; 141 | features.optionNameTypeMap[curl::SSL_OPTIONS] = "uint32_t"; 142 | return true; 143 | } 144 | 145 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 146 | // 147 | // CURL ReaderWriter implementation 148 | // 149 | 150 | // use static mutex and counter to track whether the curl_global_init(..) and curl_global_cleanup() should be called. 151 | bool curl::s_do_curl_global_init_and_cleanup = true; 152 | std::mutex s_curlImplementationMutex; 153 | uint32_t s_curlImplementationCount = 0; 154 | 155 | curl::Implementation::Implementation() 156 | { 157 | if (curl::s_do_curl_global_init_and_cleanup) 158 | { 159 | std::scoped_lock lock(s_curlImplementationMutex); 160 | if (s_curlImplementationCount == 0) 161 | { 162 | //std::cout<<"curl_global_init()"< lock(s_curlImplementationMutex); 174 | --s_curlImplementationCount; 175 | if (s_curlImplementationCount == 0) 176 | { 177 | //std::cout<<"curl_global_cleanup()"<(user_data); 190 | ostr->write(reinterpret_cast(ptr), realsize); 191 | } 192 | 193 | return realsize; 194 | } 195 | 196 | vsg::ref_ptr curl::Implementation::read(const vsg::Path& filename, vsg::ref_ptr options) const 197 | { 198 | auto _curl = curl_easy_init(); 199 | 200 | curl_easy_setopt(_curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); // make user controllable? 201 | curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1L); 202 | curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, StreamCallback); 203 | 204 | std::stringstream sstr; 205 | 206 | curl_easy_setopt(_curl, CURLOPT_URL, filename.string().c_str()); 207 | curl_easy_setopt(_curl, CURLOPT_WRITEDATA, (void*)&sstr); 208 | 209 | uint32_t sslOptions = 0; 210 | #if defined(_WIN32) && defined(CURLSSLOPT_NATIVE_CA) 211 | sslOptions |= CURLSSLOPT_NATIVE_CA; 212 | #endif 213 | if (options) options->getValue(curl::SSL_OPTIONS, sslOptions); 214 | if (sslOptions != 0) curl_easy_setopt(_curl, CURLOPT_SSL_OPTIONS, sslOptions); 215 | 216 | vsg::ref_ptr object; 217 | 218 | CURLcode result = curl_easy_perform(_curl); 219 | if (result == 0) 220 | { 221 | // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status 222 | long response_code = 0; 223 | result = curl_easy_getinfo(_curl, CURLINFO_RESPONSE_CODE, &response_code); 224 | 225 | if (result == 0 && response_code >= 200 && response_code < 300) // successful responses. 226 | { 227 | // success 228 | auto local_options = vsg::clone(options); 229 | local_options->paths.insert(local_options->paths.begin(), vsg::filePath(filename)); 230 | if (!local_options->extensionHint) 231 | { 232 | local_options->extensionHint = vsg::lowerCaseFileExtension(filename); 233 | } 234 | 235 | object = vsg::read(sstr, local_options); 236 | 237 | if (object && options->fileCache) 238 | { 239 | auto fileCachePath = getFileCachePath(options->fileCache, filename); 240 | if (fileCachePath) 241 | { 242 | vsg::makeDirectory(vsg::filePath(fileCachePath)); 243 | 244 | // reset the stringstream iterator to the beginning so we can copy it to the file cache file. 245 | sstr.clear(std::stringstream::goodbit); 246 | sstr.seekg(0); 247 | 248 | std::ofstream fout(fileCachePath, std::ios::out | std::ios::binary); 249 | 250 | fout << sstr.rdbuf(); 251 | } 252 | } 253 | } 254 | else 255 | { 256 | object = vsg::ReadError::create(vsg::make_string("vsgXchange::curl could not read file ", filename, ", CURLINFO_RESPONSE_CODE = ", response_code)); 257 | } 258 | } 259 | else 260 | { 261 | object = vsg::ReadError::create(vsg::make_string("vsgXchange::curl could not read file ", filename, ", result = ", result, ", ", curl_easy_strerror(result))); 262 | } 263 | 264 | if (_curl) curl_easy_cleanup(_curl); 265 | 266 | return object; 267 | } 268 | -------------------------------------------------------------------------------- /src/assimp/assimp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 André Normann & Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | #include "SceneConverter.h" 16 | 17 | using namespace vsgXchange; 18 | 19 | class assimp::Implementation 20 | { 21 | public: 22 | Implementation(); 23 | 24 | vsg::ref_ptr read(const vsg::Path& filename, vsg::ref_ptr options = {}) const; 25 | vsg::ref_ptr read(std::istream& fin, vsg::ref_ptr options = {}) const; 26 | vsg::ref_ptr read(const uint8_t* ptr, size_t size, vsg::ref_ptr options = {}) const; 27 | 28 | const uint32_t _importFlags; 29 | }; 30 | 31 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 32 | // 33 | // assimp ReaderWriter facade 34 | // 35 | assimp::assimp() : 36 | _implementation(new assimp::Implementation()) 37 | { 38 | vsg::debug("ASSIMP_VERSION_MAJOR ", ASSIMP_VERSION_MAJOR); 39 | vsg::debug("ASSIMP_VERSION_MINOR ", ASSIMP_VERSION_MINOR); 40 | vsg::debug("ASSIMP_VERSION_PATCH ", ASSIMP_VERSION_PATCH); 41 | } 42 | assimp::~assimp() 43 | { 44 | delete _implementation; 45 | } 46 | vsg::ref_ptr assimp::read(const vsg::Path& filename, vsg::ref_ptr options) const 47 | { 48 | return _implementation->read(filename, options); 49 | } 50 | 51 | vsg::ref_ptr assimp::read(std::istream& fin, vsg::ref_ptr options) const 52 | { 53 | return _implementation->read(fin, options); 54 | } 55 | 56 | vsg::ref_ptr assimp::read(const uint8_t* ptr, size_t size, vsg::ref_ptr options) const 57 | { 58 | return _implementation->read(ptr, size, options); 59 | } 60 | 61 | bool assimp::getFeatures(Features& features) const 62 | { 63 | std::string suported_extensions; 64 | Assimp::Importer importer; 65 | importer.GetExtensionList(suported_extensions); 66 | 67 | vsg::ReaderWriter::FeatureMask supported_features = static_cast(vsg::ReaderWriter::READ_FILENAME | vsg::ReaderWriter::READ_ISTREAM | vsg::ReaderWriter::READ_MEMORY); 68 | 69 | std::string::size_type start = 1; // skip * 70 | std::string::size_type semicolon = suported_extensions.find(';', start); 71 | while (semicolon != std::string::npos) 72 | { 73 | features.extensionFeatureMap[suported_extensions.substr(start, semicolon - start)] = supported_features; 74 | start = semicolon + 2; 75 | semicolon = suported_extensions.find(';', start); 76 | } 77 | features.extensionFeatureMap[suported_extensions.substr(start, std::string::npos)] = supported_features; 78 | 79 | // enumerate the supported vsg::Options::setValue(str, value) options 80 | features.optionNameTypeMap[assimp::generate_smooth_normals] = vsg::type_name(); 81 | features.optionNameTypeMap[assimp::generate_sharp_normals] = vsg::type_name(); 82 | features.optionNameTypeMap[assimp::crease_angle] = vsg::type_name(); 83 | features.optionNameTypeMap[assimp::two_sided] = vsg::type_name(); 84 | features.optionNameTypeMap[assimp::discard_empty_nodes] = vsg::type_name(); 85 | features.optionNameTypeMap[assimp::print_assimp] = vsg::type_name(); 86 | features.optionNameTypeMap[assimp::external_textures] = vsg::type_name(); 87 | features.optionNameTypeMap[assimp::external_texture_format] = vsg::type_name(); 88 | features.optionNameTypeMap[assimp::culling] = vsg::type_name(); 89 | features.optionNameTypeMap[assimp::vertex_color_space] = vsg::type_name(); 90 | features.optionNameTypeMap[assimp::material_color_space] = vsg::type_name(); 91 | 92 | return true; 93 | } 94 | 95 | bool assimp::readOptions(vsg::Options& options, vsg::CommandLine& arguments) const 96 | { 97 | bool result = arguments.readAndAssign(assimp::generate_smooth_normals, &options); 98 | result = arguments.readAndAssign(assimp::generate_sharp_normals, &options) || result; 99 | result = arguments.readAndAssign(assimp::crease_angle, &options) || result; 100 | result = arguments.readAndAssign(assimp::two_sided, &options) || result; 101 | result = arguments.readAndAssign(assimp::discard_empty_nodes, &options) || result; 102 | result = arguments.readAndAssign(assimp::print_assimp, &options) || result; 103 | result = arguments.readAndAssign(assimp::external_textures, &options) || result; 104 | result = arguments.readAndAssign(assimp::external_texture_format, &options) || result; 105 | result = arguments.readAndAssign(assimp::culling, &options) || result; 106 | result = arguments.readAndAssign(assimp::vertex_color_space, &options) || result; 107 | result = arguments.readAndAssign(assimp::material_color_space, &options) || result; 108 | 109 | return result; 110 | } 111 | 112 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 113 | // 114 | // assimp ReaderWriter implementation 115 | // 116 | assimp::Implementation::Implementation() : 117 | _importFlags{aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_OptimizeMeshes | aiProcess_SortByPType | aiProcess_ImproveCacheLocality | aiProcess_GenUVCoords | aiProcess_PopulateArmatureData} 118 | { 119 | } 120 | 121 | vsg::ref_ptr assimp::Implementation::read(const vsg::Path& filename, vsg::ref_ptr options) const 122 | { 123 | Assimp::Importer importer; 124 | vsg::Path ext = (options && options->extensionHint) ? options->extensionHint : vsg::lowerCaseFileExtension(filename); 125 | 126 | if (importer.IsExtensionSupported(ext.string())) 127 | { 128 | vsg::Path filenameToUse = vsg::findFile(filename, options); 129 | if (!filenameToUse) return {}; 130 | 131 | uint32_t flags = _importFlags; 132 | if (vsg::value(false, assimp::generate_smooth_normals, options)) 133 | { 134 | importer.SetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, vsg::value(80.0f, assimp::crease_angle, options)); 135 | flags |= aiProcess_GenSmoothNormals; 136 | } 137 | else if (vsg::value(false, assimp::generate_sharp_normals, options)) 138 | { 139 | flags |= aiProcess_GenNormals; 140 | } 141 | 142 | if (auto scene = importer.ReadFile(filenameToUse.string(), flags); scene) 143 | { 144 | auto opt = vsg::clone(options); 145 | opt->paths.insert(opt->paths.begin(), vsg::filePath(filenameToUse)); 146 | 147 | SceneConverter converter; 148 | converter.filename = filename; 149 | 150 | auto root = converter.visit(scene, opt, ext); 151 | if (root) 152 | { 153 | if (converter.externalTextures && converter.externalObjects && !converter.externalObjects->entries.empty()) 154 | root->setObject("external", converter.externalObjects); 155 | } 156 | 157 | return root; 158 | } 159 | else 160 | { 161 | vsg::warn("Failed to load file: ", filename, '\n', importer.GetErrorString()); 162 | } 163 | } 164 | 165 | return {}; 166 | } 167 | 168 | vsg::ref_ptr assimp::Implementation::read(std::istream& fin, vsg::ref_ptr options) const 169 | { 170 | if (!options || !options->extensionHint) return {}; 171 | 172 | Assimp::Importer importer; 173 | if (importer.IsExtensionSupported(options->extensionHint.string())) 174 | { 175 | std::string buffer(1 << 16, 0); // 64kB 176 | std::string input; 177 | 178 | while (!fin.eof()) 179 | { 180 | fin.read(&buffer[0], buffer.size()); 181 | const auto bytes_read = fin.gcount(); 182 | if (bytes_read == 0) break; 183 | input.append(&buffer[0], bytes_read); 184 | } 185 | 186 | vsg::info("assimp::Implementation::read() input.size() = ", input.size()); 187 | 188 | if (auto scene = importer.ReadFileFromMemory(input.data(), input.size(), _importFlags); scene) 189 | { 190 | SceneConverter converter; 191 | return converter.visit(scene, options, options->extensionHint); 192 | } 193 | else 194 | { 195 | vsg::warn("Failed to load file from stream: ", importer.GetErrorString()); 196 | } 197 | } 198 | 199 | return {}; 200 | } 201 | 202 | vsg::ref_ptr assimp::Implementation::read(const uint8_t* ptr, size_t size, vsg::ref_ptr options) const 203 | { 204 | if (!options || !options->extensionHint) return {}; 205 | 206 | Assimp::Importer importer; 207 | if (importer.IsExtensionSupported(options->extensionHint.string())) 208 | { 209 | if (auto scene = importer.ReadFileFromMemory(ptr, size, _importFlags); scene) 210 | { 211 | SceneConverter converter; 212 | return converter.visit(scene, options, options->extensionHint); 213 | } 214 | else 215 | { 216 | vsg::warn("Failed to load file from memory: ", importer.GetErrorString()); 217 | } 218 | } 219 | return {}; 220 | } 221 | -------------------------------------------------------------------------------- /src/assimp/SceneConverter.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 André Normann & Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #if (ASSIMP_VERSION_MAJOR == 5 && ASSIMP_VERSION_MINOR == 0) 25 | # include 26 | # define AI_MATKEY_BASE_COLOR AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR 27 | # define AI_MATKEY_GLOSSINESS_FACTOR AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR 28 | # define AI_MATKEY_METALLIC_FACTOR AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR 29 | # define AI_MATKEY_ROUGHNESS_FACTOR AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR 30 | #else 31 | # include 32 | 33 | # if (ASSIMP_VERSION_MAJOR == 5 && ASSIMP_VERSION_MINOR == 1 && ASSIMP_VERSION_PATCH == 0) 34 | # define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0 35 | # define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0 36 | # else 37 | # include 38 | # endif 39 | #endif 40 | 41 | #include 42 | 43 | namespace vsgXchange 44 | { 45 | enum class TextureFormat 46 | { 47 | native, 48 | vsgt, 49 | vsgb 50 | }; 51 | 52 | // this needs to be defined before 'vsg/commandline.h' has been included 53 | inline std::istream& operator>>(std::istream& is, TextureFormat& textureFormat) 54 | { 55 | std::string value; 56 | is >> value; 57 | 58 | if (value == "native") 59 | textureFormat = TextureFormat::native; 60 | else if (value == "vsgb") 61 | textureFormat = TextureFormat::vsgb; 62 | else if ((value == "vsgt") || (value == "vsga")) 63 | textureFormat = TextureFormat::vsgt; 64 | else 65 | textureFormat = TextureFormat::native; 66 | 67 | return is; 68 | } 69 | 70 | struct SamplerData 71 | { 72 | vsg::ref_ptr sampler; 73 | vsg::ref_ptr data; 74 | }; 75 | 76 | struct SubgraphStats 77 | { 78 | unsigned int depth = 0; 79 | unsigned int numMesh = 0; 80 | unsigned int numNodes = 0; 81 | unsigned int numBones = 0; 82 | vsg::ref_ptr vsg_object; 83 | 84 | SubgraphStats& operator+=(const SubgraphStats& rhs) 85 | { 86 | numMesh += rhs.numMesh; 87 | numNodes += rhs.numNodes; 88 | numBones += rhs.numBones; 89 | return *this; 90 | } 91 | }; 92 | 93 | struct BoneStats 94 | { 95 | unsigned int index = 0; 96 | std::string name; 97 | const aiNode* node; 98 | }; 99 | 100 | inline std::ostream& operator<<(std::ostream& output, const SubgraphStats& stats) 101 | { 102 | return output << "SubgraphStats{ numMesh = " << stats.numMesh << ", numNodes = " << stats.numNodes << ", numBones = " << stats.numBones << " }"; 103 | } 104 | 105 | inline std::ostream& operator<<(std::ostream& output, const aiMatrix4x4& m) 106 | { 107 | if (m.IsIdentity()) 108 | return output << "aiMatrix4x4{ Identity }"; 109 | else 110 | return output << "aiMatrix4x4{ {" << m.a1 << ", " << m.a2 << ", " << m.a3 << ", " << m.a4 << "} {" << m.b1 << ", " << m.b2 << ", " << m.b3 << ", " << m.b4 << "} {" << m.c1 << ", " << m.c2 << ", " << m.c3 << ", " << m.c4 << "} {" << m.d1 << ", " << m.d2 << ", " << m.d3 << ", " << m.d4 << "} }"; 111 | } 112 | 113 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 114 | // 115 | // assimp ReaderWriter SceneConverter 116 | // 117 | struct SceneConverter 118 | { 119 | using CameraMap = std::map>; 120 | using LightMap = std::map>; 121 | using SubgraphStatsMap = std::map; 122 | using BoneStatsMap = std::map; 123 | using BoneTransformMap = std::map; 124 | 125 | vsg::Path filename; 126 | 127 | vsg::ref_ptr options; 128 | const aiScene* scene = nullptr; 129 | vsg::Animations animations; 130 | CameraMap cameraMap; 131 | LightMap lightMap; 132 | SubgraphStatsMap subgraphStats; 133 | BoneStatsMap bones; 134 | BoneTransformMap boneTransforms; 135 | 136 | bool useViewDependentState = true; 137 | bool discardEmptyNodes = false; 138 | int printAssimp = 0; 139 | bool externalTextures = false; 140 | TextureFormat externalTextureFormat = TextureFormat::native; 141 | bool culling = true; 142 | 143 | // set for the file format being read. 144 | vsg::CoordinateSpace sourceVertexColorSpace = vsg::CoordinateSpace::LINEAR; 145 | vsg::CoordinateSpace sourceMaterialColorSpace = vsg::CoordinateSpace::LINEAR; 146 | 147 | // set for the target ShaderSet's 148 | vsg::CoordinateSpace targetVertexColorSpace = vsg::CoordinateSpace::LINEAR; 149 | vsg::CoordinateSpace targetMaterialCoordinateSpace = vsg::CoordinateSpace::LINEAR; 150 | 151 | // TODO flatShadedShaderSet? 152 | vsg::ref_ptr pbrShaderSet; 153 | vsg::ref_ptr phongShaderSet; 154 | vsg::ref_ptr sharedObjects; 155 | vsg::ref_ptr externalObjects; 156 | 157 | std::vector> convertedMaterials; 158 | std::vector> convertedMeshes; 159 | std::set animationTransforms; 160 | vsg::ref_ptr jointSampler; 161 | vsg::ref_ptr topEmptyTransform; 162 | 163 | SubgraphStats collectSubgraphStats(const aiNode* node, unsigned int depth); 164 | SubgraphStats collectSubgraphStats(const aiScene* in_scene); 165 | 166 | SubgraphStats print(std::ostream& out, const aiAnimation* in_anim, vsg::indentation indent); 167 | SubgraphStats print(std::ostream& out, const aiMaterial* in_material, vsg::indentation indent); 168 | SubgraphStats print(std::ostream& out, const aiMesh* in_mesh, vsg::indentation indent); 169 | SubgraphStats print(std::ostream& out, const aiNode* in_node, vsg::indentation indent); 170 | SubgraphStats print(std::ostream& out, const aiScene* in_scene, vsg::indentation indent); 171 | 172 | vsg::vec3 convert(const aiVector3D& v) { return vsg::vec3(v[0], v[1], v[2]); } 173 | vsg::dvec3 dconvert(const aiVector3D& v) { return vsg::dvec3(v[0], v[1], v[2]); } 174 | vsg::vec3 convert(const aiColor3D& v) { return vsg::vec3(v[0], v[1], v[2]); } 175 | vsg::vec4 convert(const aiColor4D& v) { return vsg::vec4(v[0], v[1], v[2], v[3]); } 176 | 177 | bool getColor(const aiMaterial* material, const char* pKey, unsigned int type, unsigned int idx, vsg::vec3& value) 178 | { 179 | aiColor3D color; 180 | if (material->Get(pKey, type, idx, color) == AI_SUCCESS) 181 | { 182 | value = convert(color); 183 | vsg::convert(value, sourceMaterialColorSpace, targetMaterialCoordinateSpace); 184 | return true; 185 | } 186 | return false; 187 | } 188 | bool getColor(const aiMaterial* material, const char* pKey, unsigned int type, unsigned int idx, vsg::vec4& value) 189 | { 190 | aiColor4D color; 191 | if (material->Get(pKey, type, idx, color) == AI_SUCCESS) 192 | { 193 | value = convert(color); 194 | vsg::convert(value, sourceMaterialColorSpace, targetMaterialCoordinateSpace); 195 | return true; 196 | } 197 | return false; 198 | } 199 | 200 | void processAnimations(); 201 | void processCameras(); 202 | void processLights(); 203 | 204 | vsg::ref_ptr processCoordinateFrame(const vsg::Path& ext); 205 | 206 | VkSamplerAddressMode getWrapMode(aiTextureMapMode mode) const 207 | { 208 | switch (mode) 209 | { 210 | case aiTextureMapMode_Wrap: return VK_SAMPLER_ADDRESS_MODE_REPEAT; 211 | case aiTextureMapMode_Clamp: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 212 | case aiTextureMapMode_Decal: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; 213 | case aiTextureMapMode_Mirror: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; 214 | default: break; 215 | } 216 | return VK_SAMPLER_ADDRESS_MODE_REPEAT; 217 | } 218 | 219 | bool hasAlphaBlend(const aiMaterial* material) const 220 | { 221 | aiString alphaMode; 222 | float opacity = 1.0; 223 | if ((material->Get(AI_MATKEY_GLTF_ALPHAMODE, alphaMode) == AI_SUCCESS && alphaMode == aiString("BLEND")) || (material->Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS && opacity < 1.0)) 224 | return true; 225 | return false; 226 | } 227 | 228 | vsg::ref_ptr getOrCreatePbrShaderSet() 229 | { 230 | if (!pbrShaderSet) 231 | { 232 | pbrShaderSet = vsg::createPhysicsBasedRenderingShaderSet(options); 233 | if (sharedObjects) sharedObjects->share(pbrShaderSet); 234 | } 235 | return pbrShaderSet; 236 | } 237 | 238 | vsg::ref_ptr getOrCreatePhongShaderSet() 239 | { 240 | if (!phongShaderSet) 241 | { 242 | phongShaderSet = vsg::createPhongShaderSet(options); 243 | if (sharedObjects) sharedObjects->share(phongShaderSet); 244 | } 245 | return phongShaderSet; 246 | } 247 | 248 | SamplerData convertTexture(const aiMaterial& material, aiTextureType type) const; 249 | 250 | void convert(const aiMaterial* material, vsg::DescriptorConfigurator& convertedMaterial); 251 | 252 | vsg::ref_ptr createIndices(const aiMesh* mesh, unsigned int numIndicesPerFace, uint32_t numIndices); 253 | void convert(const aiMesh* mesh, vsg::ref_ptr& node); 254 | 255 | vsg::ref_ptr visit(const aiScene* in_scene, vsg::ref_ptr in_options, const vsg::Path& ext); 256 | vsg::ref_ptr visit(const aiNode* node, int depth); 257 | }; 258 | } // namespace vsgXchange 259 | 260 | EVSG_type_name(vsgXchange::TextureFormat) 261 | -------------------------------------------------------------------------------- /src/stbi/stbi.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 André Normann & Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include 23 | 24 | #define STB_IMAGE_STATIC 25 | #define STB_IMAGE_IMPLEMENTATION 26 | #define STB_IMAGE_WRITE_IMPLEMENTATION 27 | 28 | #if defined(__GNUC__) 29 | # pragma GCC diagnostic push 30 | # pragma GCC diagnostic ignored "-Wunused-variable" 31 | # pragma GCC diagnostic ignored "-Wunused-but-set-variable" 32 | # pragma GCC diagnostic ignored "-Wsign-compare" 33 | # pragma GCC diagnostic ignored "-Wunused-function" 34 | #endif 35 | 36 | void* cpp_malloc(size_t size) 37 | { 38 | return vsg::allocate(size, vsg::ALLOCATOR_AFFINITY_DATA); 39 | } 40 | 41 | void cpp_free(void* ptr) 42 | { 43 | vsg::deallocate(ptr); 44 | } 45 | 46 | void* cpp_realloc_sized(void* old_ptr, size_t old_size, size_t new_size) 47 | { 48 | if (!old_ptr) return cpp_malloc(new_size); 49 | 50 | if (old_size >= new_size) return old_ptr; 51 | 52 | void* new_ptr = vsg::allocate(new_size); 53 | 54 | std::memcpy(new_ptr, old_ptr, old_size); 55 | 56 | vsg::deallocate(old_ptr); 57 | 58 | return new_ptr; 59 | } 60 | 61 | // override the stb memory allocation to make it compatible with vsg::Array* use of standard C++ new/delete. 62 | #define STBI_MALLOC(sz) cpp_malloc(sz) 63 | #define STBI_REALLOC(p, newsiz) ERROR_SHOULD_NEVER_BE_CALLED 64 | #define STBI_REALLOC_SIZED(p, oldsz, newsz) cpp_realloc_sized(p, oldsz, newsz) 65 | #define STBI_FREE(p) cpp_free(p) 66 | 67 | #include "stb_image.h" 68 | #include "stb_image_write.h" 69 | 70 | #if defined(__GNUC__) 71 | # pragma GCC diagnostic pop 72 | #endif 73 | 74 | using namespace vsgXchange; 75 | 76 | static void writeToStream(void* context, void* data, int size) 77 | { 78 | reinterpret_cast(context)->write(reinterpret_cast(data), size); 79 | } 80 | 81 | static void process_image_format(vsg::ref_ptr options, VkFormat& format) 82 | { 83 | if (!options) return; 84 | 85 | vsg::CoordinateSpace coordinateSpace; 86 | if (options->getValue(stbi::image_format, coordinateSpace)) 87 | { 88 | if (coordinateSpace == vsg::CoordinateSpace::sRGB) 89 | format = vsg::uNorm_to_sRGB(format); 90 | else if (coordinateSpace == vsg::CoordinateSpace::LINEAR) 91 | format = vsg::sRGB_to_uNorm(format); 92 | } 93 | } 94 | 95 | // if the data is in BGR or BGRA form create a copy that is reformated into RGB or RGBA respectively 96 | static std::pair> reformatForWriting(const vsg::Data* data, const vsg::Path& filename) 97 | { 98 | int num_components = 0; 99 | vsg::ref_ptr local_data; 100 | switch (data->properties.format) 101 | { 102 | case (VK_FORMAT_R8_UNORM): 103 | num_components = 1; 104 | break; 105 | case (VK_FORMAT_R8G8_UNORM): 106 | num_components = 2; 107 | break; 108 | case (VK_FORMAT_R8G8B8_SRGB): 109 | case (VK_FORMAT_R8G8B8_UNORM): 110 | num_components = 3; 111 | break; 112 | case (VK_FORMAT_R8G8B8A8_SRGB): 113 | case (VK_FORMAT_R8G8B8A8_UNORM): 114 | num_components = 4; 115 | break; 116 | case (VK_FORMAT_B8G8R8_SRGB): 117 | case (VK_FORMAT_B8G8R8_UNORM): { 118 | auto dest_data = vsg::ubvec3Array2D::create(data->width(), data->height(), vsg::Data::Properties{VK_FORMAT_R8G8B8_UNORM}); 119 | auto src_ptr = static_cast(data->dataPointer()); 120 | for (auto& dest : *dest_data) 121 | { 122 | auto& src = *(src_ptr++); 123 | dest.set(src[2], src[1], src[0]); 124 | } 125 | 126 | num_components = 3; 127 | local_data = dest_data; 128 | break; 129 | } 130 | case (VK_FORMAT_B8G8R8A8_SRGB): 131 | case (VK_FORMAT_B8G8R8A8_UNORM): { 132 | auto dest_data = vsg::ubvec4Array2D::create(data->width(), data->height(), vsg::Data::Properties{VK_FORMAT_R8G8B8A8_UNORM}); 133 | auto src_ptr = static_cast(data->dataPointer()); 134 | for (auto& dest : *dest_data) 135 | { 136 | auto& src = *(src_ptr++); 137 | dest.set(src[2], src[1], src[0], src[3]); 138 | } 139 | 140 | num_components = 4; 141 | local_data = dest_data; 142 | break; 143 | } 144 | default: 145 | vsg::warn("stbi::write(", data->className(), ", ", filename, ") data format VkFormat(", data->properties.format, ") not supported."); 146 | return {0, {}}; 147 | } 148 | return {num_components, local_data}; 149 | } 150 | 151 | stbi::stbi() : 152 | _supportedExtensions{".jpg", ".jpeg", ".jpe", ".png", ".gif", ".bmp", ".tga", ".psd", ".pgm", ".ppm"} 153 | { 154 | } 155 | 156 | bool stbi::getFeatures(Features& features) const 157 | { 158 | vsg::ReaderWriter::FeatureMask read_mask = static_cast(READ_FILENAME | READ_ISTREAM | READ_MEMORY); 159 | vsg::ReaderWriter::FeatureMask read_write_mask = static_cast(WRITE_FILENAME | WRITE_OSTREAM | READ_FILENAME | READ_ISTREAM | READ_MEMORY); 160 | 161 | features.extensionFeatureMap[".png"] = read_write_mask; 162 | features.extensionFeatureMap[".bmp"] = read_write_mask; 163 | features.extensionFeatureMap[".tga"] = read_write_mask; 164 | features.extensionFeatureMap[".jpg"] = features.extensionFeatureMap[".jpeg"] = features.extensionFeatureMap[".jpe"] = read_write_mask; 165 | 166 | features.extensionFeatureMap[".psd"] = read_mask; 167 | features.extensionFeatureMap[".pgm"] = read_mask; 168 | features.extensionFeatureMap[".ppm"] = read_mask; 169 | 170 | features.optionNameTypeMap[stbi::jpeg_quality] = vsg::type_name(); 171 | features.optionNameTypeMap[stbi::image_format] = vsg::type_name(); 172 | 173 | return true; 174 | } 175 | 176 | bool stbi::readOptions(vsg::Options& options, vsg::CommandLine& arguments) const 177 | { 178 | bool result = arguments.readAndAssign(stbi::jpeg_quality, &options); 179 | result = arguments.readAndAssign(stbi::image_format, &options) | result; 180 | return result; 181 | } 182 | 183 | vsg::ref_ptr stbi::read(const vsg::Path& filename, vsg::ref_ptr options) const 184 | { 185 | if (!vsg::compatibleExtension(filename, options, _supportedExtensions)) return {}; 186 | 187 | vsg::Path filenameToUse = findFile(filename, options); 188 | if (!filenameToUse) return {}; 189 | 190 | int width, height, channels; 191 | 192 | auto file = vsg::fopen(filenameToUse, "rb"); 193 | if (!file) return {}; 194 | 195 | const auto pixels = stbi_load_from_file(file, &width, &height, &channels, STBI_rgb_alpha); 196 | 197 | fclose(file); 198 | 199 | if (pixels) 200 | { 201 | auto vsg_data = vsg::ubvec4Array2D::create(width, height, reinterpret_cast(pixels), vsg::Data::Properties{VK_FORMAT_R8G8B8A8_SRGB}); 202 | process_image_format(options, vsg_data->properties.format); 203 | return vsg_data; 204 | } 205 | 206 | return {}; 207 | } 208 | 209 | vsg::ref_ptr stbi::read(std::istream& fin, vsg::ref_ptr options) const 210 | { 211 | if (!vsg::compatibleExtension(options, _supportedExtensions)) return {}; 212 | 213 | std::string buffer(1 << 16, 0); // 64kB 214 | std::string input; 215 | 216 | while (!fin.eof()) 217 | { 218 | fin.read(&buffer[0], buffer.size()); 219 | const auto bytes_readed = fin.gcount(); 220 | input.append(&buffer[0], bytes_readed); 221 | } 222 | 223 | int width, height, channels; 224 | const auto pixels = stbi_load_from_memory(reinterpret_cast(input.data()), static_cast(input.size()), &width, &height, &channels, STBI_rgb_alpha); 225 | if (pixels) 226 | { 227 | auto vsg_data = vsg::ubvec4Array2D::create(width, height, reinterpret_cast(pixels), vsg::Data::Properties{VK_FORMAT_R8G8B8A8_SRGB}); 228 | process_image_format(options, vsg_data->properties.format); 229 | return vsg_data; 230 | } 231 | 232 | return {}; 233 | } 234 | 235 | vsg::ref_ptr stbi::read(const uint8_t* ptr, size_t size, vsg::ref_ptr options) const 236 | { 237 | if (!vsg::compatibleExtension(options, _supportedExtensions)) return {}; 238 | 239 | int width, height, channels; 240 | const auto pixels = stbi_load_from_memory(reinterpret_cast(ptr), static_cast(size), &width, &height, &channels, STBI_rgb_alpha); 241 | if (pixels) 242 | { 243 | auto vsg_data = vsg::ubvec4Array2D::create(width, height, reinterpret_cast(pixels), vsg::Data::Properties{VK_FORMAT_R8G8B8A8_SRGB}); 244 | process_image_format(options, vsg_data->properties.format); 245 | return vsg_data; 246 | } 247 | 248 | return {}; 249 | } 250 | 251 | bool stbi::write(const vsg::Object* object, std::ostream& stream, vsg::ref_ptr options) const 252 | { 253 | const auto ext = options->extensionHint; 254 | if (_supportedExtensions.count(ext) == 0) 255 | { 256 | return false; 257 | } 258 | 259 | auto data = object->cast(); 260 | if (!data) return false; 261 | 262 | // if we need to swizzle the image we'll need to allocate a temporary vsg::Data to store the swizzled data 263 | auto [num_components, local_data] = reformatForWriting(data, {}); 264 | if (num_components == 0) return false; 265 | if (local_data) data = local_data.get(); 266 | 267 | int result = 0; 268 | if (ext == ".png") 269 | { 270 | result = stbi_write_png_to_func(&writeToStream, &stream, data->width(), data->height(), num_components, data->dataPointer(), data->properties.stride * data->width()); 271 | } 272 | else if (ext == ".bmp") 273 | { 274 | result = stbi_write_bmp_to_func(&writeToStream, &stream, data->width(), data->height(), num_components, data->dataPointer()); 275 | } 276 | else if (ext == ".tga") 277 | { 278 | result = stbi_write_tga_to_func(&writeToStream, &stream, data->width(), data->height(), num_components, data->dataPointer()); 279 | } 280 | else if (ext == ".jpg" || ext == ".jpeg" || ext == ".jpe") 281 | { 282 | int quality = 100; 283 | if (options) 284 | { 285 | options->getValue(stbi::jpeg_quality, quality); 286 | } 287 | result = stbi_write_jpg_to_func(&writeToStream, &stream, data->width(), data->height(), num_components, data->dataPointer(), quality); 288 | } 289 | return result == 1; 290 | } 291 | 292 | bool stbi::write(const vsg::Object* object, const vsg::Path& filename, vsg::ref_ptr options) const 293 | { 294 | const auto ext = vsg::lowerCaseFileExtension(filename); 295 | if (_supportedExtensions.count(ext) == 0) 296 | { 297 | return false; 298 | } 299 | 300 | auto data = object->cast(); 301 | if (!data) return false; 302 | 303 | // if we need to swizzle the image we'll need to allocate a temporary vsg::Data to store the swizzled data 304 | auto [num_components, local_data] = reformatForWriting(data, filename); 305 | if (num_components == 0) return false; 306 | if (local_data) data = local_data.get(); 307 | 308 | // convert to utf8 std::string 309 | std::string filename_str = filename.string(); 310 | int result = 0; 311 | if (ext == ".png") 312 | { 313 | result = stbi_write_png(filename_str.c_str(), data->width(), data->height(), num_components, data->dataPointer(), data->properties.stride * data->width()); 314 | } 315 | else if (ext == ".bmp") 316 | { 317 | result = stbi_write_bmp(filename_str.c_str(), data->width(), data->height(), num_components, data->dataPointer()); 318 | } 319 | else if (ext == ".tga") 320 | { 321 | result = stbi_write_tga(filename_str.c_str(), data->width(), data->height(), num_components, data->dataPointer()); 322 | } 323 | else if (ext == ".jpg" || ext == ".jpeg" || ext == ".jpe") 324 | { 325 | int quality = 100; 326 | if (options) 327 | { 328 | options->getValue(stbi::jpeg_quality, quality); 329 | } 330 | result = stbi_write_jpg(filename_str.c_str(), data->width(), data->height(), num_components, data->dataPointer(), quality); 331 | } 332 | 333 | return result == 1; 334 | } 335 | -------------------------------------------------------------------------------- /src/3DTiles/SceneGraphBuilder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2025 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shimages be included in images 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | */ 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | using namespace vsgXchange; 46 | 47 | Tiles3D::SceneGraphBuilder::SceneGraphBuilder() 48 | { 49 | } 50 | 51 | vsg::dmat4 Tiles3D::SceneGraphBuilder::createMatrix(const std::vector& m) 52 | { 53 | if (m.size() == 16) 54 | { 55 | return vsg::dmat4(m[0], m[1], m[2], m[3], 56 | m[4], m[5], m[6], m[7], 57 | m[8], m[9], m[10], m[11], 58 | m[12], m[13], m[14], m[15]); 59 | } 60 | else 61 | { 62 | return {}; 63 | } 64 | } 65 | 66 | vsg::dsphere Tiles3D::SceneGraphBuilder::createBound(vsg::ref_ptr boundingVolume) 67 | { 68 | if (boundingVolume) 69 | { 70 | if (boundingVolume->box.values.size() == 12) 71 | { 72 | const auto& v = boundingVolume->box.values; 73 | vsg::dvec3 axis_x(v[3], v[4], v[5]); 74 | vsg::dvec3 axis_y(v[6], v[7], v[8]); 75 | vsg::dvec3 axis_z(v[9], v[10], v[11]); 76 | return vsg::dsphere(v[0], v[1], v[2], vsg::length(axis_x + axis_y + axis_z)); 77 | } 78 | else if (boundingVolume->region.values.size() == 6) 79 | { 80 | const auto& v = boundingVolume->region.values; 81 | double west = v[0], south = v[1], east = v[2], north = v[3], low = v[4], high = v[5]; 82 | auto centerECEF = ellipsoidModel->convertLatLongAltitudeToECEF(vsg::dvec3(vsg::degrees(south + north) * 0.5, vsg::degrees(west + east) * 0.5, (high + low) * 0.5)); 83 | auto southWestLowECEF = ellipsoidModel->convertLatLongAltitudeToECEF(vsg::dvec3(vsg::degrees(south), vsg::degrees(west), low)); 84 | auto northEastLowECEF = ellipsoidModel->convertLatLongAltitudeToECEF(vsg::dvec3(vsg::degrees(north), vsg::degrees(east), low)); 85 | 86 | // TODO: do we need to track the accumulated transform? 87 | return vsg::dsphere(centerECEF, std::max(vsg::length(southWestLowECEF - centerECEF), vsg::length(northEastLowECEF - centerECEF))); 88 | } 89 | else if (boundingVolume->sphere.values.size() == 4) 90 | { 91 | const auto& v = boundingVolume->box.values; 92 | return vsg::dsphere(v[0], v[1], v[2], v[3]); 93 | } 94 | else 95 | { 96 | vsg::info("createBound() Unhandled boundingVolume type"); 97 | vsg::LogOutput output; 98 | boundingVolume->report(output); 99 | return {}; 100 | } 101 | } 102 | else 103 | { 104 | return {}; 105 | } 106 | } 107 | 108 | vsg::ref_ptr Tiles3D::SceneGraphBuilder::readTileChildren(vsg::ref_ptr tile, uint32_t level, const std::string& inherited_refine) 109 | { 110 | // vsg::info("readTileChildren(", tile, ", ", level, ") ", tile->children.values.size(), ", ", operationThreads); 111 | 112 | auto group = vsg::Group::create(); 113 | 114 | const std::string refine = tile->refine.empty() ? inherited_refine : tile->refine; 115 | 116 | if (refine == "ADD") 117 | { 118 | if (auto local_subgraph = tile->getRefObject("local_subgraph")) 119 | { 120 | group->addChild(local_subgraph); 121 | } 122 | } 123 | 124 | if (operationThreads && tile->children.values.size() > 1) 125 | { 126 | struct ReadTileOperation : public vsg::Inherit 127 | { 128 | SceneGraphBuilder* builder; 129 | vsg::ref_ptr tileToCreate; 130 | vsg::ref_ptr& subgraph; 131 | uint32_t level; 132 | std::string rto_inherited_refine; 133 | vsg::ref_ptr latch; 134 | 135 | ReadTileOperation(SceneGraphBuilder* in_builder, vsg::ref_ptr in_tile, vsg::ref_ptr& in_subgraph, uint32_t in_level, const std::string& in_inherited_refine, vsg::ref_ptr in_latch) : 136 | builder(in_builder), 137 | tileToCreate(in_tile), 138 | subgraph(in_subgraph), 139 | level(in_level), 140 | rto_inherited_refine(in_inherited_refine), 141 | latch(in_latch) {} 142 | 143 | void run() override 144 | { 145 | subgraph = builder->createTile(tileToCreate, level, rto_inherited_refine); 146 | // vsg::info("Tiles3D::SceneGraphBuilder::readTileChildren() createTile() ", subgraph); 147 | if (latch) latch->count_down(); 148 | } 149 | }; 150 | 151 | auto latch = vsg::Latch::create(static_cast(tile->children.values.size())); 152 | 153 | std::vector> children(tile->children.values.size()); 154 | auto itr = children.begin(); 155 | for (auto child : tile->children.values) 156 | { 157 | operationThreads->add(ReadTileOperation::create(this, child, *itr++, level + 1, refine, latch), vsg::INSERT_FRONT); 158 | } 159 | 160 | // use this thread to read the files as well 161 | operationThreads->run(); 162 | 163 | // wait till all the read operations have completed 164 | latch->wait(); 165 | 166 | for (auto& child : children) 167 | { 168 | if (child) 169 | { 170 | group->addChild(child); 171 | } 172 | else 173 | vsg::info("Failed to read child"); 174 | } 175 | } 176 | else 177 | { 178 | for (auto child : tile->children.values) 179 | { 180 | if (auto vsg_child = createTile(child, level + 1, refine)) 181 | { 182 | group->addChild(vsg_child); 183 | } 184 | } 185 | } 186 | 187 | vsg::ref_ptr root; 188 | if (group->children.size() == 1) root = group->children[0]; 189 | else root = group; 190 | 191 | assignResourceHints(root); 192 | 193 | return root; 194 | } 195 | 196 | vsg::ref_ptr Tiles3D::SceneGraphBuilder::createTile(vsg::ref_ptr tile, uint32_t level, const std::string& inherited_refine) 197 | { 198 | #if 0 199 | vsg::info("Tiles3D::createTile() {"); 200 | vsg::info(" boundingVolume = ", tile->boundingVolume); 201 | vsg::info(" viewerRequestVolume = ", tile->viewerRequestVolume); 202 | vsg::info(" tile->content = ", tile->geometricError); 203 | vsg::info(" refine = ", tile->refine); 204 | vsg::info(" transform = ", tile->transform.values); 205 | vsg::info(" content = ", tile->content); 206 | #endif 207 | 208 | vsg::dsphere bound = createBound(tile->boundingVolume); 209 | 210 | vsg::ref_ptr local_subgraph; 211 | 212 | if (tile->content && !tile->content->uri.empty()) 213 | { 214 | if (auto model = vsg::read_cast(tile->content->uri, options)) 215 | { 216 | local_subgraph = model; 217 | } 218 | } 219 | 220 | vsg::ref_ptr vsg_transform; 221 | if (!tile->transform.values.empty()) 222 | { 223 | vsg_transform = vsg::MatrixTransform::create(createMatrix(tile->transform.values)); 224 | } 225 | 226 | bool usePagedLOD = level > preLoadLevel; 227 | 228 | const std::string refine = tile->refine.empty() ? inherited_refine : tile->refine; 229 | 230 | if (refine == "ADD" && local_subgraph) 231 | { 232 | // need to pass on Tile local_subgraph to the SceneGraphBuilder::readTileChildren(..) so assign it to Tile as meta data 233 | tile->setObject("local_subgraph", local_subgraph); 234 | } 235 | 236 | if (tile->children.values.empty()) 237 | { 238 | if (local_subgraph) 239 | { 240 | if (vsg_transform) 241 | { 242 | vsg_transform->addChild(local_subgraph); 243 | return vsg_transform; 244 | } 245 | else 246 | { 247 | return local_subgraph; 248 | } 249 | } 250 | return {}; 251 | } 252 | else if (usePagedLOD) 253 | { 254 | double minimumScreenHeightRatio = 0.5; 255 | if (tile->geometricError > 0.0) 256 | { 257 | minimumScreenHeightRatio = (bound.radius / tile->geometricError) * pixelErrorToScreenHeightRatio; 258 | } 259 | 260 | auto plod = vsg::PagedLOD::create(); 261 | plod->bound = bound; 262 | plod->children[0] = vsg::PagedLOD::Child{minimumScreenHeightRatio, {}}; 263 | plod->children[1] = vsg::PagedLOD::Child{0.0, local_subgraph}; 264 | 265 | plod->filename = "children.tiles"; 266 | 267 | auto load_options = vsg::clone(options); 268 | load_options->setObject("tile", tile); 269 | load_options->setObject("builder", vsg::ref_ptr(this)); 270 | load_options->setValue("level", level); 271 | load_options->setValue("refine", refine); 272 | plod->options = load_options; 273 | 274 | return plod; 275 | } 276 | else // use LOD 277 | { 278 | auto highres_subgraph = readTileChildren(tile, level, refine); 279 | 280 | double minimumScreenHeightRatio = 0.5; 281 | if (tile->geometricError > 0.0) 282 | { 283 | minimumScreenHeightRatio = (bound.radius / tile->geometricError) * pixelErrorToScreenHeightRatio; 284 | } 285 | 286 | auto lod = vsg::LOD::create(); 287 | lod->bound = bound; 288 | lod->addChild(vsg::LOD::Child{minimumScreenHeightRatio, highres_subgraph}); 289 | if (local_subgraph) lod->addChild(vsg::LOD::Child{0.0, local_subgraph}); 290 | 291 | if (vsg_transform) 292 | { 293 | vsg_transform->addChild(lod); 294 | return vsg_transform; 295 | } 296 | else 297 | { 298 | return lod; 299 | } 300 | } 301 | return {}; 302 | } 303 | 304 | vsg::ref_ptr Tiles3D::SceneGraphBuilder::createSceneGraph(vsg::ref_ptr tileset, vsg::ref_ptr in_options) 305 | { 306 | if (!tileset) return {}; 307 | 308 | if (in_options) 309 | options = vsg::clone(in_options); 310 | else 311 | options = vsg::Options::create(); 312 | 313 | if (options) 314 | { 315 | sharedObjects = options->sharedObjects; 316 | operationThreads = options->operationThreads; 317 | if (operationThreads) options->operationThreads.reset(); 318 | } 319 | 320 | if (!sharedObjects) 321 | { 322 | options->sharedObjects = sharedObjects = vsg::SharedObjects::create(); 323 | } 324 | 325 | if (!shaderSet) 326 | { 327 | shaderSet = vsg::createPhysicsBasedRenderingShaderSet(options); 328 | sharedObjects->share(shaderSet); 329 | } 330 | 331 | vsg::ref_ptr vsg_tileset; 332 | 333 | bool inheritState = options->inheritedState.empty(); 334 | if (inheritState) 335 | { 336 | auto stateGroup = vsg::StateGroup::create(); 337 | auto layout = shaderSet->createPipelineLayout({}, {0, 1}); 338 | 339 | uint32_t vds_set = 0; 340 | stateGroup->add(vsg::BindViewDescriptorSets::create(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, vds_set)); 341 | 342 | options->inheritedState = stateGroup->stateCommands; 343 | 344 | vsg_tileset = stateGroup; 345 | } 346 | else 347 | { 348 | vsg_tileset = vsg::Group::create(); 349 | } 350 | 351 | // vsg_tileset->setObject("tileset", tileset); 352 | 353 | if (tileset->root) 354 | { 355 | if (auto vsg_root = createTile(tileset->root, 0, tileset->root->refine)) 356 | { 357 | vsg_tileset->addChild(vsg_root); 358 | } 359 | } 360 | 361 | vsg_tileset->setObject("EllipsoidModel", vsg::EllipsoidModel::create()); 362 | 363 | assignResourceHints(vsg_tileset); 364 | 365 | return vsg_tileset; 366 | } 367 | 368 | void Tiles3D::SceneGraphBuilder::assignResourceHints(vsg::ref_ptr node) 369 | { 370 | vsg::CollectResourceRequirements collectRequirements; 371 | node->accept(collectRequirements); 372 | 373 | auto resourceHints = collectRequirements.createResourceHints(); 374 | node->setObject("ResourceHints", resourceHints); 375 | } 376 | -------------------------------------------------------------------------------- /src/gdal/gdal_utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | using namespace vsgXchange; 35 | 36 | static bool s_GDAL_initialized = false; 37 | bool vsgXchange::initGDAL() 38 | { 39 | if (!s_GDAL_initialized) 40 | { 41 | s_GDAL_initialized = true; 42 | GDALAllRegister(); 43 | CPLPushErrorHandler(CPLQuietErrorHandler); 44 | return true; 45 | } 46 | else 47 | { 48 | return false; 49 | } 50 | } 51 | 52 | bool vsgXchange::compatibleDatasetProjections(const GDALDataset& lhs, const GDALDataset& rhs) 53 | { 54 | if (&lhs == &rhs) return true; 55 | 56 | const auto lhs_projectionRef = const_cast(lhs).GetProjectionRef(); 57 | const auto rhs_projectionRef = const_cast(rhs).GetProjectionRef(); 58 | 59 | // if pointers are the same then they are compatible 60 | if (lhs_projectionRef == rhs_projectionRef) return true; 61 | 62 | // if one of the pointers is NULL then they are incompatible 63 | if (!lhs_projectionRef || !rhs_projectionRef) return false; 64 | 65 | // check if the OGRSpatialReference are the same 66 | return (std::strcmp(lhs_projectionRef, rhs_projectionRef) == 0); 67 | } 68 | 69 | bool vsgXchange::compatibleDatasetProjectionsTransformAndSizes(const GDALDataset& lhs, const GDALDataset& rhs) 70 | { 71 | if (!compatibleDatasetProjections(lhs, rhs)) return false; 72 | 73 | auto& non_const_lhs = const_cast(lhs); 74 | auto& non_const_rhs = const_cast(rhs); 75 | 76 | if (non_const_lhs.GetRasterXSize() != non_const_rhs.GetRasterXSize() || non_const_lhs.GetRasterYSize() != non_const_rhs.GetRasterYSize()) 77 | { 78 | return false; 79 | } 80 | 81 | double lhs_GeoTransform[6]; 82 | double rhs_GeoTransform[6]; 83 | 84 | int numberWithValidTransforms = 0; 85 | if (non_const_lhs.GetGeoTransform(lhs_GeoTransform) == CE_None) ++numberWithValidTransforms; 86 | if (non_const_rhs.GetGeoTransform(rhs_GeoTransform) == CE_None) ++numberWithValidTransforms; 87 | 88 | // if neither have transforms mark as compatible 89 | if (numberWithValidTransforms == 0) return true; 90 | 91 | // only one has a transform so must be incompatible 92 | if (numberWithValidTransforms == 1) return false; 93 | 94 | for (int i = 0; i < 6; ++i) 95 | { 96 | if (lhs_GeoTransform[i] != rhs_GeoTransform[i]) 97 | { 98 | return false; 99 | } 100 | } 101 | return true; 102 | } 103 | 104 | template 105 | T default_value(double scale) 106 | { 107 | if (std::numeric_limits::is_integer) 108 | { 109 | if (scale < 0.0) 110 | return std::numeric_limits::min(); 111 | else if (scale > 0.0) 112 | return std::numeric_limits::max(); 113 | return static_cast(0); 114 | } 115 | else 116 | { 117 | return static_cast(scale); 118 | } 119 | } 120 | 121 | template 122 | vsg::t_vec2 default_vec2(const vsg::dvec4& value) 123 | { 124 | return vsg::t_vec2(default_value(value[0]), default_value(value[1])); 125 | } 126 | 127 | template 128 | vsg::t_vec3 default_vec3(const vsg::dvec4& value) 129 | { 130 | return vsg::t_vec3(default_value(value[0]), default_value(value[1]), default_value(value[2])); 131 | } 132 | 133 | template 134 | vsg::t_vec4 default_vec4(const vsg::dvec4& value) 135 | { 136 | return vsg::t_vec4(default_value(value[0]), default_value(value[1]), default_value(value[2]), default_value(value[3])); 137 | } 138 | 139 | vsg::ref_ptr vsgXchange::createImage2D(int width, int height, int numComponents, GDALDataType dataType, vsg::dvec4 def) 140 | { 141 | using TypeComponents = std::pair; 142 | using CreateFunction = std::function(uint32_t w, uint32_t h, vsg::dvec4 def)>; 143 | 144 | std::map createMap; 145 | createMap[TypeComponents(GDT_Byte, 1)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::ubyteArray2D::create(w, h, default_value(d[0]), vsg::Data::Properties{VK_FORMAT_R8_UNORM}); }; 146 | createMap[TypeComponents(GDT_UInt16, 1)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::ushortArray2D::create(w, h, default_value(d[0]), vsg::Data::Properties{VK_FORMAT_R16_UNORM}); }; 147 | createMap[TypeComponents(GDT_Int16, 1)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::shortArray2D::create(w, h, default_value(d[0]), vsg::Data::Properties{VK_FORMAT_R16_SNORM}); }; 148 | createMap[TypeComponents(GDT_UInt32, 1)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::uintArray2D::create(w, h, default_value(d[0]), vsg::Data::Properties{VK_FORMAT_R32_UINT}); }; 149 | createMap[TypeComponents(GDT_Int32, 1)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::intArray2D::create(w, h, default_value(d[0]), vsg::Data::Properties{VK_FORMAT_R32_SINT}); }; 150 | createMap[TypeComponents(GDT_Float32, 1)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::floatArray2D::create(w, h, default_value(d[0]), vsg::Data::Properties{VK_FORMAT_R32_SFLOAT}); }; 151 | createMap[TypeComponents(GDT_Float64, 1)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::doubleArray2D::create(w, h, default_value(d[0]), vsg::Data::Properties{VK_FORMAT_R64_SFLOAT}); }; 152 | 153 | createMap[TypeComponents(GDT_Byte, 2)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::ubvec2Array2D::create(w, h, default_vec2(d), vsg::Data::Properties{VK_FORMAT_R8G8_UNORM}); }; 154 | createMap[TypeComponents(GDT_UInt16, 2)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::usvec2Array2D::create(w, h, default_vec2(d), vsg::Data::Properties{VK_FORMAT_R16G16_UNORM}); }; 155 | createMap[TypeComponents(GDT_Int16, 2)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::svec2Array2D::create(w, h, default_vec2(d), vsg::Data::Properties{VK_FORMAT_R16G16_SNORM}); }; 156 | createMap[TypeComponents(GDT_UInt32, 2)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::uivec2Array2D::create(w, h, default_vec2(d), vsg::Data::Properties{VK_FORMAT_R32G32_UINT}); }; 157 | createMap[TypeComponents(GDT_Int32, 2)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::ivec2Array2D::create(w, h, default_vec2(d), vsg::Data::Properties{VK_FORMAT_R32G32_SINT}); }; 158 | createMap[TypeComponents(GDT_Float32, 2)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::vec2Array2D::create(w, h, default_vec2(d), vsg::Data::Properties{VK_FORMAT_R32G32_SFLOAT}); }; 159 | createMap[TypeComponents(GDT_Float64, 2)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::dvec2Array2D::create(w, h, default_vec2(d), vsg::Data::Properties{VK_FORMAT_R64G64_SFLOAT}); }; 160 | 161 | createMap[TypeComponents(GDT_Byte, 3)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::ubvec3Array2D::create(w, h, default_vec3(d), vsg::Data::Properties{VK_FORMAT_R8G8B8_UNORM}); }; 162 | createMap[TypeComponents(GDT_UInt16, 3)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::usvec3Array2D::create(w, h, default_vec3(d), vsg::Data::Properties{VK_FORMAT_R16G16B16_UNORM}); }; 163 | createMap[TypeComponents(GDT_Int16, 3)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::svec3Array2D::create(w, h, default_vec3(d), vsg::Data::Properties{VK_FORMAT_R16G16B16_SNORM}); }; 164 | createMap[TypeComponents(GDT_UInt32, 3)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::uivec3Array2D::create(w, h, default_vec3(d), vsg::Data::Properties{VK_FORMAT_R32G32B32_UINT}); }; 165 | createMap[TypeComponents(GDT_Int32, 3)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::ivec3Array2D::create(w, h, default_vec3(d), vsg::Data::Properties{VK_FORMAT_R32G32B32_SINT}); }; 166 | createMap[TypeComponents(GDT_Float32, 3)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::vec3Array2D::create(w, h, default_vec3(d), vsg::Data::Properties{VK_FORMAT_R32G32B32_SFLOAT}); }; 167 | createMap[TypeComponents(GDT_Float64, 3)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::dvec3Array2D::create(w, h, default_vec3(d), vsg::Data::Properties{VK_FORMAT_R64G64B64_SFLOAT}); }; 168 | 169 | createMap[TypeComponents(GDT_Byte, 4)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::ubvec4Array2D::create(w, h, default_vec4(d), vsg::Data::Properties{VK_FORMAT_R8G8B8A8_UNORM}); }; 170 | createMap[TypeComponents(GDT_UInt16, 4)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::usvec4Array2D::create(w, h, default_vec4(d), vsg::Data::Properties{VK_FORMAT_R16G16B16A16_UNORM}); }; 171 | createMap[TypeComponents(GDT_Int16, 4)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::svec4Array2D::create(w, h, default_vec4(d), vsg::Data::Properties{VK_FORMAT_R16G16B16A16_SNORM}); }; 172 | createMap[TypeComponents(GDT_UInt32, 4)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::uivec4Array2D::create(w, h, default_vec4(d), vsg::Data::Properties{VK_FORMAT_R32G32B32A32_UINT}); }; 173 | createMap[TypeComponents(GDT_Int32, 4)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::ivec4Array2D::create(w, h, default_vec4(d), vsg::Data::Properties{VK_FORMAT_R32G32B32A32_SINT}); }; 174 | createMap[TypeComponents(GDT_Float32, 4)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::vec4Array2D::create(w, h, default_vec4(d), vsg::Data::Properties{VK_FORMAT_R32G32B32A32_SFLOAT}); }; 175 | createMap[TypeComponents(GDT_Float64, 4)] = [](uint32_t w, uint32_t h, vsg::dvec4 d) { return vsg::dvec4Array2D::create(w, h, default_vec4(d), vsg::Data::Properties{VK_FORMAT_R64G64B64A64_SFLOAT}); }; 176 | 177 | auto itr = createMap.find(TypeComponents(dataType, numComponents)); 178 | if (itr == createMap.end()) 179 | { 180 | return {}; 181 | } 182 | 183 | return (itr->second)(width, height, def); 184 | } 185 | 186 | bool vsgXchange::copyRasterBandToImage(GDALRasterBand& band, vsg::Data& image, int component) 187 | { 188 | if (image.width() != static_cast(band.GetXSize()) || image.height() != static_cast(band.GetYSize())) 189 | { 190 | return false; 191 | } 192 | 193 | int dataSize = 0; 194 | switch (band.GetRasterDataType()) 195 | { 196 | case (GDT_Byte): dataSize = 1; break; 197 | case (GDT_UInt16): 198 | case (GDT_Int16): dataSize = 2; break; 199 | case (GDT_UInt32): 200 | case (GDT_Int32): 201 | case (GDT_Float32): dataSize = 4; break; 202 | case (GDT_Float64): dataSize = 8; break; 203 | default: 204 | return false; 205 | } 206 | 207 | int offset = dataSize * component; 208 | int stride = image.properties.stride; 209 | 210 | int nBlockXSize, nBlockYSize; 211 | band.GetBlockSize(&nBlockXSize, &nBlockYSize); 212 | 213 | int nXBlocks = (band.GetXSize() + nBlockXSize - 1) / nBlockXSize; 214 | int nYBlocks = (band.GetYSize() + nBlockYSize - 1) / nBlockYSize; 215 | 216 | uint8_t* block = new uint8_t[dataSize * nBlockXSize * nBlockYSize]; 217 | 218 | for (int iYBlock = 0; iYBlock < nYBlocks; iYBlock++) 219 | { 220 | for (int iXBlock = 0; iXBlock < nXBlocks; iXBlock++) 221 | { 222 | int nXValid, nYValid; 223 | CPLErr result = band.ReadBlock(iXBlock, iYBlock, block); 224 | if (result == 0) 225 | { 226 | // Compute the portion of the block that is valid 227 | // for partial edge blocks. 228 | band.GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid); 229 | 230 | for (int iY = 0; iY < nYValid; iY++) 231 | { 232 | uint8_t* dest_ptr = reinterpret_cast(image.dataPointer(iXBlock * nBlockXSize + (iYBlock * nBlockYSize + iY) * image.width())) + offset; 233 | uint8_t* source_ptr = block + iY * nBlockXSize * dataSize; 234 | 235 | for (int iX = 0; iX < nXValid; iX++) 236 | { 237 | for (int c = 0; c < dataSize; ++c) 238 | { 239 | dest_ptr[c] = *source_ptr; 240 | ++source_ptr; 241 | } 242 | 243 | dest_ptr += stride; 244 | } 245 | } 246 | } 247 | } 248 | } 249 | delete[] block; 250 | 251 | return true; 252 | } 253 | 254 | bool vsgXchange::assignMetaData(GDALDataset& dataset, vsg::Object& object) 255 | { 256 | auto metaData = dataset.GetMetadata(); 257 | if (!metaData) return false; 258 | 259 | for (auto ptr = metaData; *ptr != 0; ++ptr) 260 | { 261 | std::string line(*ptr); 262 | auto equal_pos = line.find('='); 263 | if (equal_pos == std::string::npos) 264 | { 265 | object.setValue(line, std::string()); 266 | } 267 | else 268 | { 269 | object.setValue(line.substr(0, equal_pos), line.substr(equal_pos + 1, std::string::npos)); 270 | } 271 | } 272 | return true; 273 | } 274 | -------------------------------------------------------------------------------- /include/vsgXchange/3DTiles.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | 5 | Copyright(c) 2025 Robert Osfield 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shimages be included in images 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | */ 25 | 26 | #include 27 | 28 | #include 29 | 30 | namespace vsgXchange 31 | { 32 | 33 | /// 3DTiles ReaderWriter, C++ won't handle class called 3DTiles so make do with Tiles3D. 34 | /// Specs for 3DTiles https://github.com/CesiumGS/3d-tiles 35 | class VSGXCHANGE_DECLSPEC Tiles3D : public vsg::Inherit 36 | { 37 | public: 38 | Tiles3D(); 39 | 40 | vsg::ref_ptr read(const vsg::Path&, vsg::ref_ptr) const override; 41 | vsg::ref_ptr read(std::istream&, vsg::ref_ptr) const override; 42 | vsg::ref_ptr read(const uint8_t* ptr, size_t size, vsg::ref_ptr options = {}) const override; 43 | 44 | vsg::ref_ptr read_json(std::istream&, vsg::ref_ptr, const vsg::Path& filename = {}) const; 45 | vsg::ref_ptr read_b3dm(std::istream&, vsg::ref_ptr, const vsg::Path& filename = {}) const; 46 | vsg::ref_ptr read_cmpt(std::istream&, vsg::ref_ptr, const vsg::Path& filename = {}) const; 47 | vsg::ref_ptr read_i3dm(std::istream&, vsg::ref_ptr, const vsg::Path& filename = {}) const; 48 | vsg::ref_ptr read_pnts(std::istream&, vsg::ref_ptr, const vsg::Path& filename = {}) const; 49 | vsg::ref_ptr read_tiles(const vsg::Path& filename, vsg::ref_ptr options) const; 50 | 51 | vsg::Logger::Level level = vsg::Logger::LOGGER_WARN; 52 | 53 | bool supportedExtension(const vsg::Path& ext) const; 54 | 55 | bool getFeatures(Features& features) const override; 56 | 57 | static constexpr const char* report = "report"; /// bool, report parsed glTF to console, defaults to false 58 | static constexpr const char* instancing = "instancing"; /// bool, hint for using vsg::InstanceNode/InstanceDraw for instancing where possible. 59 | static constexpr const char* pixel_ratio = "pixel_ratio"; /// double, sets the SceneGraphBuilder::pixelErrorToScreenHeightRatio value used for setting LOD ranges. 60 | static constexpr const char* pre_load_level = "pre_load_level"; /// uint, sets the SceneGraphBuilder::preLoadLevel values to control what LOD level are pre loaded when reading a tileset. 61 | 62 | bool readOptions(vsg::Options& options, vsg::CommandLine& arguments) const override; 63 | 64 | public: 65 | /// https://github.com/CesiumGS/3d-tiles/blob/1.0/specification/schema/boundingVolume.schema.json 66 | struct VSGXCHANGE_DECLSPEC BoundingVolume : public vsg::Inherit 67 | { 68 | vsg::ValuesSchema box; 69 | vsg::ValuesSchema region; 70 | vsg::ValuesSchema sphere; 71 | 72 | void read_array(vsg::JSONParser& parser, const std::string_view& property) override; 73 | 74 | void report(vsg::LogOutput& output); 75 | }; 76 | 77 | /// https://github.com/CesiumGS/3d-tiles/blob/1.0/specification/schema/tile.content.schema.json 78 | struct VSGXCHANGE_DECLSPEC Content : public vsg::Inherit 79 | { 80 | vsg::ref_ptr boundingVolume; 81 | std::string uri; 82 | 83 | // loaded from uri 84 | vsg::ref_ptr object; 85 | 86 | void read_object(vsg::JSONParser& parser, const std::string_view& property) override; 87 | void read_string(vsg::JSONParser& parser, const std::string_view& property) override; 88 | 89 | void report(vsg::LogOutput& output); 90 | }; 91 | 92 | /// https://github.com/CesiumGS/3d-tiles/blob/1.0/specification/schema/tile.schema.json 93 | struct VSGXCHANGE_DECLSPEC Tile : public vsg::Inherit 94 | { 95 | vsg::ref_ptr boundingVolume; 96 | vsg::ref_ptr viewerRequestVolume; 97 | double geometricError = 0.0; 98 | std::string refine; 99 | vsg::ValuesSchema transform; 100 | vsg::ObjectsSchema children; 101 | vsg::ref_ptr content; 102 | 103 | void read_array(vsg::JSONParser& parser, const std::string_view& property) override; 104 | void read_object(vsg::JSONParser& parser, const std::string_view& property) override; 105 | void read_number(vsg::JSONParser& parser, const std::string_view& property, std::istream& input) override; 106 | void read_string(vsg::JSONParser& parser, const std::string_view& property) override; 107 | 108 | void report(vsg::LogOutput& output); 109 | }; 110 | 111 | /// https://github.com/CesiumGS/3d-tiles/blob/1.0/specification/schema/properties.schema.json 112 | struct VSGXCHANGE_DECLSPEC PropertyRange : public vsg::Inherit 113 | { 114 | double minimum = 0.0; 115 | double maximum = 0.0; 116 | 117 | void read_number(vsg::JSONParser& parser, const std::string_view& property, std::istream& input) override; 118 | }; 119 | 120 | struct VSGXCHANGE_DECLSPEC Properties : public vsg::Inherit 121 | { 122 | std::map properties; 123 | 124 | void read_object(vsg::JSONParser& parser, const std::string_view& property_name) override; 125 | 126 | void report(vsg::LogOutput& output); 127 | }; 128 | 129 | /// https://github.com/CesiumGS/3d-tiles/blob/main/specification/schema/asset.schema.json 130 | struct VSGXCHANGE_DECLSPEC Asset : public vsg::Inherit 131 | { 132 | std::string version; 133 | std::string tilesetVersion; 134 | 135 | std::map strings; 136 | std::map numbers; 137 | 138 | void read_string(vsg::JSONParser& parser, const std::string_view& property) override; 139 | void read_number(vsg::JSONParser& parser, const std::string_view& property, std::istream& input) override; 140 | void report(vsg::LogOutput& output); 141 | }; 142 | 143 | /// https://github.com/CesiumGS/3d-tiles/blob/main/specification/schema/tileset.schema.json 144 | struct VSGXCHANGE_DECLSPEC Tileset : public vsg::Inherit 145 | { 146 | vsg::ref_ptr asset; 147 | vsg::ref_ptr properties; 148 | vsg::ref_ptr root; 149 | double geometricError = 0.0; 150 | vsg::StringsSchema extensionsUsed; 151 | vsg::StringsSchema extensionsRequired; 152 | 153 | void read_array(vsg::JSONParser& parser, const std::string_view& property) override; 154 | void read_object(vsg::JSONParser& parser, const std::string_view& property) override; 155 | void read_number(vsg::JSONParser& parser, const std::string_view& property, std::istream& input) override; 156 | 157 | void report(vsg::LogOutput& output); 158 | 159 | virtual void resolveURIs(vsg::ref_ptr options); 160 | }; 161 | 162 | /// Template class for reading an array of values from JSON or from a binary block 163 | template 164 | struct ArraySchema : public Inherit> 165 | { 166 | const uint32_t invalidOffset = std::numeric_limits::max(); 167 | uint32_t byteOffset = invalidOffset; 168 | std::vector values; 169 | 170 | void read_number(vsg::JSONParser&, std::istream& input) override 171 | { 172 | T value; 173 | input >> value; 174 | values.push_back(value); 175 | } 176 | 177 | void read_number(vsg::JSONParser& parser, const std::string_view& property, std::istream& input) override 178 | { 179 | if (property == "byteOffset") 180 | input >> byteOffset; 181 | else 182 | parser.warning(); 183 | } 184 | 185 | void assign(vsg::ubyteArray& binary, uint32_t count) 186 | { 187 | if (!values.empty() || byteOffset == invalidOffset) return; 188 | 189 | T* ptr = reinterpret_cast(binary.data() + byteOffset); 190 | for (uint32_t i = 0; i < count; ++i) 191 | { 192 | values.push_back(*(ptr++)); 193 | } 194 | } 195 | 196 | explicit operator bool() const noexcept { return !values.empty(); } 197 | }; 198 | 199 | struct VSGXCHANGE_DECLSPEC b3dm_FeatureTable : public vsg::Inherit 200 | { 201 | // storage for binary section 202 | vsg::ref_ptr binary; 203 | 204 | uint32_t BATCH_LENGTH = 0; 205 | ArraySchema RTC_CENTER; 206 | void read_array(vsg::JSONParser& parser, const std::string_view& property) override; 207 | void read_object(vsg::JSONParser& parser, const std::string_view& property) override; 208 | void read_number(vsg::JSONParser& parser, const std::string_view& property, std::istream& input) override; 209 | 210 | void convert(); 211 | 212 | void report(vsg::LogOutput& output); 213 | }; 214 | 215 | struct BatchTable; 216 | 217 | struct VSGXCHANGE_DECLSPEC Batch : public vsg::Inherit 218 | { 219 | uint32_t byteOffset = 0; 220 | std::string componentType; 221 | std::string type; 222 | 223 | void convert(BatchTable& batchTable); 224 | 225 | // read array parts 226 | void read_number(vsg::JSONParser& parser, std::istream& input) override; 227 | 228 | // read object parts 229 | void read_string(vsg::JSONParser& parser, const std::string_view& property) override; 230 | void read_number(vsg::JSONParser& parser, const std::string_view& property, std::istream& input) override; 231 | }; 232 | 233 | struct VSGXCHANGE_DECLSPEC BatchTable : public vsg::Inherit 234 | { 235 | std::map> batches; 236 | 237 | uint32_t length = 0; 238 | vsg::ref_ptr binary; 239 | 240 | void read_array(vsg::JSONParser& parser, const std::string_view& property) override; 241 | void read_object(vsg::JSONParser& parser, const std::string_view& property) override; 242 | 243 | void convert(); 244 | 245 | void report(vsg::LogOutput& output); 246 | }; 247 | 248 | // https://github.com/CesiumGS/3d-tiles/blob/main/specification/TileFormats/Instanced3DModel/README.adoc 249 | struct VSGXCHANGE_DECLSPEC i3dm_FeatureTable : public vsg::Inherit 250 | { 251 | // storage for binary section 252 | vsg::ref_ptr binary; 253 | 254 | // Instance sematics 255 | ArraySchema POSITION; 256 | ArraySchema POSITION_QUANTIZED; 257 | ArraySchema NORMAL_UP; 258 | ArraySchema NORMAL_RIGHT; 259 | ArraySchema NORMAL_UP_OCT32P; 260 | ArraySchema NORMAL_RIGHT_OCT32P; 261 | ArraySchema SCALE; 262 | ArraySchema SCALE_NON_UNIFORM; 263 | ArraySchema BATCH_ID; 264 | 265 | // Global sematics 266 | uint32_t INSTANCES_LENGTH = 0; 267 | ArraySchema RTC_CENTER; 268 | ArraySchema QUANTIZED_VOLUME_OFFSET; 269 | ArraySchema QUANTIZED_VOLUME_SCALE; 270 | bool EAST_NORTH_UP = false; 271 | 272 | void read_array(vsg::JSONParser& parser, const std::string_view& property) override; 273 | void read_object(vsg::JSONParser& parser, const std::string_view& property) override; 274 | void read_number(vsg::JSONParser& parser, const std::string_view& property, std::istream& input) override; 275 | void read_bool(vsg::JSONParser& parser, const std::string_view& property, bool value) override; 276 | 277 | void convert(); 278 | 279 | void report(vsg::LogOutput& output); 280 | }; 281 | 282 | public: 283 | class VSGXCHANGE_DECLSPEC SceneGraphBuilder : public vsg::Inherit 284 | { 285 | public: 286 | SceneGraphBuilder(); 287 | 288 | vsg::ref_ptr options; 289 | vsg::ref_ptr shaderSet; 290 | vsg::ref_ptr sharedObjects; 291 | vsg::ref_ptr operationThreads; 292 | 293 | vsg::ref_ptr ellipsoidModel = vsg::EllipsoidModel::create(); 294 | vsg::CoordinateConvention source_coordinateConvention = vsg::CoordinateConvention::Y_UP; 295 | double pixelErrorToScreenHeightRatio = 0.016; // 0.016 looks to replicate vsgCs worldviewer transition distances 296 | uint32_t preLoadLevel = 1; 297 | 298 | virtual void assignResourceHints(vsg::ref_ptr node); 299 | 300 | virtual vsg::dmat4 createMatrix(const std::vector& values); 301 | virtual vsg::dsphere createBound(vsg::ref_ptr boundingVolume); 302 | virtual vsg::ref_ptr readTileChildren(vsg::ref_ptr tile, uint32_t level, const std::string& inherited_refine); 303 | virtual vsg::ref_ptr createTile(vsg::ref_ptr tile, uint32_t level, const std::string& inherited_refine); 304 | virtual vsg::ref_ptr createSceneGraph(vsg::ref_ptr tileset, vsg::ref_ptr in_options); 305 | }; 306 | }; 307 | 308 | } // namespace vsgXchange 309 | 310 | EVSG_type_name(vsgXchange::Tiles3D) 311 | -------------------------------------------------------------------------------- /src/dds/dds.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright(c) 2021 André Normann & Robert Osfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | */ 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #if defined(__GNUC__) 26 | # pragma GCC diagnostic push 27 | # pragma GCC diagnostic ignored "-Wunused-variable" 28 | # pragma GCC diagnostic ignored "-Wunused-but-set-variable" 29 | # pragma GCC diagnostic ignored "-Wsign-compare" 30 | # pragma GCC diagnostic ignored "-Wunused-function" 31 | #endif 32 | 33 | #define TINYDDSLOADER_IMPLEMENTATION 34 | #include "tinyddsloader.h" 35 | 36 | #if defined(__GNUC__) 37 | # pragma GCC diagnostic pop 38 | #endif 39 | 40 | namespace 41 | { 42 | const std::unordered_map kFormatMap{ 43 | {tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm, VK_FORMAT_R8G8B8A8_UNORM}, 44 | {tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_SNorm, VK_FORMAT_R8G8B8A8_SNORM}, 45 | {tinyddsloader::DDSFile::DXGIFormat::R8G8B8A8_UNorm_SRGB, VK_FORMAT_R8G8B8A8_SRGB}, 46 | {tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm, VK_FORMAT_B8G8R8A8_UNORM}, 47 | {tinyddsloader::DDSFile::DXGIFormat::B8G8R8A8_UNorm_SRGB, VK_FORMAT_B8G8R8A8_SRGB}, 48 | {tinyddsloader::DDSFile::DXGIFormat::R8G8_UNorm, VK_FORMAT_R8G8_UNORM}, 49 | {tinyddsloader::DDSFile::DXGIFormat::R8G8_SNorm, VK_FORMAT_R8G8_SNORM}, 50 | {tinyddsloader::DDSFile::DXGIFormat::R8G8_UInt, VK_FORMAT_R8G8_UINT}, 51 | {tinyddsloader::DDSFile::DXGIFormat::R8G8_SInt, VK_FORMAT_R8G8_SINT}, 52 | {tinyddsloader::DDSFile::DXGIFormat::BC7_UNorm, VK_FORMAT_BC7_UNORM_BLOCK}, 53 | {tinyddsloader::DDSFile::DXGIFormat::BC7_UNorm_SRGB, VK_FORMAT_BC7_SRGB_BLOCK}, 54 | {tinyddsloader::DDSFile::DXGIFormat::BC6H_UF16, VK_FORMAT_BC6H_UFLOAT_BLOCK}, 55 | {tinyddsloader::DDSFile::DXGIFormat::BC6H_SF16, VK_FORMAT_BC6H_SFLOAT_BLOCK}, 56 | {tinyddsloader::DDSFile::DXGIFormat::BC5_UNorm, VK_FORMAT_BC5_UNORM_BLOCK}, 57 | {tinyddsloader::DDSFile::DXGIFormat::BC5_SNorm, VK_FORMAT_BC5_SNORM_BLOCK}, 58 | {tinyddsloader::DDSFile::DXGIFormat::BC4_UNorm, VK_FORMAT_BC4_UNORM_BLOCK}, 59 | {tinyddsloader::DDSFile::DXGIFormat::BC4_SNorm, VK_FORMAT_BC4_SNORM_BLOCK}, 60 | {tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm, VK_FORMAT_BC3_UNORM_BLOCK}, 61 | {tinyddsloader::DDSFile::DXGIFormat::BC3_UNorm_SRGB, VK_FORMAT_BC3_SRGB_BLOCK}, 62 | {tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm, VK_FORMAT_BC2_UNORM_BLOCK}, 63 | {tinyddsloader::DDSFile::DXGIFormat::BC2_UNorm_SRGB, VK_FORMAT_BC2_SRGB_BLOCK}, 64 | {tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm, VK_FORMAT_BC1_RGBA_UNORM_BLOCK}, 65 | {tinyddsloader::DDSFile::DXGIFormat::BC1_UNorm_SRGB, VK_FORMAT_BC1_RGBA_SRGB_BLOCK}, 66 | {tinyddsloader::DDSFile::DXGIFormat::R16G16B16A16_Float, VK_FORMAT_R16G16B16A16_SFLOAT}, 67 | {tinyddsloader::DDSFile::DXGIFormat::R32G32B32A32_Float, VK_FORMAT_R32G32B32A32_SFLOAT}}; 68 | 69 | std::pair> allocateAndCopyToContiguousBlock(tinyddsloader::DDSFile& ddsFile, const vsg::Data::Properties& layout) 70 | { 71 | const auto numMipMaps = layout.mipLevels; 72 | const auto numArrays = ddsFile.GetArraySize(); 73 | 74 | size_t totalSize = 0; 75 | for (uint32_t i = 0; i < numMipMaps; ++i) 76 | { 77 | for (uint32_t j = 0; j < numArrays; ++j) 78 | { 79 | const auto data = ddsFile.GetImageData(i, j); 80 | totalSize += data->m_memSlicePitch; 81 | } 82 | } 83 | 84 | if (totalSize == 0) return {nullptr, nullptr}; 85 | 86 | auto raw = new uint8_t[totalSize]; 87 | 88 | auto mipmapLayout = vsg::MipmapLayout::create(numMipMaps); 89 | auto mipmapItr = mipmapLayout->begin(); 90 | 91 | uint32_t offset = 0; 92 | uint8_t* image_ptr = raw; 93 | for (uint32_t i = 0; i < numMipMaps; ++i) 94 | { 95 | for (uint32_t j = 0; j < numArrays; ++j) 96 | { 97 | const auto data = ddsFile.GetImageData(i, j); 98 | 99 | if (j == 0) 100 | { 101 | (*mipmapItr++).set(data->m_width, data->m_height, data->m_depth, offset); 102 | } 103 | 104 | std::memcpy(image_ptr, data->m_mem, data->m_memSlicePitch); 105 | 106 | offset += static_cast(data->m_memSlicePitch); 107 | image_ptr += data->m_memSlicePitch; 108 | } 109 | } 110 | 111 | return {raw, mipmapLayout}; 112 | } 113 | 114 | int computeImageViewType(tinyddsloader::DDSFile& ddsFile) 115 | { 116 | switch (ddsFile.GetTextureDimension()) 117 | { 118 | case tinyddsloader::DDSFile::TextureDimension::Texture1D: return VK_IMAGE_VIEW_TYPE_1D; 119 | case tinyddsloader::DDSFile::TextureDimension::Texture2D: 120 | if (ddsFile.GetArraySize() > 1) 121 | { 122 | return ddsFile.IsCubemap() ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D_ARRAY; 123 | } 124 | else 125 | { 126 | return VK_IMAGE_VIEW_TYPE_2D; 127 | } 128 | case tinyddsloader::DDSFile::TextureDimension::Texture3D: return VK_IMAGE_VIEW_TYPE_3D; 129 | case tinyddsloader::DDSFile::TextureDimension::Unknown: return -1; 130 | } 131 | return -1; 132 | } 133 | 134 | static void process_image_format(vsg::ref_ptr options, VkFormat& format) 135 | { 136 | if (!options) return; 137 | 138 | vsg::CoordinateSpace coordinateSpace; 139 | if (options->getValue(vsgXchange::dds::image_format, coordinateSpace)) 140 | { 141 | if (coordinateSpace == vsg::CoordinateSpace::sRGB) 142 | format = vsg::uNorm_to_sRGB(format); 143 | else if (coordinateSpace == vsg::CoordinateSpace::LINEAR) 144 | format = vsg::sRGB_to_uNorm(format); 145 | } 146 | } 147 | 148 | vsg::ref_ptr readCompressed(tinyddsloader::DDSFile& ddsFile, VkFormat targetFormat) 149 | { 150 | const auto width = ddsFile.GetWidth(); 151 | const auto height = ddsFile.GetHeight(); 152 | const auto numArrays = ddsFile.GetArraySize(); 153 | 154 | auto formatTraits = vsg::getFormatTraits(targetFormat); 155 | 156 | uint32_t widthInBlocks = (width + formatTraits.blockWidth - 1) / formatTraits.blockWidth; 157 | uint32_t heightInBlocks = (height + formatTraits.blockHeight - 1) / formatTraits.blockHeight; 158 | 159 | uint32_t numMipMaps = ddsFile.GetMipCount(); 160 | 161 | vsg::Data::Properties layout; 162 | layout.format = targetFormat; 163 | layout.mipLevels = numMipMaps; 164 | layout.blockWidth = formatTraits.blockWidth; 165 | layout.blockHeight = formatTraits.blockHeight; 166 | layout.blockDepth = formatTraits.blockDepth; 167 | layout.imageViewType = computeImageViewType(ddsFile); 168 | 169 | auto [raw, mipmapLayout] = allocateAndCopyToContiguousBlock(ddsFile, layout); 170 | 171 | vsg::ref_ptr vsg_data; 172 | 173 | switch (targetFormat) 174 | { 175 | case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: 176 | case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: 177 | case VK_FORMAT_BC4_SNORM_BLOCK: 178 | case VK_FORMAT_BC4_UNORM_BLOCK: 179 | if (numArrays > 1) 180 | vsg_data = vsg::block64Array3D::create(widthInBlocks, heightInBlocks, numArrays, reinterpret_cast(raw), layout, mipmapLayout); 181 | else 182 | vsg_data = vsg::block64Array2D::create(widthInBlocks, heightInBlocks, reinterpret_cast(raw), layout, mipmapLayout); 183 | break; 184 | case VK_FORMAT_BC2_UNORM_BLOCK: 185 | case VK_FORMAT_BC2_SRGB_BLOCK: 186 | case VK_FORMAT_BC3_UNORM_BLOCK: 187 | case VK_FORMAT_BC3_SRGB_BLOCK: 188 | case VK_FORMAT_BC5_UNORM_BLOCK: 189 | case VK_FORMAT_BC5_SNORM_BLOCK: 190 | case VK_FORMAT_BC6H_UFLOAT_BLOCK: 191 | case VK_FORMAT_BC6H_SFLOAT_BLOCK: 192 | case VK_FORMAT_BC7_UNORM_BLOCK: 193 | case VK_FORMAT_BC7_SRGB_BLOCK: 194 | if (numArrays > 1) 195 | vsg_data = vsg::block128Array3D::create(widthInBlocks, heightInBlocks, numArrays, reinterpret_cast(raw), layout, mipmapLayout); 196 | else 197 | vsg_data = vsg::block128Array2D::create(widthInBlocks, heightInBlocks, reinterpret_cast(raw), layout, mipmapLayout); 198 | break; 199 | default: 200 | std::cerr << "dds::readCompressed() Format is not supported yet: " << (uint32_t)targetFormat << std::endl; 201 | break; 202 | } 203 | #if 0 204 | if (vsg_data && mipmapLayout) 205 | { 206 | vsg_data->setObject("mipmapLayout", mipmapLayout); 207 | } 208 | #endif 209 | 210 | return vsg_data; 211 | } 212 | 213 | vsg::ref_ptr readDds(tinyddsloader::DDSFile& ddsFile, vsg::ref_ptr options) 214 | { 215 | const auto width = ddsFile.GetWidth(); 216 | const auto height = ddsFile.GetHeight(); 217 | const auto depth = ddsFile.GetDepth(); 218 | const auto numMipMaps = ddsFile.GetMipCount(); 219 | const auto format = ddsFile.GetFormat(); 220 | const auto isCompressed = ddsFile.IsCompressed(format); 221 | const auto dim = ddsFile.GetTextureDimension(); 222 | const auto numArrays = ddsFile.GetArraySize(); 223 | 224 | // const auto bpp = tinyddsloader::DDSFile::GetBitsPerPixel(format); 225 | //std::cerr << "Fileinfo width: " << width << ", height: " << height << ", depth: " << depth << ", count: " << valueCount 226 | // << ", format: " << (int)format << ", bpp: " << tinyddsloader::DDSFile::GetBitsPerPixel(format) 227 | // << ", mipmaps: " << numMipMaps << ", arrays: " << numArrays 228 | // << std::boolalpha << ", cubemap: " << isCubemap << ", compressed: " << isCompressed << std::endl; 229 | 230 | if (auto it = kFormatMap.find(format); it != kFormatMap.end()) 231 | { 232 | vsg::ref_ptr vsg_data; 233 | if (isCompressed) 234 | { 235 | vsg_data = readCompressed(ddsFile, it->second); 236 | } 237 | else 238 | { 239 | vsg::Data::Properties layout; 240 | layout.format = it->second; 241 | layout.mipLevels = numMipMaps; 242 | layout.imageViewType = computeImageViewType(ddsFile); 243 | 244 | auto [raw, mipmapLayout] = allocateAndCopyToContiguousBlock(ddsFile, layout); 245 | 246 | switch (dim) 247 | { 248 | case tinyddsloader::DDSFile::TextureDimension::Texture1D: 249 | switch (layout.format) 250 | { 251 | case VK_FORMAT_R32G32B32A32_SFLOAT: 252 | vsg_data = vsg::vec4Array::create(width, reinterpret_cast(raw), layout, mipmapLayout); 253 | break; 254 | case VK_FORMAT_R16G16B16A16_SFLOAT: 255 | vsg_data = vsg::usvec4Array::create(width, reinterpret_cast(raw), layout, mipmapLayout); 256 | break; 257 | default: 258 | vsg_data = vsg::ubvec4Array::create(width, reinterpret_cast(raw), layout, mipmapLayout); 259 | break; 260 | } 261 | break; 262 | case tinyddsloader::DDSFile::TextureDimension::Texture2D: 263 | if (numArrays > 1) 264 | { 265 | switch (layout.format) 266 | { 267 | case VK_FORMAT_R32G32B32A32_SFLOAT: 268 | vsg_data = vsg::vec4Array3D::create(width, height, numArrays, reinterpret_cast(raw), layout, mipmapLayout); 269 | break; 270 | case VK_FORMAT_R16G16B16A16_SFLOAT: 271 | vsg_data = vsg::usvec4Array3D::create(width, height, numArrays, reinterpret_cast(raw), layout, mipmapLayout); 272 | break; 273 | default: 274 | vsg_data = vsg::ubvec4Array3D::create(width, height, numArrays, reinterpret_cast(raw), layout, mipmapLayout); 275 | break; 276 | } 277 | } 278 | else 279 | { 280 | switch (layout.format) 281 | { 282 | case VK_FORMAT_R32G32B32A32_SFLOAT: 283 | vsg_data = vsg::vec4Array2D::create(width, height, reinterpret_cast(raw), layout, mipmapLayout); 284 | break; 285 | case VK_FORMAT_R16G16B16A16_SFLOAT: 286 | vsg_data = vsg::usvec4Array2D::create(width, height, reinterpret_cast(raw), layout, mipmapLayout); 287 | break; 288 | default: 289 | vsg_data = vsg::ubvec4Array2D::create(width, height, reinterpret_cast(raw), layout, mipmapLayout); 290 | break; 291 | } 292 | } 293 | break; 294 | case tinyddsloader::DDSFile::TextureDimension::Texture3D: 295 | switch (layout.format) 296 | { 297 | case VK_FORMAT_R32G32B32A32_SFLOAT: 298 | vsg_data = vsg::vec4Array3D::create(width, height, depth, reinterpret_cast(raw), layout, mipmapLayout); 299 | break; 300 | case VK_FORMAT_R16G16B16A16_SFLOAT: 301 | vsg_data = vsg::usvec4Array3D::create(width, height, depth, reinterpret_cast(raw), layout, mipmapLayout); 302 | break; 303 | default: 304 | vsg_data = vsg::ubvec4Array3D::create(width, height, depth, reinterpret_cast(raw), layout, mipmapLayout); 305 | break; 306 | } 307 | break; 308 | case tinyddsloader::DDSFile::TextureDimension::Unknown: 309 | std::cerr << "dds::readDds() Num of dimension (" << (uint32_t)dim << ") not supported." << std::endl; 310 | break; 311 | } 312 | #if 0 313 | if (vsg_data && mipmapLayout) 314 | { 315 | vsg_data->setObject("mipmapLayout", mipmapLayout); 316 | } 317 | #endif 318 | } 319 | 320 | if (options && vsg_data) process_image_format(options, vsg_data->properties.format); 321 | 322 | return vsg_data; 323 | } 324 | else 325 | { 326 | std::cerr << "dds::readDds() Format is not supported yet: " << (uint32_t)format << std::endl; 327 | } 328 | 329 | return {}; 330 | } 331 | 332 | } // namespace 333 | 334 | using namespace vsgXchange; 335 | 336 | dds::dds() : 337 | _supportedExtensions{".dds"} 338 | { 339 | } 340 | 341 | vsg::ref_ptr dds::read(const vsg::Path& filename, vsg::ref_ptr options) const 342 | { 343 | if (!vsg::compatibleExtension(filename, options, _supportedExtensions)) return {}; 344 | 345 | vsg::Path filenameToUse = findFile(filename, options); 346 | if (!filenameToUse) return {}; 347 | 348 | tinyddsloader::DDSFile ddsFile; 349 | 350 | std::ifstream ifs(filenameToUse, std::ios_base::binary); 351 | if (const auto result = ddsFile.Load(ifs); result == tinyddsloader::Success) 352 | { 353 | return readDds(ddsFile, options); 354 | } 355 | else 356 | { 357 | switch (result) 358 | { 359 | case tinyddsloader::ErrorNotSupported: 360 | std::cerr << "dds::read(" << filename << ") Error loading file: Feature not supported" << std::endl; 361 | break; 362 | default: 363 | std::cerr << "dds::read(" << filename << ") Error loading file: " << result << std::endl; 364 | break; 365 | } 366 | } 367 | 368 | return {}; 369 | } 370 | 371 | vsg::ref_ptr dds::read(std::istream& fin, vsg::ref_ptr options) const 372 | { 373 | if (!vsg::compatibleExtension(options, _supportedExtensions)) return {}; 374 | 375 | tinyddsloader::DDSFile ddsFile; 376 | if (const auto result = ddsFile.Load(fin); result == tinyddsloader::Success) 377 | { 378 | return readDds(ddsFile, options); 379 | } 380 | else 381 | { 382 | switch (result) 383 | { 384 | case tinyddsloader::ErrorNotSupported: 385 | std::cerr << "dds::read(istream&) Error loading file: Feature not supported" << std::endl; 386 | break; 387 | default: 388 | std::cerr << "dds::read(istream&) Error loading file: " << result << std::endl; 389 | break; 390 | } 391 | } 392 | 393 | return {}; 394 | } 395 | 396 | vsg::ref_ptr dds::read(const uint8_t* ptr, size_t size, vsg::ref_ptr options) const 397 | { 398 | if (!vsg::compatibleExtension(options, _supportedExtensions)) return {}; 399 | 400 | tinyddsloader::DDSFile ddsFile; 401 | if (const auto result = ddsFile.Load(ptr, size); result == tinyddsloader::Success) 402 | { 403 | return readDds(ddsFile, options); 404 | } 405 | else 406 | { 407 | switch (result) 408 | { 409 | case tinyddsloader::ErrorNotSupported: 410 | std::cerr << "dds::read(uint_8_t*, size_t) Error loading file: Feature not supported" << std::endl; 411 | break; 412 | default: 413 | std::cerr << "dds::read(uint_8_t*, size_t) Error loading file: " << result << std::endl; 414 | break; 415 | } 416 | } 417 | 418 | return {}; 419 | } 420 | 421 | bool dds::getFeatures(Features& features) const 422 | { 423 | for (auto& ext : _supportedExtensions) 424 | { 425 | features.extensionFeatureMap[ext] = static_cast(vsg::ReaderWriter::READ_FILENAME | vsg::ReaderWriter::READ_ISTREAM | vsg::ReaderWriter::READ_MEMORY); 426 | } 427 | 428 | features.optionNameTypeMap[dds::image_format] = vsg::type_name(); 429 | 430 | return true; 431 | } 432 | 433 | bool dds::readOptions(vsg::Options& options, vsg::CommandLine& arguments) const 434 | { 435 | bool result = arguments.readAndAssign(dds::image_format, &options); 436 | return result; 437 | } 438 | --------------------------------------------------------------------------------