diff --git a/.travis.sh b/.travis.sh index fb42bd40d..f0f0f5d70 100755 --- a/.travis.sh +++ b/.travis.sh @@ -7,7 +7,8 @@ # function generate() { OPTIONS="-DASSIMP_WERROR=ON" - + OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=NO" + if [ "$DISABLE_EXPORTERS" = "YES" ] ; then OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=YES" else diff --git a/BUILDBINARIES_EXAMPLE.bat b/BUILDBINARIES_EXAMPLE.bat new file mode 100644 index 000000000..2dd13a542 --- /dev/null +++ b/BUILDBINARIES_EXAMPLE.bat @@ -0,0 +1,26 @@ +:: This is an example file to generate binaries using Windows Operating System +:: This script is configured to be executed from the source directory + +:: Compiled binaries will be placed in BINARIES_DIR\code\CONFIG + +:: NOTE +:: The build process will generate a config.h file that is placed in BINARIES_DIR\include +:: This file must be merged with SOURCE_DIR\include +:: You should write yourself a script that copies the files where you want them. +:: Also see: https://github.com/assimp/assimp/pull/2646 + +SET SOURCE_DIR=. + +:: For generators see "cmake --help" +SET GENERATOR=Visual Studio 15 2017 + +SET BINARIES_DIR="./BINARIES/Win32" +cmake CMakeLists.txt -G "%GENERATOR%" -S %SOURCE_DIR% -B %BINARIES_DIR% +cmake --build %BINARIES_DIR% --config release + +SET BINARIES_DIR="./BINARIES/x64" +cmake CMakeLists.txt -G "%GENERATOR% Win64" -S %SOURCE_DIR% -B %BINARIES_DIR% +cmake --build %BINARIES_DIR% --config debug +cmake --build %BINARIES_DIR% --config release + +PAUSE diff --git a/Build.md b/Build.md index 7c908606d..2db47798d 100644 --- a/Build.md +++ b/Build.md @@ -1,17 +1,31 @@ # Build Instructions -## Install CMake + +## Build on all platforms using vcpkg +You can download and install assimp using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager: +```bash + git clone https://github.com/Microsoft/vcpkg.git + cd vcpkg + ./bootstrap-vcpkg.sh + ./vcpkg integrate install + vcpkg install assimp +``` +The assimp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. + +## Manual build instructions + +### Install CMake Asset-Importer-Lib can be build for a lot of different platforms. We are using cmake to generate the build environment for these via cmake. So you have to make sure that you have a working cmake-installation on your system. You can download it at https://cmake.org/ or for linux install it via ```bash sudo apt-get install cmake ``` -## Get the source +### Get the source Make sure you have a working git-installation. Open a command prompt and clone the Asset-Importer-Lib via: ```bash git clone https://github.com/assimp/assimp.git ``` -## Build instructions for Windows with Visual-Studio +### Build instructions for Windows with Visual-Studio First you have to install Visual-Studio on your windows-system. You can get the Community-Version for free here: https://visualstudio.microsoft.com/de/downloads/ To generate the build environment for your IDE open a command prompt, navigate to your repo and type: @@ -20,10 +34,10 @@ cmake CMakeLists.txt ``` This will generate the project files for the visual studio. All dependencies used to build Asset-IMporter-Lib shall be part of the repo. If you want to use you own zlib.installation this is possible as well. Check the options for it. -## Build instructions for Windows with UWP +### Build instructions for Windows with UWP See -## Build instructions for Linux / Unix +### Build instructions for Linux / Unix Open a terminal and got to your repository. You can generate the makefiles and build the library via: ```bash @@ -34,7 +48,7 @@ The option -j descripes the number of parallel processes for the build. In this If you want to use a IDE for linux you can try QTCreator for instance. -## Build instructions for MinGW +### Build instructions for MinGW Older versions of MinGW's compiler (e.g. 5.1.0) do not support the -mbig_obj flag required to compile some of assimp's files, especially for debug builds. Version 7.3.0 of g++-mingw-w64 & gcc-mingw-w64 appears to work. @@ -50,7 +64,7 @@ The following toolchain may or may not be helpful for building assimp using MinG Besides the toolchain, compilation should be the same as for Linux / Unix. -## CMake build options +### CMake build options The cmake-build-environment provides options to configure the build. The following options can be used: - **BUILD_SHARED_LIBS ( default ON )**: Generation of shared libs ( dll for windows, so for Linux ). Set this to OFF to get a static lib. - **BUILD_FRAMEWORK ( default OFF, MacOnly)**: Build package as Mac OS X Framework bundle diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ed9f6b56..dcafb649f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -253,7 +253,7 @@ ELSEIF(MSVC) IF(MSVC12) ADD_COMPILE_OPTIONS(/wd4351) ENDIF() - SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2") + SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2 /DEBUG:FULL /Zi") ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) IF(NOT HUNTER_ENABLED) SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}") @@ -271,22 +271,20 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW ) SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") ENDIF() - SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj ${CMAKE_CXX_FLAGS}") + SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj -O3 ${CMAKE_CXX_FLAGS}") SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") ADD_DEFINITIONS( -U__STRICT_ANSI__ ) ENDIF() IF ( IOS AND NOT HUNTER_ENABLED) - -IF (CMAKE_BUILD_TYPE STREQUAL "Debug") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og") -ELSE() - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3") - # Experimental for pdb generation -ENDIF() - + IF (CMAKE_BUILD_TYPE STREQUAL "Debug") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og") + ELSE() + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3") + # Experimental for pdb generation + ENDIF() ENDIF( IOS AND NOT HUNTER_ENABLED) IF (ASSIMP_COVERALLS) @@ -559,17 +557,15 @@ ENDIF(NOT HUNTER_ENABLED) ADD_SUBDIRECTORY( code/ ) IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) + # The viewer for windows only IF ( WIN32 AND DirectX_D3DX9_LIBRARY ) OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} ) IF ( ASSIMP_BUILD_ASSIMP_VIEW ) ADD_SUBDIRECTORY( tools/assimp_view/ ) ENDIF ( ASSIMP_BUILD_ASSIMP_VIEW ) ENDIF ( WIN32 AND DirectX_D3DX9_LIBRARY ) - + # Te command line tool ADD_SUBDIRECTORY( tools/assimp_cmd/ ) -IF (NOT IOS) - ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ ) -ENDIF (NOT IOS) ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS ) IF ( ASSIMP_BUILD_SAMPLES) diff --git a/Readme.md b/Readme.md index 52a195a64..f749993fd 100644 --- a/Readme.md +++ b/Readme.md @@ -120,7 +120,7 @@ __Exporters__: - FBX ( experimental ) ### Building ### -Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file. Our build system is CMake, if you used CMake before there is a good chance you know what to do. +Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file. We are available in vcpkg, and our build system is CMake; if you used CMake before there is a good chance you know what to do. ### Ports ### * [Android](port/AndroidJNI/README.md) diff --git a/appveyor.yml b/appveyor.yml index 3729ea028..df16431bd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -16,6 +16,8 @@ matrix: image: - Visual Studio 2015 - Visual Studio 2017 + - Visual Studio 2019 + - MinGW platform: - Win32 @@ -26,10 +28,13 @@ configuration: Release install: - set PATH=C:\Ruby24-x64\bin;%PATH% - set CMAKE_DEFINES -DASSIMP_WERROR=ON + - if [%COMPILER%]==[MinGW] set PATH=C:\MinGW\bin;%PATH% - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015 - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" set CMAKE_GENERATOR_NAME=Visual Studio 15 2017 - - if "%platform%"=="x64" set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_NAME% Win64 - - cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" . + - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2019" set CMAKE_GENERATOR_NAME=Visual Studio 16 2019 + - cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" -A %platform% . + # Rename sh.exe as sh.exe in PATH interferes with MinGW + - rename "C:\Program Files\Git\usr\bin\sh.exe" "sh2.exe" - set PATH=%PATH%;"C:\\Program Files (x86)\\Inno Setup 5" - ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/5/7/b/57b2947c-7221-4f33-b35e-2fc78cb10df4/vc_redist.x64.exe -OutFile .\packaging\windows-innosetup\vc_redist.x64.exe - ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/1/d/8/1d8137db-b5bb-4925-8c5d-927424a2e4de/vc_redist.x86.exe -OutFile .\packaging\windows-innosetup\vc_redist.x86.exe diff --git a/assimpTargets-debug.cmake.in b/assimpTargets-debug.cmake.in index 1ebe2a608..ed98e777b 100644 --- a/assimpTargets-debug.cmake.in +++ b/assimpTargets-debug.cmake.in @@ -63,7 +63,11 @@ if(MSVC) else() set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" ) if(ASSIMP_BUILD_SHARED_LIBS) - set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") + if(APPLE) + set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@") + else(APPLE) + set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") + endif() set_target_properties(assimp::assimp PROPERTIES IMPORTED_SONAME_DEBUG "${sharedLibraryName}" IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" diff --git a/assimpTargets-release.cmake.in b/assimpTargets-release.cmake.in index b09b881f7..a5fe74933 100644 --- a/assimpTargets-release.cmake.in +++ b/assimpTargets-release.cmake.in @@ -63,7 +63,11 @@ if(MSVC) else() set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" ) if(ASSIMP_BUILD_SHARED_LIBS) - set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") + if(APPLE) + set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@") + else(APPLE) + set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") + endif() set_target_properties(assimp::assimp PROPERTIES IMPORTED_SONAME_RELEASE "${sharedLibraryName}" IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" diff --git a/cmake-modules/Findassimp.cmake b/cmake-modules/Findassimp.cmake index 95f3250b3..663645574 100644 --- a/cmake-modules/Findassimp.cmake +++ b/cmake-modules/Findassimp.cmake @@ -54,14 +54,18 @@ else(WIN32) find_path( assimp_INCLUDE_DIRS - NAMES postprocess.h scene.h version.h config.h cimport.h - PATHS /usr/local/include/ + NAMES assimp/postprocess.h assimp/scene.h assimp/version.h assimp/config.h assimp/cimport.h + PATHS /usr/local/include + PATHS /usr/include/ + ) find_library( assimp_LIBRARIES NAMES assimp PATHS /usr/local/lib/ + PATHS /usr/lib64/ + PATHS /usr/lib/ ) if (assimp_INCLUDE_DIRS AND assimp_LIBRARIES) @@ -78,4 +82,4 @@ else(WIN32) endif (assimp_FIND_REQUIRED) endif (assimp_FOUND) -endif(WIN32) \ No newline at end of file +endif(WIN32) diff --git a/code/3DS/3DSLoader.cpp b/code/3DS/3DSLoader.cpp index 96b80c962..3c659d0b0 100644 --- a/code/3DS/3DSLoader.cpp +++ b/code/3DS/3DSLoader.cpp @@ -50,9 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER -// internal headers #include "3DSLoader.h" -#include #include #include #include diff --git a/code/AMF/AMFImporter.cpp b/code/AMF/AMFImporter.cpp index d173bd0f5..dedb6dcdd 100644 --- a/code/AMF/AMFImporter.cpp +++ b/code/AMF/AMFImporter.cpp @@ -83,7 +83,7 @@ void AMFImporter::Clear() mMaterial_Converted.clear(); mTexture_Converted.clear(); // Delete all elements - if(mNodeElement_List.size()) + if(!mNodeElement_List.empty()) { for(CAMFImporter_NodeElement* ne: mNodeElement_List) { delete ne; } diff --git a/code/AMF/AMFImporter_Postprocess.cpp b/code/AMF/AMFImporter_Postprocess.cpp index 2bfe3f78c..79b5e15e2 100644 --- a/code/AMF/AMFImporter_Postprocess.cpp +++ b/code/AMF/AMFImporter_Postprocess.cpp @@ -66,7 +66,7 @@ aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /* aiColor4D tcol; // Check if stored data are supported. - if(Composition.size() != 0) + if(!Composition.empty()) { throw DeadlyImportError("IME. GetColor for composition"); } @@ -321,7 +321,7 @@ void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list 0) pOutputList_Separated.push_back(face_list_cur); + if(!face_list_cur.empty()) pOutputList_Separated.push_back(face_list_cur); - } while(pInputList.size() > 0); + } while(!pInputList.empty()); } void AMFImporter::Postprocess_AddMetadata(const std::list& metadataList, aiNode& sceneNode) const @@ -712,7 +712,7 @@ std::list mesh_idx; }// for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child) // if meshes was created then assign new indices with current aiNode - if(mesh_idx.size() > 0) + if(!mesh_idx.empty()) { std::list::const_iterator mit = mesh_idx.begin(); @@ -787,7 +787,7 @@ std::list ch_node; }// for(const CAMFImporter_NodeElement* ne: pConstellation.Child) // copy found aiNode's as children - if(ch_node.size() == 0) throw DeadlyImportError(" must have at least one ."); + if(ch_node.empty()) throw DeadlyImportError(" must have at least one ."); size_t ch_idx = 0; @@ -883,13 +883,13 @@ nl_clean_loop: if(node_list.size() > 1) { // walk through all nodes - for(std::list::iterator nl_it = node_list.begin(); nl_it != node_list.end(); nl_it++) + for(std::list::iterator nl_it = node_list.begin(); nl_it != node_list.end(); ++nl_it) { // and try to find them in another top nodes. std::list::const_iterator next_it = nl_it; - next_it++; - for(; next_it != node_list.end(); next_it++) + ++next_it; + for(; next_it != node_list.end(); ++next_it) { if((*next_it)->FindNode((*nl_it)->mName) != nullptr) { @@ -907,7 +907,7 @@ nl_clean_loop: // // // Nodes - if(node_list.size() > 0) + if(!node_list.empty()) { std::list::const_iterator nl_it = node_list.begin(); @@ -924,7 +924,7 @@ nl_clean_loop: // // Meshes - if(mesh_list.size() > 0) + if(!mesh_list.empty()) { std::list::const_iterator ml_it = mesh_list.begin(); diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 447a02bf2..eec805b54 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -137,7 +137,6 @@ SET( PUBLIC_HEADERS ${HEADER_PATH}/irrXMLWrapper.h ${HEADER_PATH}/BlobIOSystem.h ${HEADER_PATH}/MathFunctions.h - ${HEADER_PATH}/Macros.h ${HEADER_PATH}/Exceptional.h ${HEADER_PATH}/ByteSwapper.h ) @@ -766,6 +765,8 @@ ADD_ASSIMP_EXPORTER( X3D ) ADD_ASSIMP_IMPORTER( GLTF + glTF/glTFCommon.h + glTF/glTFCommon.cpp glTF/glTFAsset.h glTF/glTFAsset.inl glTF/glTFAssetWriter.h @@ -1057,6 +1058,8 @@ MESSAGE(STATUS "Disabled importer formats:${ASSIMP_IMPORTERS_DISABLED}") MESSAGE(STATUS "Enabled exporter formats:${ASSIMP_EXPORTERS_ENABLED}") MESSAGE(STATUS "Disabled exporter formats:${ASSIMP_EXPORTERS_DISABLED}") +SOURCE_GROUP( include\\assimp FILES ${PUBLIC_HEADERS} ) + SET( assimp_src # Assimp Files ${Core_SRCS} diff --git a/code/Collada/ColladaExporter.cpp b/code/Collada/ColladaExporter.cpp index cace8460e..6fd31ed3b 100644 --- a/code/Collada/ColladaExporter.cpp +++ b/code/Collada/ColladaExporter.cpp @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaExporter.h" #include +#include #include #include #include @@ -155,7 +156,7 @@ void ColladaExporter::WriteFile() { // ------------------------------------------------------------------------------------------------ // Writes the asset header void ColladaExporter::WriteHeader() { - static const ai_real epsilon = ai_real( 0.00001 ); + static const ai_real epsilon = Math::getEpsilon(); static const aiQuaternion x_rot(aiMatrix3x3( 0, -1, 0, 1, 0, 0, @@ -317,7 +318,7 @@ void ColladaExporter::WriteTextures() { std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char*) texture->achFormatHint); - std::unique_ptr outfile(mIOSystem->Open(mPath + name, "wb")); + std::unique_ptr outfile(mIOSystem->Open(mPath + mIOSystem->getOsSeparator() + name, "wb")); if(outfile == NULL) { throw DeadlyExportError("could not open output texture file: " + mPath + name); } @@ -1671,4 +1672,4 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) } #endif -#endif \ No newline at end of file +#endif diff --git a/code/Collada/ColladaLoader.cpp b/code/Collada/ColladaLoader.cpp index 6ef90c817..0fbc7d599 100644 --- a/code/Collada/ColladaLoader.cpp +++ b/code/Collada/ColladaLoader.cpp @@ -588,7 +588,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla // ------------------------------------------------------------------------------------------------ // Find mesh from either meshes or morph target meshes -aiMesh *ColladaLoader::findMesh(std::string meshid) { +aiMesh *ColladaLoader::findMesh(const std::string& meshid) { for (unsigned int i = 0; i < mMeshes.size(); ++i) { if (std::string(mMeshes[i]->mName.data) == meshid) { return mMeshes[i]; @@ -688,7 +688,7 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M Collada::MorphMethod method = Collada::Normalized; for (std::map::const_iterator it = pParser.mControllerLibrary.begin(); - it != pParser.mControllerLibrary.end(); it++) { + it != pParser.mControllerLibrary.end(); ++it) { const Collada::Controller &c = it->second; const Collada::Mesh* baseMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, c.mMeshId); diff --git a/code/Collada/ColladaLoader.h b/code/Collada/ColladaLoader.h index 92f390f17..dce46e06f 100644 --- a/code/Collada/ColladaLoader.h +++ b/code/Collada/ColladaLoader.h @@ -120,7 +120,7 @@ protected: void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget); - aiMesh *findMesh(std::string meshid); + aiMesh *findMesh(const std::string& meshid); /** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */ aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh, diff --git a/code/Common/BaseImporter.cpp b/code/Common/BaseImporter.cpp index 0a5694aa0..b77bbfe23 100644 --- a/code/Common/BaseImporter.cpp +++ b/code/Common/BaseImporter.cpp @@ -76,9 +76,25 @@ BaseImporter::~BaseImporter() { // nothing to do here } +void BaseImporter::UpdateImporterScale( Importer* pImp ) +{ + ai_assert(pImp != nullptr); + ai_assert(importerScale != 0.0); + ai_assert(fileScale != 0.0); + + double activeScale = importerScale * fileScale; + + // Set active scaling + pImp->SetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, static_cast( activeScale) ); + + ASSIMP_LOG_DEBUG_F("UpdateImporterScale scale set: %f", activeScale ); +} + // ------------------------------------------------------------------------------------------------ // Imports the given file and returns the imported data. -aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) { +aiScene* BaseImporter::ReadFile(Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) { + + m_progress = pImp->GetProgressHandler(); if (nullptr == m_progress) { return nullptr; @@ -100,6 +116,11 @@ aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, { InternReadFile( pFile, sc.get(), &filter); + // Calculate import scale hook - required because pImp not available anywhere else + // passes scale into ScaleProcess + UpdateImporterScale(pImp); + + } catch( const std::exception& err ) { // extract error description m_ErrorText = err.what(); @@ -112,7 +133,7 @@ aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, } // ------------------------------------------------------------------------------------------------ -void BaseImporter::SetupProperties(const Importer* /*pImp*/) +void BaseImporter::SetupProperties(const Importer* pImp) { // the default implementation does nothing } @@ -588,6 +609,8 @@ aiScene* BatchLoader::GetImport( unsigned int which ) return nullptr; } + + // ------------------------------------------------------------------------------------------------ void BatchLoader::LoadAll() { diff --git a/code/Common/DefaultIOSystem.cpp b/code/Common/DefaultIOSystem.cpp index d40b67de3..6fdc24dd8 100644 --- a/code/Common/DefaultIOSystem.cpp +++ b/code/Common/DefaultIOSystem.cpp @@ -61,83 +61,66 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -// maximum path length -// XXX http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html -#ifdef PATH_MAX -# define PATHLIMIT PATH_MAX -#else -# define PATHLIMIT 4096 +#ifdef _WIN32 +static std::wstring Utf8ToWide(const char* in) +{ + int size = MultiByteToWideChar(CP_UTF8, 0, in, -1, nullptr, 0); + // size includes terminating null; std::wstring adds null automatically + std::wstring out(static_cast(size) - 1, L'\0'); + MultiByteToWideChar(CP_UTF8, 0, in, -1, &out[0], size); + return out; +} + +static std::string WideToUtf8(const wchar_t* in) +{ + int size = WideCharToMultiByte(CP_UTF8, 0, in, -1, nullptr, 0, nullptr, nullptr); + // size includes terminating null; std::string adds null automatically + std::string out(static_cast(size) - 1, '\0'); + WideCharToMultiByte(CP_UTF8, 0, in, -1, &out[0], size, nullptr, nullptr); + return out; +} #endif // ------------------------------------------------------------------------------------------------ // Tests for the existence of a file at the given path. -bool DefaultIOSystem::Exists( const char* pFile) const +bool DefaultIOSystem::Exists(const char* pFile) const { #ifdef _WIN32 - wchar_t fileName16[PATHLIMIT]; - -#ifndef WindowsStore - bool isUnicode = IsTextUnicode(pFile, static_cast(strlen(pFile)), NULL) != 0; - if (isUnicode) { - - MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT); - struct __stat64 filestat; - if (0 != _wstat64(fileName16, &filestat)) { - return false; - } - } else { -#endif - FILE* file = ::fopen(pFile, "rb"); - if (!file) - return false; - - ::fclose(file); -#ifndef WindowsStore + struct __stat64 filestat; + if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) { + return false; } -#endif #else - FILE* file = ::fopen( pFile, "rb"); - if( !file) + FILE* file = ::fopen(pFile, "rb"); + if (!file) return false; - ::fclose( file); + ::fclose(file); #endif return true; } // ------------------------------------------------------------------------------------------------ // Open a new file with a given path. -IOStream* DefaultIOSystem::Open( const char* strFile, const char* strMode) +IOStream* DefaultIOSystem::Open(const char* strFile, const char* strMode) { - ai_assert(NULL != strFile); - ai_assert(NULL != strMode); + ai_assert(strFile != nullptr); + ai_assert(strMode != nullptr); FILE* file; #ifdef _WIN32 - wchar_t fileName16[PATHLIMIT]; -#ifndef WindowsStore - bool isUnicode = IsTextUnicode(strFile, static_cast(strlen(strFile)), NULL) != 0; - if (isUnicode) { - MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, strFile, -1, fileName16, PATHLIMIT); - std::string mode8(strMode); - file = ::_wfopen(fileName16, std::wstring(mode8.begin(), mode8.end()).c_str()); - } else { -#endif - file = ::fopen(strFile, strMode); -#ifndef WindowsStore - } -#endif + file = ::_wfopen(Utf8ToWide(strFile).c_str(), Utf8ToWide(strMode).c_str()); #else file = ::fopen(strFile, strMode); #endif - if (nullptr == file) + if (!file) return nullptr; - return new DefaultIOStream(file, (std::string) strFile); + return new DefaultIOStream(file, strFile); } // ------------------------------------------------------------------------------------------------ // Closes the given file and releases all resources associated with it. -void DefaultIOSystem::Close( IOStream* pFile) +void DefaultIOSystem::Close(IOStream* pFile) { delete pFile; } @@ -155,78 +138,56 @@ char DefaultIOSystem::getOsSeparator() const // ------------------------------------------------------------------------------------------------ // IOSystem default implementation (ComparePaths isn't a pure virtual function) -bool IOSystem::ComparePaths (const char* one, const char* second) const +bool IOSystem::ComparePaths(const char* one, const char* second) const { - return !ASSIMP_stricmp(one,second); + return !ASSIMP_stricmp(one, second); } // ------------------------------------------------------------------------------------------------ // Convert a relative path into an absolute path -inline static void MakeAbsolutePath (const char* in, char* _out) +inline static std::string MakeAbsolutePath(const char* in) { - ai_assert(in && _out); -#if defined( _MSC_VER ) || defined( __MINGW32__ ) -#ifndef WindowsStore - bool isUnicode = IsTextUnicode(in, static_cast(strlen(in)), NULL) != 0; - if (isUnicode) { - wchar_t out16[PATHLIMIT]; - wchar_t in16[PATHLIMIT]; - MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, in, -1, out16, PATHLIMIT); - wchar_t* ret = ::_wfullpath(out16, in16, PATHLIMIT); - if (ret) { - WideCharToMultiByte(CP_UTF8, MB_PRECOMPOSED, out16, -1, _out, PATHLIMIT, nullptr, nullptr); - } - if (!ret) { - // preserve the input path, maybe someone else is able to fix - // the path before it is accessed (e.g. our file system filter) - ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in)); - strcpy(_out, in); - } - - } else { -#endif - char* ret = :: _fullpath(_out, in, PATHLIMIT); - if (!ret) { - // preserve the input path, maybe someone else is able to fix - // the path before it is accessed (e.g. our file system filter) - ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in)); - strcpy(_out, in); - } -#ifndef WindowsStore + ai_assert(in); + std::string out; +#ifdef _WIN32 + wchar_t* ret = ::_wfullpath(nullptr, Utf8ToWide(in).c_str(), 0); + if (ret) { + out = WideToUtf8(ret); + free(ret); + } +#else + char* ret = realpath(in, nullptr); + if (ret) { + out = ret; + free(ret); } #endif -#else - // use realpath - char* ret = realpath(in, _out); - if(!ret) { + if (!ret) { // preserve the input path, maybe someone else is able to fix // the path before it is accessed (e.g. our file system filter) ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in)); - strcpy(_out,in); + out = in; } -#endif + return out; } // ------------------------------------------------------------------------------------------------ // DefaultIOSystem's more specialized implementation -bool DefaultIOSystem::ComparePaths (const char* one, const char* second) const +bool DefaultIOSystem::ComparePaths(const char* one, const char* second) const { // chances are quite good both paths are formatted identically, // so we can hopefully return here already - if( !ASSIMP_stricmp(one,second) ) + if (!ASSIMP_stricmp(one, second)) return true; - char temp1[PATHLIMIT]; - char temp2[PATHLIMIT]; + std::string temp1 = MakeAbsolutePath(one); + std::string temp2 = MakeAbsolutePath(second); - MakeAbsolutePath (one, temp1); - MakeAbsolutePath (second, temp2); - - return !ASSIMP_stricmp(temp1,temp2); + return !ASSIMP_stricmp(temp1, temp2); } // ------------------------------------------------------------------------------------------------ -std::string DefaultIOSystem::fileName( const std::string &path ) +std::string DefaultIOSystem::fileName(const std::string& path) { std::string ret = path; std::size_t last = ret.find_last_of("\\/"); @@ -235,16 +196,16 @@ std::string DefaultIOSystem::fileName( const std::string &path ) } // ------------------------------------------------------------------------------------------------ -std::string DefaultIOSystem::completeBaseName( const std::string &path ) +std::string DefaultIOSystem::completeBaseName(const std::string& path) { std::string ret = fileName(path); std::size_t pos = ret.find_last_of('.'); - if(pos != ret.npos) ret = ret.substr(0, pos); + if (pos != std::string::npos) ret = ret.substr(0, pos); return ret; } // ------------------------------------------------------------------------------------------------ -std::string DefaultIOSystem::absolutePath( const std::string &path ) +std::string DefaultIOSystem::absolutePath(const std::string& path) { std::string ret = path; std::size_t last = ret.find_last_of("\\/"); @@ -253,5 +214,3 @@ std::string DefaultIOSystem::absolutePath( const std::string &path ) } // ------------------------------------------------------------------------------------------------ - -#undef PATHLIMIT diff --git a/code/Common/Exporter.cpp b/code/Common/Exporter.cpp index 090b561ae..34d49c472 100644 --- a/code/Common/Exporter.cpp +++ b/code/Common/Exporter.cpp @@ -315,34 +315,6 @@ const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const cha return pimpl->blob; } -// ------------------------------------------------------------------------------------------------ -bool IsVerboseFormat(const aiMesh* mesh) { - // avoid slow vector specialization - std::vector seen(mesh->mNumVertices,0); - for(unsigned int i = 0; i < mesh->mNumFaces; ++i) { - const aiFace& f = mesh->mFaces[i]; - for(unsigned int j = 0; j < f.mNumIndices; ++j) { - if(++seen[f.mIndices[j]] == 2) { - // found a duplicate index - return false; - } - } - } - - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool IsVerboseFormat(const aiScene* pScene) { - for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - if(!IsVerboseFormat(pScene->mMeshes[i])) { - return false; - } - } - - return true; -} - // ------------------------------------------------------------------------------------------------ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing, const ExportProperties* pProperties) { @@ -352,7 +324,7 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c // format. They will likely not be aware that there is a flag in the scene to indicate // this, however. To avoid surprises and bug reports, we check for duplicates in // meshes upfront. - const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || IsVerboseFormat(pScene); + const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || MakeVerboseFormatProcess::IsVerboseFormat(pScene); pimpl->mProgressHandler->UpdateFileWrite(0, 4); @@ -472,7 +444,10 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c } ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry. - exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProperties ? pProperties : &emptyProperties); + ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties; + pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again); + exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); + exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); pimpl->mProgressHandler->UpdateFileWrite(4, 4); } catch (DeadlyExportError& err) { diff --git a/code/Common/SceneCombiner.cpp b/code/Common/SceneCombiner.cpp index e445bd743..f7b13cc95 100644 --- a/code/Common/SceneCombiner.cpp +++ b/code/Common/SceneCombiner.cpp @@ -1091,6 +1091,35 @@ void SceneCombiner::Copy( aiMesh** _dest, const aiMesh* src ) { aiFace& f = dest->mFaces[i]; GetArrayCopy(f.mIndices,f.mNumIndices); } + + // make a deep copy of all blend shapes + CopyPtrArray(dest->mAnimMeshes, dest->mAnimMeshes, dest->mNumAnimMeshes); +} + +// ------------------------------------------------------------------------------------------------ +void SceneCombiner::Copy(aiAnimMesh** _dest, const aiAnimMesh* src) { + if (nullptr == _dest || nullptr == src) { + return; + } + + aiAnimMesh* dest = *_dest = new aiAnimMesh(); + + // get a flat copy + ::memcpy(dest, src, sizeof(aiAnimMesh)); + + // and reallocate all arrays + GetArrayCopy(dest->mVertices, dest->mNumVertices); + GetArrayCopy(dest->mNormals, dest->mNumVertices); + GetArrayCopy(dest->mTangents, dest->mNumVertices); + GetArrayCopy(dest->mBitangents, dest->mNumVertices); + + unsigned int n = 0; + while (dest->HasTextureCoords(n)) + GetArrayCopy(dest->mTextureCoords[n++], dest->mNumVertices); + + n = 0; + while (dest->HasVertexColors(n)) + GetArrayCopy(dest->mColors[n++], dest->mNumVertices); } // ------------------------------------------------------------------------------------------------ @@ -1167,6 +1196,7 @@ void SceneCombiner::Copy( aiAnimation** _dest, const aiAnimation* src ) { // and reallocate all arrays CopyPtrArray( dest->mChannels, src->mChannels, dest->mNumChannels ); + CopyPtrArray( dest->mMorphMeshChannels, src->mMorphMeshChannels, dest->mNumMorphMeshChannels ); } // ------------------------------------------------------------------------------------------------ @@ -1186,6 +1216,26 @@ void SceneCombiner::Copy(aiNodeAnim** _dest, const aiNodeAnim* src) { GetArrayCopy( dest->mRotationKeys, dest->mNumRotationKeys ); } +void SceneCombiner::Copy(aiMeshMorphAnim** _dest, const aiMeshMorphAnim* src) { + if ( nullptr == _dest || nullptr == src ) { + return; + } + + aiMeshMorphAnim* dest = *_dest = new aiMeshMorphAnim(); + + // get a flat copy + ::memcpy(dest,src,sizeof(aiMeshMorphAnim)); + + // and reallocate all arrays + GetArrayCopy( dest->mKeys, dest->mNumKeys ); + for (ai_uint i = 0; i < dest->mNumKeys;++i) { + dest->mKeys[i].mValues = new unsigned int[dest->mKeys[i].mNumValuesAndWeights]; + dest->mKeys[i].mWeights = new double[dest->mKeys[i].mNumValuesAndWeights]; + ::memcpy(dest->mKeys[i].mValues, src->mKeys[i].mValues, dest->mKeys[i].mNumValuesAndWeights * sizeof(unsigned int)); + ::memcpy(dest->mKeys[i].mWeights, src->mKeys[i].mWeights, dest->mKeys[i].mNumValuesAndWeights * sizeof(double)); + } +} + // ------------------------------------------------------------------------------------------------ void SceneCombiner::Copy( aiCamera** _dest,const aiCamera* src) { if ( nullptr == _dest || nullptr == src ) { diff --git a/code/Common/Version.cpp b/code/Common/Version.cpp index cc94340ac..868cfb06a 100644 --- a/code/Common/Version.cpp +++ b/code/Common/Version.cpp @@ -46,8 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "ScenePrivate.h" -static const unsigned int MajorVersion = 4; -static const unsigned int MinorVersion = 1; +static const unsigned int MajorVersion = 5; +static const unsigned int MinorVersion = 0; // -------------------------------------------------------------------------------- // Legal information string - don't remove this. diff --git a/code/FBX/FBXConverter.cpp b/code/FBX/FBXConverter.cpp index fd7929e19..152be3277 100644 --- a/code/FBX/FBXConverter.cpp +++ b/code/FBX/FBXConverter.cpp @@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXImporter.h" #include +#include #include @@ -78,7 +79,7 @@ namespace Assimp { #define CONVERT_FBX_TIME(time) static_cast(time) / 46186158000L - FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit ) + FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones ) : defaultMaterialIndex() , lights() , cameras() @@ -90,8 +91,7 @@ namespace Assimp { , mNodeNames() , anim_fps() , out(out) - , doc(doc) - , mCurrentUnit(FbxUnit::cm) { + , doc(doc) { // animations need to be converted first since this will // populate the node_anim_chain_bits map, which is needed // to determine which nodes need to be generated. @@ -119,7 +119,6 @@ namespace Assimp { ConvertGlobalSettings(); TransferDataToScene(); - ConvertToUnitScale(unit); // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE // to make sure the scene passes assimp's validation. FBX files @@ -555,7 +554,7 @@ namespace Assimp { return; } - const float angle_epsilon = 1e-6f; + const float angle_epsilon = Math::getEpsilon(); out = aiMatrix4x4(); @@ -696,7 +695,7 @@ namespace Assimp { std::fill_n(chain, static_cast(TransformationComp_MAXIMUM), aiMatrix4x4()); // generate transformation matrices for all the different transformation components - const float zero_epsilon = 1e-6f; + const float zero_epsilon = Math::getEpsilon(); const aiVector3D all_ones(1.0f, 1.0f, 1.0f); const aiVector3D& PreRotation = PropertyGet(props, "PreRotation", ok); @@ -2003,6 +2002,21 @@ namespace Assimp { TrySetTextureProperties(out_mat, textures, "Maya|SpecularTexture", aiTextureType_SPECULAR, mesh); TrySetTextureProperties(out_mat, textures, "Maya|FalloffTexture", aiTextureType_OPACITY, mesh); TrySetTextureProperties(out_mat, textures, "Maya|ReflectionMapTexture", aiTextureType_REFLECTION, mesh); + + // Maya PBR + TrySetTextureProperties(out_mat, textures, "Maya|baseColor|file", aiTextureType_BASE_COLOR, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|normalCamera|file", aiTextureType_NORMAL_CAMERA, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|emissionColor|file", aiTextureType_EMISSION_COLOR, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|metalness|file", aiTextureType_METALNESS, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|diffuseRoughness|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh); + + // Maya stingray + TrySetTextureProperties(out_mat, textures, "Maya|TEX_color_map|file", aiTextureType_BASE_COLOR, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|TEX_normal_map|file", aiTextureType_NORMAL_CAMERA, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|TEX_emissive_map|file", aiTextureType_EMISSION_COLOR, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|TEX_metallic_map|file", aiTextureType_METALNESS, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|TEX_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh); } void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh) @@ -2954,7 +2968,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa TransformationCompDefaultValue(comp) ); - const float epsilon = 1e-6f; + const float epsilon = Math::getEpsilon(); return (dyn_val - static_val).SquareLength() < epsilon; } @@ -3537,46 +3551,6 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate()); } - void FBXConverter::ConvertToUnitScale( FbxUnit unit ) { - if (mCurrentUnit == unit) { - return; - } - - ai_real scale = 1.0; - if (mCurrentUnit == FbxUnit::cm) { - if (unit == FbxUnit::m) { - scale = (ai_real)0.01; - } else if (unit == FbxUnit::km) { - scale = (ai_real)0.00001; - } - } else if (mCurrentUnit == FbxUnit::m) { - if (unit == FbxUnit::cm) { - scale = (ai_real)100.0; - } else if (unit == FbxUnit::km) { - scale = (ai_real)0.001; - } - } else if (mCurrentUnit == FbxUnit::km) { - if (unit == FbxUnit::cm) { - scale = (ai_real)100000.0; - } else if (unit == FbxUnit::m) { - scale = (ai_real)1000.0; - } - } - - for (auto mesh : meshes) { - if (nullptr == mesh) { - continue; - } - - if (mesh->HasPositions()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - aiVector3D &pos = mesh->mVertices[i]; - pos *= scale; - } - } - } - } - void FBXConverter::TransferDataToScene() { ai_assert(!out->mMeshes); @@ -3630,9 +3604,9 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa } // ------------------------------------------------------------------------------------------------ - void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit) + void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones) { - FBXConverter converter(out, doc, removeEmptyBones, unit); + FBXConverter converter(out, doc, removeEmptyBones); } } // !FBX diff --git a/code/FBX/FBXConverter.h b/code/FBX/FBXConverter.h index fb1a87ca6..77ced1950 100644 --- a/code/FBX/FBXConverter.h +++ b/code/FBX/FBXConverter.h @@ -76,23 +76,13 @@ namespace Assimp { namespace FBX { class Document; - -enum class FbxUnit { - cm = 0, - m, - km, - NumUnits, - - Undefined -}; - /** * Convert a FBX #Document to #aiScene * @param out Empty scene to be populated * @param doc Parsed FBX document * @param removeEmptyBones Will remove bones, which do not have any references to vertices. */ -void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit); +void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones); /** Dummy class to encapsulate the conversion process */ class FBXConverter { @@ -123,7 +113,7 @@ public: }; public: - FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit); + FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones); ~FBXConverter(); private: @@ -430,10 +420,6 @@ private: void ConvertGlobalSettings(); - // ------------------------------------------------------------------------------------------------ - // Will perform the conversion from a given unit to the requested unit. - void ConvertToUnitScale(FbxUnit unit); - // ------------------------------------------------------------------------------------------------ // copy generated meshes, animations, lights, cameras and textures to the output scene void TransferDataToScene(); @@ -470,7 +456,6 @@ private: aiScene* const out; const FBX::Document& doc; - FbxUnit mCurrentUnit; }; } diff --git a/code/FBX/FBXExportProperty.cpp b/code/FBX/FBXExportProperty.cpp index f8593e629..f2a63b72b 100644 --- a/code/FBX/FBXExportProperty.cpp +++ b/code/FBX/FBXExportProperty.cpp @@ -59,11 +59,7 @@ namespace FBX { FBXExportProperty::FBXExportProperty(bool v) : type('C') -, data(1) { - data = { - uint8_t(v) - }; -} +, data(1, uint8_t(v)) {} FBXExportProperty::FBXExportProperty(int16_t v) : type('Y') diff --git a/code/FBX/FBXExporter.cpp b/code/FBX/FBXExporter.cpp index 8ebc8555a..9316dc4f0 100644 --- a/code/FBX/FBXExporter.cpp +++ b/code/FBX/FBXExporter.cpp @@ -67,6 +67,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include // RESOURCES: // https://code.blender.org/2013/08/fbx-binary-file-format-specification/ @@ -1005,6 +1006,9 @@ void FBXExporter::WriteObjects () object_node.EndProperties(outstream, binary, indent); object_node.BeginChildren(outstream, binary, indent); + bool bJoinIdenticalVertices = mProperties->GetPropertyBool("bJoinIdenticalVertices", true); + std::vector> vVertexIndice;//save vertex_indices as it is needed later + // geometry (aiMesh) mesh_uids.clear(); indent = 1; @@ -1031,21 +1035,35 @@ void FBXExporter::WriteObjects () std::vector vertex_indices; // map of vertex value to its index in the data vector std::map index_by_vertex_value; - int32_t index = 0; - for (size_t vi = 0; vi < m->mNumVertices; ++vi) { - aiVector3D vtx = m->mVertices[vi]; - auto elem = index_by_vertex_value.find(vtx); - if (elem == index_by_vertex_value.end()) { - vertex_indices.push_back(index); - index_by_vertex_value[vtx] = index; - flattened_vertices.push_back(vtx[0]); - flattened_vertices.push_back(vtx[1]); - flattened_vertices.push_back(vtx[2]); - ++index; - } else { - vertex_indices.push_back(int32_t(elem->second)); + if(bJoinIdenticalVertices){ + int32_t index = 0; + for (size_t vi = 0; vi < m->mNumVertices; ++vi) { + aiVector3D vtx = m->mVertices[vi]; + auto elem = index_by_vertex_value.find(vtx); + if (elem == index_by_vertex_value.end()) { + vertex_indices.push_back(index); + index_by_vertex_value[vtx] = index; + flattened_vertices.push_back(vtx[0]); + flattened_vertices.push_back(vtx[1]); + flattened_vertices.push_back(vtx[2]); + ++index; + } else { + vertex_indices.push_back(int32_t(elem->second)); + } } } + else { // do not join vertex, respect the export flag + vertex_indices.resize(m->mNumVertices); + std::iota(vertex_indices.begin(), vertex_indices.end(), 0); + for(unsigned int v = 0; v < m->mNumVertices; ++ v) { + aiVector3D vtx = m->mVertices[v]; + flattened_vertices.push_back(vtx.x); + flattened_vertices.push_back(vtx.y); + flattened_vertices.push_back(vtx.z); + } + } + vVertexIndice.push_back(vertex_indices); + FBX::Node::WritePropertyNode( "Vertices", flattened_vertices, outstream, binary, indent ); @@ -1116,6 +1134,51 @@ void FBXExporter::WriteObjects () normals.End(outstream, binary, indent, true); } + // colors, if any + // TODO only one color channel currently + const int32_t colorChannelIndex = 0; + if (m->HasVertexColors(colorChannelIndex)) { + FBX::Node vertexcolors("LayerElementColor", int32_t(colorChannelIndex)); + vertexcolors.Begin(outstream, binary, indent); + vertexcolors.DumpProperties(outstream, binary, indent); + vertexcolors.EndProperties(outstream, binary, indent); + vertexcolors.BeginChildren(outstream, binary, indent); + indent = 3; + FBX::Node::WritePropertyNode( + "Version", int32_t(101), outstream, binary, indent + ); + char layerName[8]; + sprintf(layerName, "COLOR_%d", colorChannelIndex); + FBX::Node::WritePropertyNode( + "Name", (const char*)layerName, outstream, binary, indent + ); + FBX::Node::WritePropertyNode( + "MappingInformationType", "ByPolygonVertex", + outstream, binary, indent + ); + FBX::Node::WritePropertyNode( + "ReferenceInformationType", "Direct", + outstream, binary, indent + ); + std::vector color_data; + color_data.reserve(4 * polygon_data.size()); + for (size_t fi = 0; fi < m->mNumFaces; ++fi) { + const aiFace &f = m->mFaces[fi]; + for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) { + const aiColor4D &c = m->mColors[colorChannelIndex][f.mIndices[pvi]]; + color_data.push_back(c.r); + color_data.push_back(c.g); + color_data.push_back(c.b); + color_data.push_back(c.a); + } + } + FBX::Node::WritePropertyNode( + "Colors", color_data, outstream, binary, indent + ); + indent = 2; + vertexcolors.End(outstream, binary, indent, true); + } + // uvs, if any for (size_t uvi = 0; uvi < m->GetNumUVChannels(); ++uvi) { if (m->mNumUVComponents[uvi] > 2) { @@ -1209,6 +1272,11 @@ void FBXExporter::WriteObjects () le.AddChild("Type", "LayerElementNormal"); le.AddChild("TypedIndex", int32_t(0)); layer.AddChild(le); + // TODO only 1 color channel currently + le = FBX::Node("LayerElement"); + le.AddChild("Type", "LayerElementColor"); + le.AddChild("TypedIndex", int32_t(0)); + layer.AddChild(le); le = FBX::Node("LayerElement"); le.AddChild("Type", "LayerElementMaterial"); le.AddChild("TypedIndex", int32_t(0)); @@ -1221,7 +1289,7 @@ void FBXExporter::WriteObjects () for(unsigned int lr = 1; lr < m->GetNumUVChannels(); ++ lr) { - FBX::Node layerExtra("Layer", int32_t(1)); + FBX::Node layerExtra("Layer", int32_t(lr)); layerExtra.AddChild("Version", int32_t(100)); FBX::Node leExtra("LayerElement"); leExtra.AddChild("Type", "LayerElementUV"); @@ -1748,28 +1816,8 @@ void FBXExporter::WriteObjects () // connect it connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]); - // we will be indexing by vertex... - // but there might be a different number of "vertices" - // between assimp and our output FBX. - // this code is cut-and-pasted from the geometry section above... - // ideally this should not be so. - // --- - // index of original vertex in vertex data vector - std::vector vertex_indices; - // map of vertex value to its index in the data vector - std::map index_by_vertex_value; - int32_t index = 0; - for (size_t vi = 0; vi < m->mNumVertices; ++vi) { - aiVector3D vtx = m->mVertices[vi]; - auto elem = index_by_vertex_value.find(vtx); - if (elem == index_by_vertex_value.end()) { - vertex_indices.push_back(index); - index_by_vertex_value[vtx] = index; - ++index; - } else { - vertex_indices.push_back(int32_t(elem->second)); - } - } + //computed before + std::vector& vertex_indices = vVertexIndice[mi]; // TODO, FIXME: this won't work if anything is not in the bind pose. // for now if such a situation is detected, we throw an exception. @@ -2435,7 +2483,7 @@ void FBXExporter::WriteModelNodes( void FBXExporter::WriteAnimationCurveNode( StreamWriterLE& outstream, int64_t uid, - std::string name, // "T", "R", or "S" + const std::string& name, // "T", "R", or "S" aiVector3D default_value, std::string property_name, // "Lcl Translation" etc int64_t layer_uid, diff --git a/code/FBX/FBXExporter.h b/code/FBX/FBXExporter.h index 71fb55c57..1ae727eda 100644 --- a/code/FBX/FBXExporter.h +++ b/code/FBX/FBXExporter.h @@ -156,7 +156,7 @@ namespace Assimp void WriteAnimationCurveNode( StreamWriterLE& outstream, int64_t uid, - std::string name, // "T", "R", or "S" + const std::string& name, // "T", "R", or "S" aiVector3D default_value, std::string property_name, // "Lcl Translation" etc int64_t animation_layer_uid, diff --git a/code/FBX/FBXImporter.cpp b/code/FBX/FBXImporter.cpp index 09694a38f..c8c1a6853 100644 --- a/code/FBX/FBXImporter.cpp +++ b/code/FBX/FBXImporter.cpp @@ -185,16 +185,15 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS // take the raw parse-tree and convert it to a FBX DOM Document doc(parser,settings); - FbxUnit unit(FbxUnit::cm); - if (settings.convertToMeters) { - unit = FbxUnit::m; - } - // convert the FBX DOM to aiScene - ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones, unit); - - // units is relative to CM :) we need it in meters for assimp - SetFileScale( doc.GlobalSettings().UnitScaleFactor() * 0.01f); + ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones); + + // size relative to cm + float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor(); + + // Set FBX file scale is relative to CM must be converted to M for + // assimp universal format (M) + SetFileScale( size_relative_to_cm * 0.01f); std::for_each(tokens.begin(),tokens.end(),Util::delete_fun()); } diff --git a/code/Importer/IFC/IFCCurve.cpp b/code/Importer/IFC/IFCCurve.cpp index b0a1fdaa9..a817b4f9f 100644 --- a/code/Importer/IFC/IFCCurve.cpp +++ b/code/Importer/IFC/IFCCurve.cpp @@ -311,10 +311,9 @@ class TrimmedCurve : public BoundedCurve { public: // -------------------------------------------------- TrimmedCurve(const Schema_2x3::IfcTrimmedCurve& entity, ConversionData& conv) - : BoundedCurve(entity,conv) + : BoundedCurve(entity,conv), + base(std::shared_ptr(Curve::Convert(entity.BasisCurve,conv))) { - base = std::shared_ptr(Curve::Convert(entity.BasisCurve,conv)); - typedef std::shared_ptr Entry; // for some reason, trimmed curves can either specify a parametric value @@ -500,7 +499,7 @@ bool Curve::InRange(IfcFloat u) const { if (IsClosed()) { return true; } - const IfcFloat epsilon = 1e-5; + const IfcFloat epsilon = Math::getEpsilon(); return u - range.first > -epsilon && range.second - u > -epsilon; } #endif diff --git a/code/Importer/IFC/IFCGeometry.cpp b/code/Importer/IFC/IFCGeometry.cpp index 032030112..d1c7aee19 100644 --- a/code/Importer/IFC/IFCGeometry.cpp +++ b/code/Importer/IFC/IFCGeometry.cpp @@ -128,7 +128,7 @@ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t m outer_polygon_it = begin + master_bounds; } else { - for(iit = begin; iit != end; iit++) { + for(iit = begin; iit != end; ++iit) { // find the polygon with the largest area and take it as the outer bound. IfcVector3& n = normals[std::distance(begin,iit)]; const IfcFloat area = n.SquareLength(); diff --git a/code/Importer/IFC/IFCOpenings.cpp b/code/Importer/IFC/IFCOpenings.cpp index a24ffb4ca..d6c40b383 100644 --- a/code/Importer/IFC/IFCOpenings.cpp +++ b/code/Importer/IFC/IFCOpenings.cpp @@ -593,7 +593,7 @@ typedef std::vector(); return (std::fabs(bb.second.x - ibb.first.x) < epsilon && bb.first.y <= ibb.second.y && bb.second.y >= ibb.first.y) || (std::fabs(bb.first.x - ibb.second.x) < epsilon && ibb.first.y <= bb.second.y && ibb.second.y >= bb.first.y) || (std::fabs(bb.second.y - ibb.first.y) < epsilon && bb.first.x <= ibb.second.x && bb.second.x >= ibb.first.x) || @@ -681,7 +681,7 @@ bool IntersectingLineSegments(const IfcVector2& n0, const IfcVector2& n1, // ------------------------------------------------------------------------------------------------ void FindAdjacentContours(ContourVector::iterator current, const ContourVector& contours) { - const IfcFloat sqlen_epsilon = static_cast(1e-8); + const IfcFloat sqlen_epsilon = static_cast(Math::getEpsilon()); const BoundingBox& bb = (*current).bb; // What is to be done here is to populate the skip lists for the contour @@ -758,7 +758,7 @@ void FindAdjacentContours(ContourVector::iterator current, const ContourVector& // ------------------------------------------------------------------------------------------------ AI_FORCE_INLINE bool LikelyBorder(const IfcVector2& vdelta) { - const IfcFloat dot_point_epsilon = static_cast(1e-5); + const IfcFloat dot_point_epsilon = static_cast(Math::getEpsilon()); return std::fabs(vdelta.x * vdelta.y) < dot_point_epsilon; } diff --git a/code/Irr/IRRMeshLoader.cpp b/code/Irr/IRRMeshLoader.cpp index f3aed5943..057218464 100644 --- a/code/Irr/IRRMeshLoader.cpp +++ b/code/Irr/IRRMeshLoader.cpp @@ -57,7 +57,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include using namespace Assimp; using namespace irr; diff --git a/code/MD2/MD2Loader.cpp b/code/MD2/MD2Loader.cpp index a26f70533..7023c0fa3 100644 --- a/code/MD2/MD2Loader.cpp +++ b/code/MD2/MD2Loader.cpp @@ -344,7 +344,7 @@ void MD2Importer::InternReadFile( const std::string& pFile, if (pcSkins->name[0]) { aiString szString; - const size_t iLen = ::strlen(pcSkins->name); + const ai_uint32 iLen = (ai_uint32) ::strlen(pcSkins->name); ::memcpy(szString.data,pcSkins->name,iLen); szString.data[iLen] = '\0'; szString.length = iLen; diff --git a/code/MD5/MD5Loader.cpp b/code/MD5/MD5Loader.cpp index 38c44b515..a4aed8d70 100644 --- a/code/MD5/MD5Loader.cpp +++ b/code/MD5/MD5Loader.cpp @@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "MD5Loader.h" #include #include +#include #include #include #include @@ -64,7 +65,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; // Minimum weight value. Weights inside [-n ... n] are ignored -#define AI_MD5_WEIGHT_EPSILON 1e-5f +#define AI_MD5_WEIGHT_EPSILON Math::getEpsilon() static const aiImporterDesc desc = { diff --git a/code/MD5/MD5Parser.cpp b/code/MD5/MD5Parser.cpp index b955e9cbc..37490212f 100644 --- a/code/MD5/MD5Parser.cpp +++ b/code/MD5/MD5Parser.cpp @@ -235,7 +235,7 @@ bool MD5Parser::ParseSection(Section& out) const char* szStart = ++sz; \ while('\"'!=*sz)++sz; \ const char* szEnd = (sz++); \ - out.length = (size_t)(szEnd - szStart); \ + out.length = (ai_uint32) (szEnd - szStart); \ ::memcpy(out.data,szStart,out.length); \ out.data[out.length] = '\0'; // ------------------------------------------------------------------------------------------------ diff --git a/code/MDL/MDLLoader.cpp b/code/MDL/MDLLoader.cpp index 9ca36c079..d71057d55 100644 --- a/code/MDL/MDLLoader.cpp +++ b/code/MDL/MDLLoader.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -54,7 +52,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "MDL/MDLDefaultColorMap.h" #include "MD2/MD2FileData.h" -#include #include #include #include @@ -94,23 +91,24 @@ static const aiImporterDesc desc = { // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer MDLImporter::MDLImporter() - : configFrameID(), - mBuffer(), - iGSFileVersion(), - pIOHandler(), - pScene(), - iFileSize() -{} +: configFrameID() +, mBuffer() +, iGSFileVersion() +, pIOHandler() +, pScene() +, iFileSize() { + // empty +} // ------------------------------------------------------------------------------------------------ // Destructor, private as well -MDLImporter::~MDLImporter() -{} +MDLImporter::~MDLImporter() { + // empty +} // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const -{ +bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { const std::string extension = GetExtension(pFile); // if check for extension is not enough, check for the magic tokens @@ -404,23 +402,15 @@ void MDLImporter::InternReadFile_Quake1() { // now get a pointer to the first frame in the file BE_NCONST MDL::Frame* pcFrames = (BE_NCONST MDL::Frame*)szCurrent; - BE_NCONST MDL::SimpleFrame* pcFirstFrame; + MDL::SimpleFrame* pcFirstFrame; if (0 == pcFrames->type) { // get address of single frame - pcFirstFrame = &pcFrames->frame; + pcFirstFrame =( MDL::SimpleFrame*) &pcFrames->frame; } else { // get the first frame in the group - -#if 1 - // FIXME: the cast is wrong and cause a warning on clang 5.0 - // disable this code for now, fix it later - ai_assert(false && "Bad pointer cast"); - pcFirstFrame = nullptr; // Workaround: msvc++ C4703 error -#else - BE_NCONST MDL::GroupFrame* pcFrames2 = (BE_NCONST MDL::GroupFrame*)pcFrames; - pcFirstFrame = (BE_NCONST MDL::SimpleFrame*)(&pcFrames2->time + pcFrames->type); -#endif + BE_NCONST MDL::GroupFrame* pcFrames2 = (BE_NCONST MDL::GroupFrame*) pcFrames; + pcFirstFrame = &(pcFrames2->frames[0]); } BE_NCONST MDL::Vertex* pcVertices = (BE_NCONST MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name)); VALIDATE_FILE_SIZE((const unsigned char*)(pcVertices + pcHeader->num_verts)); diff --git a/code/MDL/MDLLoader.h b/code/MDL/MDLLoader.h index bbe945529..c5ebac024 100644 --- a/code/MDL/MDLLoader.h +++ b/code/MDL/MDLLoader.h @@ -89,16 +89,12 @@ public: MDLImporter(); ~MDLImporter(); - -public: - // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; - // ------------------------------------------------------------------- /** Called prior to ReadFile(). * The function is a request to the importer to update its configuration @@ -107,8 +103,6 @@ public: void SetupProperties(const Importer* pImp); protected: - - // ------------------------------------------------------------------- /** Return importer meta information. * See #BaseImporter::GetInfo for the details @@ -122,8 +116,6 @@ protected: void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); -protected: - // ------------------------------------------------------------------- /** Import a quake 1 MDL file (IDPO) */ @@ -154,7 +146,6 @@ protected: void SizeCheck(const void* szPos); void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine); - // ------------------------------------------------------------------- /** Validate the header data structure of a game studio MDL7 file * \param pcHeader Input header to be validated @@ -167,7 +158,6 @@ protected: */ void ValidateHeader_Quake1(const MDL::Header* pcHeader); - // ------------------------------------------------------------------- /** Try to load a palette from the current directory (colormap.lmp) * If it is not found the default palette of Quake1 is returned @@ -179,9 +169,8 @@ protected: */ void FreePalette(const unsigned char* pszColorMap); - // ------------------------------------------------------------------- - /** Load a paletized texture from the file and convert it to 32bpp + /** Load a palletized texture from the file and convert it to 32bpp */ void CreateTextureARGB8_3DGS_MDL3(const unsigned char* szData); @@ -195,7 +184,6 @@ protected: unsigned int iType, unsigned int* piSkip); - // ------------------------------------------------------------------- /** Used to load textures from MDL5 * \param szData Input data @@ -206,7 +194,6 @@ protected: unsigned int iType, unsigned int* piSkip); - // ------------------------------------------------------------------- /** Checks whether a texture can be replaced with a single color * This is useful for all file formats before MDL7 (all those @@ -218,14 +205,12 @@ protected: */ aiColor4D ReplaceTextureWithColor(const aiTexture* pcTexture); - // ------------------------------------------------------------------- /** Converts the absolute texture coordinates in MDL5 files to * relative in a range between 0 and 1 */ void CalculateUVCoordinates_MDL5(); - // ------------------------------------------------------------------- /** Read an UV coordinate from the file. If the file format is not * MDL5, the function calculates relative texture coordinates @@ -245,7 +230,6 @@ protected: */ void SetupMaterialProperties_3DGS_MDL5_Quake1( ); - // ------------------------------------------------------------------- /** Parse a skin lump in a MDL7/HMP7 file with all of its features * variant 1: Current cursor position is the beginning of the skin header diff --git a/code/Material/MaterialSystem.cpp b/code/Material/MaterialSystem.cpp index d0b39093b..0be6e9f7b 100644 --- a/code/Material/MaterialSystem.cpp +++ b/code/Material/MaterialSystem.cpp @@ -51,7 +51,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include using namespace Assimp; @@ -545,23 +544,7 @@ aiReturn aiMaterial::AddProperty (const aiString* pInput, unsigned int type, unsigned int index) { - // We don't want to add the whole buffer .. write a 32 bit length - // prefix followed by the zero-terminated UTF8 string. - // (HACK) I don't want to break the ABI now, but we definitely - // ought to change aiString::mLength to uint32_t one day. - if (sizeof(size_t) == 8) { - aiString copy = *pInput; - uint32_t* s = reinterpret_cast(©.length); - s[1] = static_cast(pInput->length); - - return AddBinaryProperty(s+1, - static_cast(pInput->length+1+4), - pKey, - type, - index, - aiPTI_String); - } - ai_assert(sizeof(size_t)==4); + ai_assert(sizeof(ai_uint32)==4); return AddBinaryProperty(pInput, static_cast(pInput->length+1+4), pKey, diff --git a/code/Obj/ObjFileImporter.cpp b/code/Obj/ObjFileImporter.cpp index 549956474..26cc6d1f9 100644 --- a/code/Obj/ObjFileImporter.cpp +++ b/code/Obj/ObjFileImporter.cpp @@ -79,10 +79,7 @@ using namespace std; ObjFileImporter::ObjFileImporter() : m_Buffer() , m_pRootObject( nullptr ) -, m_strAbsPath( "" ) { - DefaultIOSystem io; - m_strAbsPath = io.getOsSeparator(); -} +, m_strAbsPath( std::string(1, DefaultIOSystem().getOsSeparator()) ) {} // ------------------------------------------------------------------------------------------------ // Destructor. diff --git a/code/Obj/ObjFileParser.cpp b/code/Obj/ObjFileParser.cpp index 97ef4af70..699aafe6a 100644 --- a/code/Obj/ObjFileParser.cpp +++ b/code/Obj/ObjFileParser.cpp @@ -244,8 +244,8 @@ void ObjFileParser::copyNextWord(char *pBuffer, size_t length) { size_t index = 0; m_DataIt = getNextWord(m_DataIt, m_DataItEnd); if ( *m_DataIt == '\\' ) { - m_DataIt++; - m_DataIt++; + ++m_DataIt; + ++m_DataIt; m_DataIt = getNextWord( m_DataIt, m_DataItEnd ); } while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) { diff --git a/code/Ply/PlyLoader.cpp b/code/Ply/PlyLoader.cpp index 3924305cb..ca1ec22f8 100644 --- a/code/Ply/PlyLoader.cpp +++ b/code/Ply/PlyLoader.cpp @@ -49,7 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "PlyLoader.h" #include -#include #include #include #include diff --git a/code/PostProcessing/ComputeUVMappingProcess.cpp b/code/PostProcessing/ComputeUVMappingProcess.cpp index bb571a551..df4d44337 100644 --- a/code/PostProcessing/ComputeUVMappingProcess.cpp +++ b/code/PostProcessing/ComputeUVMappingProcess.cpp @@ -354,12 +354,12 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& } else if (axis * base_axis_z >= angle_epsilon) { FindMeshCenter(mesh, center, min, max); - diffu = max.y - min.y; - diffv = max.z - min.z; + diffu = max.x - min.x; + diffv = max.y - min.y; for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { const aiVector3D& pos = mesh->mVertices[pnt]; - out[pnt].Set((pos.y - min.y) / diffu,(pos.x - min.x) / diffv,0.0); + out[pnt].Set((pos.x - min.x) / diffu,(pos.y - min.y) / diffv,0.0); } } // slower code path in case the mapping axis is not one of the coordinate system axes diff --git a/code/PostProcessing/FindInvalidDataProcess.cpp b/code/PostProcessing/FindInvalidDataProcess.cpp index 433f04244..016884c6e 100644 --- a/code/PostProcessing/FindInvalidDataProcess.cpp +++ b/code/PostProcessing/FindInvalidDataProcess.cpp @@ -52,7 +52,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FindInvalidDataProcess.h" #include "ProcessHelper.h" -#include #include #include diff --git a/code/PostProcessing/MakeVerboseFormat.cpp b/code/PostProcessing/MakeVerboseFormat.cpp index 50ff5ed93..41f50a5ba 100644 --- a/code/PostProcessing/MakeVerboseFormat.cpp +++ b/code/PostProcessing/MakeVerboseFormat.cpp @@ -224,3 +224,32 @@ bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh) } return (pcMesh->mNumVertices != iOldNumVertices); } + + +// ------------------------------------------------------------------------------------------------ +bool IsMeshInVerboseFormat(const aiMesh* mesh) { + // avoid slow vector specialization + std::vector seen(mesh->mNumVertices,0); + for(unsigned int i = 0; i < mesh->mNumFaces; ++i) { + const aiFace& f = mesh->mFaces[i]; + for(unsigned int j = 0; j < f.mNumIndices; ++j) { + if(++seen[f.mIndices[j]] == 2) { + // found a duplicate index + return false; + } + } + } + + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool MakeVerboseFormatProcess::IsVerboseFormat(const aiScene* pScene) { + for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + if(!IsMeshInVerboseFormat(pScene->mMeshes[i])) { + return false; + } + } + + return true; +} diff --git a/code/PostProcessing/MakeVerboseFormat.h b/code/PostProcessing/MakeVerboseFormat.h index 1adf8e2f6..8565d5933 100644 --- a/code/PostProcessing/MakeVerboseFormat.h +++ b/code/PostProcessing/MakeVerboseFormat.h @@ -94,6 +94,13 @@ public: * @param pScene The imported data to work at. */ void Execute( aiScene* pScene); +public: + + // ------------------------------------------------------------------- + /** Checks whether the scene is already in verbose format. + * @param pScene The data to check. + * @return true if the scene is already in verbose format. */ + static bool IsVerboseFormat(const aiScene* pScene); private: diff --git a/code/PostProcessing/ValidateDataStructure.cpp b/code/PostProcessing/ValidateDataStructure.cpp index 712fd6943..75d1b6ef7 100644 --- a/code/PostProcessing/ValidateDataStructure.cpp +++ b/code/PostProcessing/ValidateDataStructure.cpp @@ -538,13 +538,17 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation) { Validate(&pAnimation->mName); - // validate all materials - if (pAnimation->mNumChannels) + // validate all animations + if (pAnimation->mNumChannels || pAnimation->mNumMorphMeshChannels) { - if (!pAnimation->mChannels) { + if (!pAnimation->mChannels && pAnimation->mNumChannels) { ReportError("aiAnimation::mChannels is NULL (aiAnimation::mNumChannels is %i)", pAnimation->mNumChannels); } + if (!pAnimation->mMorphMeshChannels && pAnimation->mNumMorphMeshChannels) { + ReportError("aiAnimation::mMorphMeshChannels is NULL (aiAnimation::mNumMorphMeshChannels is %i)", + pAnimation->mNumMorphMeshChannels); + } for (unsigned int i = 0; i < pAnimation->mNumChannels;++i) { if (!pAnimation->mChannels[i]) @@ -554,6 +558,15 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation) } Validate(pAnimation, pAnimation->mChannels[i]); } + for (unsigned int i = 0; i < pAnimation->mNumMorphMeshChannels;++i) + { + if (!pAnimation->mMorphMeshChannels[i]) + { + ReportError("aiAnimation::mMorphMeshChannels[%i] is NULL (aiAnimation::mNumMorphMeshChannels is %i)", + i, pAnimation->mNumMorphMeshChannels); + } + Validate(pAnimation, pAnimation->mMorphMeshChannels[i]); + } } else { ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there."); @@ -903,6 +916,48 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation, } } +void ValidateDSProcess::Validate( const aiAnimation* pAnimation, + const aiMeshMorphAnim* pMeshMorphAnim) +{ + Validate(&pMeshMorphAnim->mName); + + if (!pMeshMorphAnim->mNumKeys) { + ReportError("Empty mesh morph animation channel"); + } + + // otherwise check whether one of the keys exceeds the total duration of the animation + if (pMeshMorphAnim->mNumKeys) + { + if (!pMeshMorphAnim->mKeys) + { + ReportError("aiMeshMorphAnim::mKeys is NULL (aiMeshMorphAnim::mNumKeys is %i)", + pMeshMorphAnim->mNumKeys); + } + double dLast = -10e10; + for (unsigned int i = 0; i < pMeshMorphAnim->mNumKeys;++i) + { + // ScenePreprocessor will compute the duration if still the default value + // (Aramis) Add small epsilon, comparison tended to fail if max_time == duration, + // seems to be due the compilers register usage/width. + if (pAnimation->mDuration > 0. && pMeshMorphAnim->mKeys[i].mTime > pAnimation->mDuration+0.001) + { + ReportError("aiMeshMorphAnim::mKeys[%i].mTime (%.5f) is larger " + "than aiAnimation::mDuration (which is %.5f)",i, + (float)pMeshMorphAnim->mKeys[i].mTime, + (float)pAnimation->mDuration); + } + if (i && pMeshMorphAnim->mKeys[i].mTime <= dLast) + { + ReportWarning("aiMeshMorphAnim::mKeys[%i].mTime (%.5f) is smaller " + "than aiMeshMorphAnim::mKeys[%i] (which is %.5f)",i, + (float)pMeshMorphAnim->mKeys[i].mTime, + i-1, (float)dLast); + } + dLast = pMeshMorphAnim->mKeys[i].mTime; + } + } +} + // ------------------------------------------------------------------------------------------------ void ValidateDSProcess::Validate( const aiNode* pNode) { @@ -958,7 +1013,7 @@ void ValidateDSProcess::Validate( const aiString* pString) { if (pString->length > MAXLEN) { - ReportError("aiString::length is too large (%lu, maximum is %lu)", + ReportError("aiString::length is too large (%u, maximum is %lu)", pString->length,MAXLEN); } const char* sz = pString->data; diff --git a/code/PostProcessing/ValidateDataStructure.h b/code/PostProcessing/ValidateDataStructure.h index 0b891ef41..7b309c925 100644 --- a/code/PostProcessing/ValidateDataStructure.h +++ b/code/PostProcessing/ValidateDataStructure.h @@ -55,6 +55,7 @@ struct aiBone; struct aiMesh; struct aiAnimation; struct aiNodeAnim; +struct aiMeshMorphAnim; struct aiTexture; struct aiMaterial; struct aiNode; @@ -150,6 +151,13 @@ protected: void Validate( const aiAnimation* pAnimation, const aiNodeAnim* pBoneAnim); + /** Validates a mesh morph animation channel. + * @param pAnimation Input animation. + * @param pMeshMorphAnim Mesh morph animation channel. + * */ + void Validate( const aiAnimation* pAnimation, + const aiMeshMorphAnim* pMeshMorphAnim); + // ------------------------------------------------------------------- /** Validates a node and all of its subnodes * @param Node Input node*/ diff --git a/code/X/XFileParser.cpp b/code/X/XFileParser.cpp index 08d3c88da..8fcf87cf6 100644 --- a/code/X/XFileParser.cpp +++ b/code/X/XFileParser.cpp @@ -596,11 +596,11 @@ void XFileParser::ParseDataObjectMeshNormals( Mesh* pMesh) // do not crah when no face definitions are there if (numFaces > 0) { // normal face creation - pMesh->mNormFaces.resize( pMesh->mNormFaces.size() + numFaces ); + pMesh->mNormFaces.resize( numFaces ); for( unsigned int a = 0; a < numFaces; ++a ) { unsigned int numIndices = ReadInt(); - pMesh->mNormFaces.push_back( Face() ); - Face& face = pMesh->mNormFaces.back(); + pMesh->mNormFaces[a] = Face(); + Face& face = pMesh->mNormFaces[a]; for( unsigned int b = 0; b < numIndices; ++b ) { face.mIndices.push_back( ReadInt()); } diff --git a/code/X3D/X3DExporter.cpp b/code/X3D/X3DExporter.cpp index 9839e6ca6..e5eeb0886 100644 --- a/code/X3D/X3DExporter.cpp +++ b/code/X3D/X3DExporter.cpp @@ -68,7 +68,7 @@ aiMatrix4x4 out_matr; } // multiplicate all matrices in reverse order - for(std::list::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); rit++) out_matr = out_matr * (*rit); + for(std::list::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); ++rit) out_matr = out_matr * (*rit); return out_matr; } diff --git a/code/X3D/X3DImporter.cpp b/code/X3D/X3DImporter.cpp index 96fcf067a..367d84fcf 100644 --- a/code/X3D/X3DImporter.cpp +++ b/code/X3D/X3DImporter.cpp @@ -136,8 +136,8 @@ X3DImporter::~X3DImporter() { void X3DImporter::Clear() { NodeElement_Cur = nullptr; // Delete all elements - if(NodeElement_List.size()) { - for ( std::list::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++ ) { + if(!NodeElement_List.empty()) { + for ( std::list::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it ) { delete *it; } NodeElement_List.clear(); @@ -151,7 +151,7 @@ void X3DImporter::Clear() { bool X3DImporter::FindNodeElement_FromRoot(const std::string& pID, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement) { - for(std::list::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++) + for(std::list::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it) { if(((*it)->Type == pType) && ((*it)->ID == pID)) { @@ -182,7 +182,7 @@ bool X3DImporter::FindNodeElement_FromNode(CX3DImporter_NodeElement* pStartNode, }// if((pStartNode->Type() == pType) && (pStartNode->ID() == pID)) // Check childs of pStartNode. - for(std::list::iterator ch_it = pStartNode->Child.begin(); ch_it != pStartNode->Child.end(); ch_it++) + for(std::list::iterator ch_it = pStartNode->Child.begin(); ch_it != pStartNode->Child.end(); ++ch_it) { found = FindNodeElement_FromNode(*ch_it, pID, pType, pElement); if ( found ) @@ -614,10 +614,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol3f(const int pAttrIdx, std::ve XML_ReadNode_GetAttrVal_AsListCol3f(pAttrIdx, tlist);// read as list // and copy to array - if(tlist.size() > 0) + if(!tlist.empty()) { pValue.reserve(tlist.size()); - for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); + for(std::list::iterator it = tlist.begin(); it != tlist.end(); ++it) pValue.push_back(*it); } } @@ -647,10 +647,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol4f(const int pAttrIdx, std::ve XML_ReadNode_GetAttrVal_AsListCol4f(pAttrIdx, tlist);// read as list // and copy to array - if(tlist.size() > 0) + if(!tlist.empty()) { pValue.reserve(tlist.size()); - for ( std::list::iterator it = tlist.begin(); it != tlist.end(); it++ ) + for ( std::list::iterator it = tlist.begin(); it != tlist.end(); ++it ) { pValue.push_back( *it ); } @@ -684,10 +684,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrVec2f(const int pAttrIdx, std::ve XML_ReadNode_GetAttrVal_AsListVec2f(pAttrIdx, tlist);// read as list // and copy to array - if(tlist.size() > 0) + if(!tlist.empty()) { pValue.reserve(tlist.size()); - for ( std::list::iterator it = tlist.begin(); it != tlist.end(); it++ ) + for ( std::list::iterator it = tlist.begin(); it != tlist.end(); ++it ) { pValue.push_back( *it ); } @@ -722,10 +722,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrVec3f(const int pAttrIdx, std::ve XML_ReadNode_GetAttrVal_AsListVec3f(pAttrIdx, tlist);// read as list // and copy to array - if(tlist.size() > 0) + if(!tlist.empty()) { pValue.reserve(tlist.size()); - for ( std::list::iterator it = tlist.begin(); it != tlist.end(); it++ ) + for ( std::list::iterator it = tlist.begin(); it != tlist.end(); ++it ) { pValue.push_back( *it ); } @@ -823,7 +823,7 @@ void X3DImporter::GeometryHelper_Extend_PointToLine(const std::list& std::list::const_iterator pit = pPoint.begin(); std::list::const_iterator pit_last = pPoint.end(); - pit_last--; + --pit_last; if ( pPoint.size() < 2 ) { @@ -837,7 +837,7 @@ void X3DImporter::GeometryHelper_Extend_PointToLine(const std::list& { pLine.push_back(*pit);// second point of previous line pLine.push_back(*pit);// first point of next line - pit++; + ++pit; } // add last point of last line pLine.push_back(*pit); @@ -855,7 +855,7 @@ void X3DImporter::GeometryHelper_Extend_PolylineIdxToLineIdx(const std::list::const_iterator plit_next; - plit_next = plit, plit_next++; + plit_next = plit, ++plit_next; pLineCoordIdx.push_back(*plit);// second point of previous line. pLineCoordIdx.push_back(-1);// delimiter if((*plit_next == (-1)) || (plit_next == pPolylineCoordIdx.end())) break;// current polyline is finished @@ -910,7 +910,7 @@ void X3DImporter::GeometryHelper_CoordIdxStr2FacesArr(const std::vector pFaces.reserve(f_data.size() / 3); inds.reserve(4); //PrintVectorSet("build. ci", pCoordIdx); - for(std::vector::iterator it = f_data.begin(); it != f_data.end(); it++) + for(std::vector::iterator it = f_data.begin(); it != f_data.end(); ++it) { // when face is got count how many indices in it. if(*it == (-1)) @@ -957,7 +957,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list tcol; // create RGBA array from RGB. - for(std::list::const_iterator it = pColors.begin(); it != pColors.end(); it++) tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1)); + for(std::list::const_iterator it = pColors.begin(); it != pColors.end(); ++it) tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1)); // call existing function for adding RGBA colors MeshGeometry_AddColor(pMesh, tcol, pColorPerVertex); @@ -997,7 +997,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list tcol; // create RGBA array from RGB. - for ( std::list::const_iterator it = pColors.begin(); it != pColors.end(); it++ ) + for ( std::list::const_iterator it = pColors.begin(); it != pColors.end(); ++it ) { tcol.push_back( aiColor4D( ( *it ).r, ( *it ).g, ( *it ).b, 1 ) ); } @@ -1031,7 +1031,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector::const_iterator it = pColors.begin(); it != pColors.end(); it++ ) + for ( std::list::const_iterator it = pColors.begin(); it != pColors.end(); ++it ) { col_arr_copy.push_back( *it ); } @@ -1048,7 +1048,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector::const_iterator colidx_it = pColorIdx.begin(), coordidx_it = pCoordIdx.begin(); colidx_it != pColorIdx.end(); colidx_it++, coordidx_it++) + for(std::vector::const_iterator colidx_it = pColorIdx.begin(), coordidx_it = pCoordIdx.begin(); colidx_it != pColorIdx.end(); ++colidx_it, ++coordidx_it) { if ( *colidx_it == ( -1 ) ) { @@ -1121,7 +1121,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); it++) col_tgt_list.push_back(*it); + for(std::vector::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); ++it) col_tgt_list.push_back(*it); // add prepared colors list to mesh. MeshGeometry_AddColor(pMesh, col_tgt_list, pColorPerVertex); } @@ -1134,7 +1134,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::vector::const_iterator it = pNormals.begin(); it != pNormals.end(); it++ ) + for ( std::list::const_iterator it = pNormals.begin(); it != pNormals.end(); ++it ) { norm_arr_copy.push_back( *it ); } @@ -1147,7 +1147,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::vector::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); it++) + for(std::vector::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); ++it) { if(*it != (-1)) tind.push_back(*it); } @@ -1227,7 +1227,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); it++) + for(std::list::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) { texcoord_arr_copy.push_back(aiVector3D((*it).x, (*it).y, 0)); } @@ -1291,7 +1291,7 @@ void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); it++ ) + for ( std::list::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it ) { tc_arr_copy.push_back( aiVector3D( ( *it ).x, ( *it ).y, 0 ) ); } @@ -1699,7 +1699,7 @@ void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy // create nodes tree Postprocess_BuildNode(*NodeElement_Cur, *pScene->mRootNode, mesh_list, mat_list, light_list); // copy needed data to scene - if(mesh_list.size() > 0) + if(!mesh_list.empty()) { std::list::const_iterator it = mesh_list.begin(); @@ -1708,7 +1708,7 @@ void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy for(size_t i = 0; i < pScene->mNumMeshes; i++) pScene->mMeshes[i] = *it++; } - if(mat_list.size() > 0) + if(!mat_list.empty()) { std::list::const_iterator it = mat_list.begin(); @@ -1717,7 +1717,7 @@ void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy for(size_t i = 0; i < pScene->mNumMaterials; i++) pScene->mMaterials[i] = *it++; } - if(light_list.size() > 0) + if(!light_list.empty()) { std::list::const_iterator it = light_list.begin(); diff --git a/code/X3D/X3DImporter_Geometry2D.cpp b/code/X3D/X3DImporter_Geometry2D.cpp index b29c80b04..350fd6c40 100644 --- a/code/X3D/X3DImporter_Geometry2D.cpp +++ b/code/X3D/X3DImporter_Geometry2D.cpp @@ -356,7 +356,7 @@ void X3DImporter::ParseNode_Geometry2D_Polyline2D() std::list tlist; // convert vec2 to vec3 - for(std::list::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); it2++) tlist.push_back(aiVector3D(it2->x, it2->y, 0)); + for(std::list::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); ++it2) tlist.push_back(aiVector3D(it2->x, it2->y, 0)); // convert point set to line set GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices); @@ -399,7 +399,7 @@ void X3DImporter::ParseNode_Geometry2D_Polypoint2D() if(!def.empty()) ne->ID = def; // convert vec2 to vec3 - for(std::list::iterator it2 = point.begin(); it2 != point.end(); it2++) + for(std::list::iterator it2 = point.begin(); it2 != point.end(); ++it2) { ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0)); } @@ -500,7 +500,7 @@ void X3DImporter::ParseNode_Geometry2D_TriangleSet2D() if(!def.empty()) ne->ID = def; // convert vec2 to vec3 - for(std::list::iterator it2 = vertices.begin(); it2 != vertices.end(); it2++) + for(std::list::iterator it2 = vertices.begin(); it2 != vertices.end(); ++it2) { ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0)); } diff --git a/code/X3D/X3DImporter_Geometry3D.cpp b/code/X3D/X3DImporter_Geometry3D.cpp index 2eecc079d..e12cbd3ab 100644 --- a/code/X3D/X3DImporter_Geometry3D.cpp +++ b/code/X3D/X3DImporter_Geometry3D.cpp @@ -153,11 +153,11 @@ void X3DImporter::ParseNode_Geometry3D_Cone() { StandardShapes::MakeCircle(bottomRadius, tess, tvec); height = -(height / 2); - for(std::vector::iterator it = tvec.begin(); it != tvec.end(); it++) it->y = height;// y - because circle made in oXZ. + for(std::vector::iterator it = tvec.begin(); it != tvec.end(); ++it) it->y = height;// y - because circle made in oXZ. } // copy data from temp array - for(std::vector::iterator it = tvec.begin(); it != tvec.end(); it++) ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices.push_back(*it); + for(std::vector::iterator it = tvec.begin(); it != tvec.end(); ++it) ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices.push_back(*it); ((CX3DImporter_NodeElement_Geometry3D*)ne)->Solid = solid; ((CX3DImporter_NodeElement_Geometry3D*)ne)->NumIndices = 3; @@ -226,11 +226,11 @@ void X3DImporter::ParseNode_Geometry3D_Cylinder() // copy data from temp arrays std::list& vlist = ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices;// just short alias. - for(std::vector::iterator it = tside.begin(); it != tside.end(); it++) vlist.push_back(*it); + for(std::vector::iterator it = tside.begin(); it != tside.end(); ++it) vlist.push_back(*it); if(top) { - for(std::vector::iterator it = tcir.begin(); it != tcir.end(); it++) + for(std::vector::iterator it = tcir.begin(); it != tcir.end(); ++it) { (*it).y = height;// y - because circle made in oXZ. vlist.push_back(*it); @@ -239,7 +239,7 @@ void X3DImporter::ParseNode_Geometry3D_Cylinder() if(bottom) { - for(std::vector::iterator it = tcir.begin(); it != tcir.end(); it++) + for(std::vector::iterator it = tcir.begin(); it != tcir.end(); ++it) { (*it).y = -height;// y - because circle made in oXZ. vlist.push_back(*it); @@ -336,7 +336,7 @@ void X3DImporter::ParseNode_Geometry3D_ElevationGrid() aiVector3D tvec(xSpacing * xi, *he_it, zSpacing * zi); grid_alias.Vertices.push_back(tvec); - he_it++; + ++he_it; } } }// END: create grid vertices list @@ -977,7 +977,7 @@ void X3DImporter::ParseNode_Geometry3D_Sphere() StandardShapes::MakeSphere(tess, tlist); // copy data from temp array and apply scale - for(std::vector::iterator it = tlist.begin(); it != tlist.end(); it++) + for(std::vector::iterator it = tlist.begin(); it != tlist.end(); ++it) { ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices.push_back(*it * radius); } diff --git a/code/X3D/X3DImporter_Networking.cpp b/code/X3D/X3DImporter_Networking.cpp index 89010ae08..a7a200675 100644 --- a/code/X3D/X3DImporter_Networking.cpp +++ b/code/X3D/X3DImporter_Networking.cpp @@ -93,7 +93,7 @@ void X3DImporter::ParseNode_Networking_Inline() // at this place new group mode created and made current, so we can name it. if(!def.empty()) NodeElement_Cur->ID = def; - if(load && (url.size() > 0)) + if(load && !url.empty()) { std::string full_path = mpIOHandler->CurrentDirectory() + url.front(); diff --git a/code/X3D/X3DImporter_Postprocess.cpp b/code/X3D/X3DImporter_Postprocess.cpp index e7686b41e..539563fcf 100644 --- a/code/X3D/X3DImporter_Postprocess.cpp +++ b/code/X3D/X3DImporter_Postprocess.cpp @@ -81,7 +81,7 @@ aiMatrix4x4 X3DImporter::PostprocessHelper_Matrix_GlobalToCurrent() const } // multiplicate all matrices in reverse order - for(std::list::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); rit++) out_matr = out_matr * (*rit); + for(std::list::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); ++rit) out_matr = out_matr * (*rit); return out_matr; } @@ -89,7 +89,7 @@ aiMatrix4x4 X3DImporter::PostprocessHelper_Matrix_GlobalToCurrent() const void X3DImporter::PostprocessHelper_CollectMetadata(const CX3DImporter_NodeElement& pNodeElement, std::list& pList) const { // walk through childs and find for metadata. - for(std::list::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++) + for(std::list::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); ++el_it) { if(((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaBoolean) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaDouble) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaFloat) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaInteger) || @@ -194,7 +194,7 @@ void X3DImporter::Postprocess_BuildMaterial(const CX3DImporter_NodeElement& pNod aiMaterial& taimat = **pMaterial;// creating alias for convenience. // at this point pNodeElement point to node. Walk through childs and add all stored data. - for(std::list::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++) + for(std::list::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); ++el_it) { if((*el_it)->Type == CX3DImporter_NodeElement::ENET_Material) { @@ -255,7 +255,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle std::vector tarr; tarr.reserve(tnemesh.Vertices.size()); - for(std::list::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); it++) tarr.push_back(*it); + for(std::list::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); ++it) tarr.push_back(*it); *pMesh = StandardShapes::MakeMesh(tarr, static_cast(tnemesh.NumIndices));// create mesh from vertices using Assimp help. return;// mesh is build, nothing to do anymore. @@ -273,7 +273,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle std::vector tarr; tarr.reserve(tnemesh.Vertices.size()); - for(std::list::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); it++) tarr.push_back(*it); + for(std::list::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); ++it) tarr.push_back(*it); *pMesh = StandardShapes::MakeMesh(tarr, static_cast(tnemesh.NumIndices));// create mesh from vertices using Assimp help. @@ -289,7 +289,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle // at first create mesh from existing vertices. *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIdx, tnemesh.Vertices); // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex); @@ -301,7 +301,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle MeshGeometry_AddTexCoord(**pMesh, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of ElevationGrid: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_ElevationGrid) @@ -313,7 +313,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -322,7 +322,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex); @@ -338,7 +338,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedFaceSet) @@ -348,7 +348,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -357,7 +357,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { ai_assert(*pMesh); if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) @@ -369,7 +369,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle {} // skip because already read when mesh created. else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedLineSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedLineSet) @@ -381,7 +381,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -390,7 +390,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { ai_assert(*pMesh); if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) @@ -408,7 +408,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedTriangleSet or IndexedTriangleFanSet, or \ IndexedTriangleStripSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleFanSet) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleStripSet)) @@ -430,7 +430,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -438,7 +438,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle vec_copy.reserve(((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.size()); for(std::list::const_iterator it = ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.begin(); - it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); it++) + it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); ++it) { vec_copy.push_back(*it); } @@ -448,7 +448,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { ai_assert(*pMesh); if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) @@ -459,7 +459,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle {} // skip because already read when mesh created. else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of PointSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_PointSet) @@ -469,7 +469,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -478,7 +478,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { ai_assert(*pMesh); if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) @@ -489,7 +489,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle {} // skip because already read when mesh created. else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of LineSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_LineSet) @@ -499,7 +499,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -508,7 +508,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if ( nullptr == *pMesh ) { break; @@ -526,7 +526,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeFanSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleFanSet) @@ -536,7 +536,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -544,7 +544,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle vec_copy.reserve(((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.size()); for(std::list::const_iterator it = ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.begin(); - it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); it++) + it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); ++it) { vec_copy.push_back(*it); } @@ -554,7 +554,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { ai_assert(*pMesh); if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) @@ -570,7 +570,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleSet) @@ -580,7 +580,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -589,7 +589,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { ai_assert(*pMesh); if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) @@ -605,7 +605,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TriangleStripSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleStripSet) @@ -639,16 +639,16 @@ void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeEle } else { - for(size_t i = 0; i < (size_t)tne_group.Choice; i++) chit_begin++;// forward iterator to chosen node. + for(size_t i = 0; i < (size_t)tne_group.Choice; i++) ++chit_begin;// forward iterator to chosen node. chit_end = chit_begin; - chit_end++;// point end iterator to next element after chosen node. + ++chit_end;// point end iterator to next element after chosen node. } }// if(tne_group.UseChoice) }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Group) // Reserve memory for fast access and check children. - for(std::list::const_iterator it = chit_begin; it != chit_end; it++) + for(std::list::const_iterator it = chit_begin; it != chit_end; ++it) {// in this loop we do not read metadata because it's already read at begin. if((*it)->Type == CX3DImporter_NodeElement::ENET_Group) { @@ -677,7 +677,7 @@ void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeEle }// for(std::list::const_iterator it = chit_begin; it != chit_end; it++) // copy data about children and meshes to aiNode. - if(SceneNode_Child.size() > 0) + if(!SceneNode_Child.empty()) { std::list::const_iterator it = SceneNode_Child.begin(); @@ -686,7 +686,7 @@ void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeEle for(size_t i = 0; i < pSceneNode.mNumChildren; i++) pSceneNode.mChildren[i] = *it++; } - if(SceneNode_Mesh.size() > 0) + if(!SceneNode_Mesh.empty()) { std::list::const_iterator it = SceneNode_Mesh.begin(); @@ -706,7 +706,7 @@ void X3DImporter::Postprocess_BuildShape(const CX3DImporter_NodeElement_Shape& p CX3DImporter_NodeElement::EType mesh_type = CX3DImporter_NodeElement::ENET_Invalid; unsigned int mat_ind = 0; - for(std::list::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); it++) + for(std::list::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); ++it) { if(PostprocessHelper_ElementIsMesh((*it)->Type)) { @@ -779,7 +779,7 @@ void X3DImporter::Postprocess_CollectMetadata(const CX3DImporter_NodeElement& pN // copy collected metadata to output node. pSceneNode.mMetaData = aiMetadata::Alloc( static_cast(meta_list.size()) ); meta_idx = 0; - for(std::list::const_iterator it = meta_list.begin(); it != meta_list.end(); it++, meta_idx++) + for(std::list::const_iterator it = meta_list.begin(); it != meta_list.end(); ++it, ++meta_idx) { CX3DImporter_NodeElement_Meta* cur_meta = (CX3DImporter_NodeElement_Meta*)*it; diff --git a/code/X3D/X3DImporter_Rendering.cpp b/code/X3D/X3DImporter_Rendering.cpp index d0c58030d..6e95c9441 100644 --- a/code/X3D/X3DImporter_Rendering.cpp +++ b/code/X3D/X3DImporter_Rendering.cpp @@ -295,7 +295,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleFanSet() ne_alias.CoordIndex.clear(); int counter = 0; int32_t idx[3]; - for(std::vector::const_iterator idx_it = index.begin(); idx_it != index.end(); idx_it++) + for(std::vector::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it) { idx[2] = *idx_it; if (idx[2] < 0) @@ -413,7 +413,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleSet() ne_alias.CoordIndex.clear(); int counter = 0; int32_t idx[3]; - for(std::vector::const_iterator idx_it = index.begin(); idx_it != index.end(); idx_it++) + for(std::vector::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it) { idx[counter++] = *idx_it; if (counter > 2) @@ -519,7 +519,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleStripSet() ne_alias.CoordIndex.clear(); int counter = 0; int32_t idx[3]; - for(std::vector::const_iterator idx_it = index.begin(); idx_it != index.end(); idx_it++) + for(std::vector::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it) { idx[2] = *idx_it; if (idx[2] < 0) @@ -617,7 +617,7 @@ void X3DImporter::ParseNode_Rendering_LineSet() size_t coord_num = 0; ne_alias.CoordIndex.clear(); - for(std::vector::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) + for(std::vector::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); ++vc_it) { if(*vc_it < 2) throw DeadlyImportError("LineSet. vertexCount shall be greater than or equal to two."); @@ -765,7 +765,7 @@ void X3DImporter::ParseNode_Rendering_TriangleFanSet() // assign indices for first triangle coord_num_first = 0; coord_num_prev = 1; - for(std::vector::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) + for(std::vector::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); ++vc_it) { if(*vc_it < 3) throw DeadlyImportError("TriangleFanSet. fanCount shall be greater than or equal to three."); @@ -956,7 +956,7 @@ void X3DImporter::ParseNode_Rendering_TriangleStripSet() ne_alias.CoordIndex.clear(); coord_num_sb = 0; - for(std::vector::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) + for(std::vector::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); ++vc_it) { if(*vc_it < 3) throw DeadlyImportError("TriangleStripSet. stripCount shall be greater than or equal to three."); diff --git a/code/X3D/X3DImporter_Texturing.cpp b/code/X3D/X3DImporter_Texturing.cpp index b4e42025a..2eaf3e6bc 100644 --- a/code/X3D/X3DImporter_Texturing.cpp +++ b/code/X3D/X3DImporter_Texturing.cpp @@ -89,7 +89,7 @@ void X3DImporter::ParseNode_Texturing_ImageTexture() ((CX3DImporter_NodeElement_ImageTexture*)ne)->RepeatS = repeatS; ((CX3DImporter_NodeElement_ImageTexture*)ne)->RepeatT = repeatT; // Attribute "url" can contain list of strings. But we need only one - first. - if(url.size() > 0) + if(!url.empty()) ((CX3DImporter_NodeElement_ImageTexture*)ne)->URL = url.front(); else ((CX3DImporter_NodeElement_ImageTexture*)ne)->URL = ""; diff --git a/code/glTF/glTFAsset.h b/code/glTF/glTFAsset.h index 359917b95..ddc7f086e 100644 --- a/code/glTF/glTFAsset.h +++ b/code/glTF/glTFAsset.h @@ -92,38 +92,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # endif #endif +#include "glTF/glTFCommon.h" + namespace glTF { -#ifdef ASSIMP_API - using Assimp::IOStream; - using Assimp::IOSystem; - using std::shared_ptr; -#else - using std::shared_ptr; - - typedef std::runtime_error DeadlyImportError; - typedef std::runtime_error DeadlyExportError; - - enum aiOrigin { aiOrigin_SET = 0, aiOrigin_CUR = 1, aiOrigin_END = 2 }; - class IOSystem; - class IOStream - { - FILE* f; - public: - IOStream(FILE* file) : f(file) {} - ~IOStream() { fclose(f); f = 0; } - - size_t Read(void* b, size_t sz, size_t n) { return fread(b, sz, n, f); } - size_t Write(const void* b, size_t sz, size_t n) { return fwrite(b, sz, n, f); } - int Seek(size_t off, aiOrigin orig) { return fseek(f, off, int(orig)); } - size_t Tell() const { return ftell(f); } - - size_t FileSize() { - long p = Tell(), len = (Seek(0, aiOrigin_END), Tell()); - return size_t((Seek(p, aiOrigin_SET), len)); - } - }; -#endif + using glTFCommon::shared_ptr; + using glTFCommon::IOSystem; + using glTFCommon::IOStream; using rapidjson::Value; using rapidjson::Document; @@ -136,37 +111,9 @@ namespace glTF struct Light; struct Skin; - - // Vec/matrix types, as raw float arrays - typedef float (vec3)[3]; - typedef float (vec4)[4]; - typedef float (mat4)[16]; - - - namespace Util - { - void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); - - size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); - - inline size_t DecodeBase64(const char* in, uint8_t*& out) - { - return DecodeBase64(in, strlen(in), out); - } - - struct DataURI - { - const char* mediaType; - const char* charset; - bool base64; - const char* data; - size_t dataLength; - }; - - //! Check if a uri is a data URI - inline bool ParseDataURI(const char* uri, size_t uriLen, DataURI& out); - } - + using glTFCommon::vec3; + using glTFCommon::vec4; + using glTFCommon::mat4; //! Magic number for GLB files #define AI_GLB_MAGIC_NUMBER "glTF" diff --git a/code/glTF/glTFAsset.inl b/code/glTF/glTFAsset.inl index 7b7acd705..f31781a3f 100644 --- a/code/glTF/glTFAsset.inl +++ b/code/glTF/glTFAsset.inl @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -52,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif using namespace Assimp; +using namespace glTFCommon; namespace glTF { @@ -301,7 +301,7 @@ inline void Buffer::Read(Value& obj, Asset& r) const char* uri = it->GetString(); - Util::DataURI dataURI; + glTFCommon::Util::DataURI dataURI; if (ParseDataURI(uri, it->GetStringLength(), dataURI)) { if (dataURI.base64) { uint8_t* data = 0; @@ -654,12 +654,12 @@ inline void Image::Read(Value& obj, Asset& r) if (Value* uri = FindString(obj, "uri")) { const char* uristr = uri->GetString(); - Util::DataURI dataURI; + glTFCommon::Util::DataURI dataURI; if (ParseDataURI(uristr, uri->GetStringLength(), dataURI)) { mimeType = dataURI.mediaType; if (dataURI.base64) { uint8_t *ptr = nullptr; - mDataLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, ptr); + mDataLength = glTFCommon::Util::DecodeBase64(dataURI.data, dataURI.dataLength, ptr); mData.reset(ptr); } } @@ -1180,8 +1180,12 @@ inline void Light::SetDefaults() falloffExponent = 0.f; } -inline void Node::Read(Value& obj, Asset& r) -{ +inline +void Node::Read(Value& obj, Asset& r) { + if (name.empty()) { + name = id; + } + if (Value* children = FindArray(obj, "children")) { this->children.reserve(children->Size()); for (unsigned int i = 0; i < children->Size(); ++i) { @@ -1474,190 +1478,4 @@ inline std::string Asset::FindUniqueID(const std::string& str, const char* suffi return id; } -namespace Util { - - inline - bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) { - if ( NULL == const_uri ) { - return false; - } - - if (const_uri[0] != 0x10) { // we already parsed this uri? - if (strncmp(const_uri, "data:", 5) != 0) // not a data uri? - return false; - } - - // set defaults - out.mediaType = "text/plain"; - out.charset = "US-ASCII"; - out.base64 = false; - - char* uri = const_cast(const_uri); - if (uri[0] != 0x10) { - uri[0] = 0x10; - uri[1] = uri[2] = uri[3] = uri[4] = 0; - - size_t i = 5, j; - if (uri[i] != ';' && uri[i] != ',') { // has media type? - uri[1] = char(i); - for (; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { - // nothing to do! - } - } - while (uri[i] == ';' && i < uriLen) { - uri[i++] = '\0'; - for (j = i; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { - // nothing to do! - } - - if ( strncmp( uri + j, "charset=", 8 ) == 0 ) { - uri[2] = char(j + 8); - } else if ( strncmp( uri + j, "base64", 6 ) == 0 ) { - uri[3] = char(j); - } - } - if (i < uriLen) { - uri[i++] = '\0'; - uri[4] = char(i); - } else { - uri[1] = uri[2] = uri[3] = 0; - uri[4] = 5; - } - } - - if ( uri[ 1 ] != 0 ) { - out.mediaType = uri + uri[ 1 ]; - } - if ( uri[ 2 ] != 0 ) { - out.charset = uri + uri[ 2 ]; - } - if ( uri[ 3 ] != 0 ) { - out.base64 = true; - } - out.data = uri + uri[4]; - out.dataLength = (uri + uriLen) - out.data; - - return true; - } - - template - struct DATA - { - static const uint8_t tableDecodeBase64[128]; - }; - - template - const uint8_t DATA::tableDecodeBase64[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, - 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 - }; - - inline char EncodeCharBase64(uint8_t b) - { - return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)]; - } - - inline uint8_t DecodeCharBase64(char c) - { - return DATA::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs? - /*if (c >= 'A' && c <= 'Z') return c - 'A'; - if (c >= 'a' && c <= 'z') return c - 'a' + 26; - if (c >= '0' && c <= '9') return c - '0' + 52; - if (c == '+') return 62; - if (c == '/') return 63; - return 64; // '-' */ - } - - inline size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out) - { - ai_assert(inLength % 4 == 0); - - if (inLength < 4) { - out = 0; - return 0; - } - - int nEquals = int(in[inLength - 1] == '=') + - int(in[inLength - 2] == '='); - - size_t outLength = (inLength * 3) / 4 - nEquals; - out = new uint8_t[outLength]; - memset(out, 0, outLength); - - size_t i, j = 0; - - for (i = 0; i + 4 < inLength; i += 4) { - uint8_t b0 = DecodeCharBase64(in[i]); - uint8_t b1 = DecodeCharBase64(in[i + 1]); - uint8_t b2 = DecodeCharBase64(in[i + 2]); - uint8_t b3 = DecodeCharBase64(in[i + 3]); - - out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); - out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); - out[j++] = (uint8_t)((b2 << 6) | b3); - } - - { - uint8_t b0 = DecodeCharBase64(in[i]); - uint8_t b1 = DecodeCharBase64(in[i + 1]); - uint8_t b2 = DecodeCharBase64(in[i + 2]); - uint8_t b3 = DecodeCharBase64(in[i + 3]); - - out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); - if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); - if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3); - } - - return outLength; - } - - - - inline void EncodeBase64( - const uint8_t* in, size_t inLength, - std::string& out) - { - size_t outLength = ((inLength + 2) / 3) * 4; - - size_t j = out.size(); - out.resize(j + outLength); - - for (size_t i = 0; i < inLength; i += 3) { - uint8_t b = (in[i] & 0xFC) >> 2; - out[j++] = EncodeCharBase64(b); - - b = (in[i] & 0x03) << 4; - if (i + 1 < inLength) { - b |= (in[i + 1] & 0xF0) >> 4; - out[j++] = EncodeCharBase64(b); - - b = (in[i + 1] & 0x0F) << 2; - if (i + 2 < inLength) { - b |= (in[i + 2] & 0xC0) >> 6; - out[j++] = EncodeCharBase64(b); - - b = in[i + 2] & 0x3F; - out[j++] = EncodeCharBase64(b); - } - else { - out[j++] = EncodeCharBase64(b); - out[j++] = '='; - } - } - else { - out[j++] = EncodeCharBase64(b); - out[j++] = '='; - out[j++] = '='; - } - } - } - -} - } // ns glTF diff --git a/code/glTF/glTFAssetWriter.inl b/code/glTF/glTFAssetWriter.inl index 20afb24e7..1bbb8fd8c 100644 --- a/code/glTF/glTFAssetWriter.inl +++ b/code/glTF/glTFAssetWriter.inl @@ -55,7 +55,8 @@ namespace glTF { namespace { template - inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) { + inline + Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) { val.SetArray(); val.Reserve(N, al); for (decltype(N) i = 0; i < N; ++i) { @@ -64,7 +65,8 @@ namespace glTF { return val; } - inline Value& MakeValue(Value& val, const std::vector & r, MemoryPoolAllocator<>& al) { + inline + Value& MakeValue(Value& val, const std::vector & r, MemoryPoolAllocator<>& al) { val.SetArray(); val.Reserve(static_cast(r.size()), al); for (unsigned int i = 0; i < r.size(); ++i) { @@ -213,7 +215,7 @@ namespace glTF { else if (img.HasData()) { uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType); uri += ";base64,"; - Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri); + glTFCommon::Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri); } else { uri = img.uri; diff --git a/code/glTF/glTFCommon.cpp b/code/glTF/glTFCommon.cpp new file mode 100644 index 000000000..cd03224e4 --- /dev/null +++ b/code/glTF/glTFCommon.cpp @@ -0,0 +1,193 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ +#include "glTF/glTFCommon.h" + +namespace glTFCommon { + +using namespace glTFCommon::Util; + +namespace Util { + +size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out) { + ai_assert(inLength % 4 == 0); + + if (inLength < 4) { + out = 0; + return 0; + } + + int nEquals = int(in[inLength - 1] == '=') + + int(in[inLength - 2] == '='); + + size_t outLength = (inLength * 3) / 4 - nEquals; + out = new uint8_t[outLength]; + memset(out, 0, outLength); + + size_t i, j = 0; + + for (i = 0; i + 4 < inLength; i += 4) { + uint8_t b0 = DecodeCharBase64(in[i]); + uint8_t b1 = DecodeCharBase64(in[i + 1]); + uint8_t b2 = DecodeCharBase64(in[i + 2]); + uint8_t b3 = DecodeCharBase64(in[i + 3]); + + out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); + out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); + out[j++] = (uint8_t)((b2 << 6) | b3); + } + + { + uint8_t b0 = DecodeCharBase64(in[i]); + uint8_t b1 = DecodeCharBase64(in[i + 1]); + uint8_t b2 = DecodeCharBase64(in[i + 2]); + uint8_t b3 = DecodeCharBase64(in[i + 3]); + + out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); + if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); + if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3); + } + + return outLength; +} + +void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out) { + size_t outLength = ((inLength + 2) / 3) * 4; + + size_t j = out.size(); + out.resize(j + outLength); + + for (size_t i = 0; i < inLength; i += 3) { + uint8_t b = (in[i] & 0xFC) >> 2; + out[j++] = EncodeCharBase64(b); + + b = (in[i] & 0x03) << 4; + if (i + 1 < inLength) { + b |= (in[i + 1] & 0xF0) >> 4; + out[j++] = EncodeCharBase64(b); + + b = (in[i + 1] & 0x0F) << 2; + if (i + 2 < inLength) { + b |= (in[i + 2] & 0xC0) >> 6; + out[j++] = EncodeCharBase64(b); + + b = in[i + 2] & 0x3F; + out[j++] = EncodeCharBase64(b); + } + else { + out[j++] = EncodeCharBase64(b); + out[j++] = '='; + } + } + else { + out[j++] = EncodeCharBase64(b); + out[j++] = '='; + out[j++] = '='; + } + } +} + +bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) { + if (nullptr == const_uri) { + return false; + } + + if (const_uri[0] != 0x10) { // we already parsed this uri? + if (strncmp(const_uri, "data:", 5) != 0) // not a data uri? + return false; + } + + // set defaults + out.mediaType = "text/plain"; + out.charset = "US-ASCII"; + out.base64 = false; + + char* uri = const_cast(const_uri); + if (uri[0] != 0x10) { + uri[0] = 0x10; + uri[1] = uri[2] = uri[3] = uri[4] = 0; + + size_t i = 5, j; + if (uri[i] != ';' && uri[i] != ',') { // has media type? + uri[1] = char(i); + for (; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { + // nothing to do! + } + } + while (uri[i] == ';' && i < uriLen) { + uri[i++] = '\0'; + for (j = i; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { + // nothing to do! + } + + if (strncmp(uri + j, "charset=", 8) == 0) { + uri[2] = char(j + 8); + } + else if (strncmp(uri + j, "base64", 6) == 0) { + uri[3] = char(j); + } + } + if (i < uriLen) { + uri[i++] = '\0'; + uri[4] = char(i); + } + else { + uri[1] = uri[2] = uri[3] = 0; + uri[4] = 5; + } + } + + if (uri[1] != 0) { + out.mediaType = uri + uri[1]; + } + if (uri[2] != 0) { + out.charset = uri + uri[2]; + } + if (uri[3] != 0) { + out.base64 = true; + } + out.data = uri + uri[4]; + out.dataLength = (uri + uriLen) - out.data; + + return true; +} + +} +} diff --git a/code/glTF/glTFCommon.h b/code/glTF/glTFCommon.h new file mode 100644 index 000000000..d9edee75e --- /dev/null +++ b/code/glTF/glTFCommon.h @@ -0,0 +1,248 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ +#ifndef AI_GLFTCOMMON_H_INC +#define AI_GLFTCOMMON_H_INC + +#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER + +#include + +#include +#include +#include +#include +#include +#include + +#define RAPIDJSON_HAS_STDSTRING 1 +#include +#include +#include + +#ifdef ASSIMP_API +# include +# include +# include +#else +# include +# define AI_SWAP4(p) +# define ai_assert +#endif + + +#if _MSC_VER > 1500 || (defined __GNUC___) +# define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP +# else +# define gltf_unordered_map map +#endif + +#ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP +# include +# if _MSC_VER > 1600 +# define gltf_unordered_map unordered_map +# else +# define gltf_unordered_map tr1::unordered_map +# endif +#endif + +namespace glTFCommon { + +#ifdef ASSIMP_API + using Assimp::IOStream; + using Assimp::IOSystem; + using std::shared_ptr; +#else + using std::shared_ptr; + + typedef std::runtime_error DeadlyImportError; + typedef std::runtime_error DeadlyExportError; + + enum aiOrigin { + aiOrigin_SET = 0, + aiOrigin_CUR = 1, + aiOrigin_END = 2 + }; + + class IOSystem; + + class IOStream { + public: + IOStream(FILE* file) : f(file) {} + ~IOStream() { fclose(f); f = 0; } + + size_t Read(void* b, size_t sz, size_t n) { return fread(b, sz, n, f); } + size_t Write(const void* b, size_t sz, size_t n) { return fwrite(b, sz, n, f); } + int Seek(size_t off, aiOrigin orig) { return fseek(f, off, int(orig)); } + size_t Tell() const { return ftell(f); } + + size_t FileSize() { + long p = Tell(), len = (Seek(0, aiOrigin_END), Tell()); + return size_t((Seek(p, aiOrigin_SET), len)); + } + + private: + FILE* f; + }; +#endif + + // Vec/matrix types, as raw float arrays + typedef float(vec3)[3]; + typedef float(vec4)[4]; + typedef float(mat4)[16]; + + inline + void CopyValue(const glTFCommon::vec3& v, aiColor4D& out) { + out.r = v[0]; + out.g = v[1]; + out.b = v[2]; + out.a = 1.0; + } + + inline + void CopyValue(const glTFCommon::vec4& v, aiColor4D& out) { + out.r = v[0]; + out.g = v[1]; + out.b = v[2]; + out.a = v[3]; + } + + inline + void CopyValue(const glTFCommon::vec4& v, aiColor3D& out) { + out.r = v[0]; + out.g = v[1]; + out.b = v[2]; + } + + inline + void CopyValue(const glTFCommon::vec3& v, aiColor3D& out) { + out.r = v[0]; + out.g = v[1]; + out.b = v[2]; + } + + inline + void CopyValue(const glTFCommon::vec3& v, aiVector3D& out) { + out.x = v[0]; + out.y = v[1]; + out.z = v[2]; + } + + inline + void CopyValue(const glTFCommon::vec4& v, aiQuaternion& out) { + out.x = v[0]; + out.y = v[1]; + out.z = v[2]; + out.w = v[3]; + } + + inline + void CopyValue(const glTFCommon::mat4& v, aiMatrix4x4& o) { + o.a1 = v[0]; o.b1 = v[1]; o.c1 = v[2]; o.d1 = v[3]; + o.a2 = v[4]; o.b2 = v[5]; o.c2 = v[6]; o.d2 = v[7]; + o.a3 = v[8]; o.b3 = v[9]; o.c3 = v[10]; o.d3 = v[11]; + o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15]; + } + + namespace Util { + + void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); + + size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); + + inline + size_t DecodeBase64(const char* in, uint8_t*& out) { + return DecodeBase64(in, strlen(in), out); + } + + struct DataURI { + const char* mediaType; + const char* charset; + bool base64; + const char* data; + size_t dataLength; + }; + + //! Check if a uri is a data URI + bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out); + + template + struct DATA { + static const uint8_t tableDecodeBase64[128]; + }; + + template + const uint8_t DATA::tableDecodeBase64[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 + }; + + inline + char EncodeCharBase64(uint8_t b) { + return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)]; + } + + inline + uint8_t DecodeCharBase64(char c) { + return DATA::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs? + /*if (c >= 'A' && c <= 'Z') return c - 'A'; + if (c >= 'a' && c <= 'z') return c - 'a' + 26; + if (c >= '0' && c <= '9') return c - '0' + 52; + if (c == '+') return 62; + if (c == '/') return 63; + return 64; // '-' */ + } + + size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); + + void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); + } + +} + +#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER + +#endif // AI_GLFTCOMMON_H_INC diff --git a/code/glTF/glTFExporter.cpp b/code/glTF/glTFExporter.cpp index 3bd944bb6..034f91f3b 100644 --- a/code/glTF/glTFExporter.cpp +++ b/code/glTF/glTFExporter.cpp @@ -242,7 +242,10 @@ inline Ref ExportData(Asset& a, std::string& meshName, Ref& bu namespace { void GetMatScalar(const aiMaterial* mat, float& val, const char* propName, int type, int idx) { - ai_assert(mat->Get(propName, type, idx, val) == AI_SUCCESS); + ai_assert( nullptr != mat ); + if ( nullptr != mat ) { + mat->Get(propName, type, idx, val); + } } } diff --git a/code/glTF/glTFImporter.cpp b/code/glTF/glTFImporter.cpp index 146d7453e..9ecd742f6 100644 --- a/code/glTF/glTFImporter.cpp +++ b/code/glTF/glTFImporter.cpp @@ -82,7 +82,7 @@ glTFImporter::glTFImporter() : BaseImporter() , meshOffsets() , embeddedTexIdxs() -, mScene( NULL ) { +, mScene( nullptr ) { // empty } @@ -90,17 +90,16 @@ glTFImporter::~glTFImporter() { // empty } -const aiImporterDesc* glTFImporter::GetInfo() const -{ +const aiImporterDesc* glTFImporter::GetInfo() const { return &desc; } -bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool /* checkSig */) const -{ +bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool /* checkSig */) const { const std::string &extension = GetExtension(pFile); - if (extension != "gltf" && extension != "glb") + if (extension != "gltf" && extension != "glb") { return false; + } if (pIOHandler) { glTF::Asset asset(pIOHandler); @@ -116,44 +115,9 @@ bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool return false; } - - -//static void CopyValue(const glTF::vec3& v, aiColor3D& out) -//{ -// out.r = v[0]; out.g = v[1]; out.b = v[2]; -//} - -static void CopyValue(const glTF::vec4& v, aiColor4D& out) -{ - out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = v[3]; -} - -static void CopyValue(const glTF::vec4& v, aiColor3D& out) -{ - out.r = v[0]; out.g = v[1]; out.b = v[2]; -} - -static void CopyValue(const glTF::vec3& v, aiVector3D& out) -{ - out.x = v[0]; out.y = v[1]; out.z = v[2]; -} - -static void CopyValue(const glTF::vec4& v, aiQuaternion& out) -{ - out.x = v[0]; out.y = v[1]; out.z = v[2]; out.w = v[3]; -} - -static void CopyValue(const glTF::mat4& v, aiMatrix4x4& o) -{ - o.a1 = v[ 0]; o.b1 = v[ 1]; o.c1 = v[ 2]; o.d1 = v[ 3]; - o.a2 = v[ 4]; o.b2 = v[ 5]; o.c2 = v[ 6]; o.d2 = v[ 7]; - o.a3 = v[ 8]; o.b3 = v[ 9]; o.c3 = v[10]; o.d3 = v[11]; - o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15]; -} - -inline void SetMaterialColorProperty(std::vector& embeddedTexIdxs, Asset& /*r*/, glTF::TexProperty prop, aiMaterial* mat, - aiTextureType texType, const char* pKey, unsigned int type, unsigned int idx) -{ +inline +void SetMaterialColorProperty(std::vector& embeddedTexIdxs, Asset& /*r*/, glTF::TexProperty prop, aiMaterial* mat, + aiTextureType texType, const char* pKey, unsigned int type, unsigned int idx) { if (prop.texture) { if (prop.texture->source) { aiString uri(prop.texture->source->uri); @@ -167,16 +131,14 @@ inline void SetMaterialColorProperty(std::vector& embeddedTexIdxs, Asset& / mat->AddProperty(&uri, _AI_MATKEY_TEXTURE_BASE, texType, 0); } - } - else { + } else { aiColor4D col; CopyValue(prop.color, col); mat->AddProperty(&col, 1, pKey, type, idx); } } -void glTFImporter::ImportMaterials(glTF::Asset& r) -{ +void glTFImporter::ImportMaterials(glTF::Asset& r) { mScene->mNumMaterials = unsigned(r.materials.Size()); mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials]; @@ -304,7 +266,7 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) aim->mName = mesh.id; if (mesh.primitives.size() > 1) { - size_t& len = aim->mName.length; + ai_uint32& len = aim->mName.length; aim->mName.data[len] = '-'; len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p); } @@ -499,27 +461,31 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes); } -void glTFImporter::ImportCameras(glTF::Asset& r) -{ - if (!r.cameras.Size()) return; +void glTFImporter::ImportCameras(glTF::Asset& r) { + if (!r.cameras.Size()) { + return; + } mScene->mNumCameras = r.cameras.Size(); mScene->mCameras = new aiCamera*[r.cameras.Size()]; - for (size_t i = 0; i < r.cameras.Size(); ++i) { Camera& cam = r.cameras[i]; aiCamera* aicam = mScene->mCameras[i] = new aiCamera(); if (cam.type == Camera::Perspective) { - aicam->mAspect = cam.perspective.aspectRatio; - aicam->mHorizontalFOV = cam.perspective.yfov * aicam->mAspect; + aicam->mHorizontalFOV = cam.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect); aicam->mClipPlaneFar = cam.perspective.zfar; aicam->mClipPlaneNear = cam.perspective.znear; - } - else { - // assimp does not support orthographic cameras + } else { + aicam->mClipPlaneFar = cam.ortographic.zfar; + aicam->mClipPlaneNear = cam.ortographic.znear; + aicam->mHorizontalFOV = 0.0; + aicam->mAspect = 1.0f; + if (0.f != cam.ortographic.ymag) { + aicam->mAspect = cam.ortographic.xmag / cam.ortographic.ymag; + } } } } diff --git a/code/glTF2/glTF2Asset.h b/code/glTF2/glTF2Asset.h index 23015c90a..15c4c44fa 100644 --- a/code/glTF2/glTF2Asset.h +++ b/code/glTF2/glTF2Asset.h @@ -95,38 +95,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include "glTF/glTFCommon.h" + namespace glTF2 { -#ifdef ASSIMP_API - using Assimp::IOStream; - using Assimp::IOSystem; - using std::shared_ptr; -#else - using std::shared_ptr; - - typedef std::runtime_error DeadlyImportError; - typedef std::runtime_error DeadlyExportError; - - enum aiOrigin { aiOrigin_SET = 0, aiOrigin_CUR = 1, aiOrigin_END = 2 }; - class IOSystem; - class IOStream - { - FILE* f; - public: - IOStream(FILE* file) : f(file) {} - ~IOStream() { fclose(f); f = 0; } - - size_t Read(void* b, size_t sz, size_t n) { return fread(b, sz, n, f); } - size_t Write(const void* b, size_t sz, size_t n) { return fwrite(b, sz, n, f); } - int Seek(size_t off, aiOrigin orig) { return fseek(f, off, int(orig)); } - size_t Tell() const { return ftell(f); } - - size_t FileSize() { - long p = Tell(), len = (Seek(0, aiOrigin_END), Tell()); - return size_t((Seek(p, aiOrigin_SET), len)); - } - }; -#endif + using glTFCommon::shared_ptr; + using glTFCommon::IOSystem; + using glTFCommon::IOStream; using rapidjson::Value; using rapidjson::Document; @@ -138,35 +113,9 @@ namespace glTF2 struct Texture; struct Skin; - // Vec/matrix types, as raw float arrays - typedef float (vec3)[3]; - typedef float (vec4)[4]; - typedef float (mat4)[16]; - - namespace Util - { - void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); - - size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); - - inline size_t DecodeBase64(const char* in, uint8_t*& out) - { - return DecodeBase64(in, strlen(in), out); - } - - struct DataURI - { - const char* mediaType; - const char* charset; - bool base64; - const char* data; - size_t dataLength; - }; - - //! Check if a uri is a data URI - inline bool ParseDataURI(const char* uri, size_t uriLen, DataURI& out); - } - + using glTFCommon::vec3; + using glTFCommon::vec4; + using glTFCommon::mat4; //! Magic number for GLB files #define AI_GLB_MAGIC_NUMBER "glTF" @@ -552,7 +501,7 @@ namespace glTF2 /// but in real life you'll get: /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 2, byteLength: 4} /// Yes, accessor of next mesh has offset and length which mean: current mesh data is decoded, all other data is encoded. - /// And when before you start to read data of current mesh (with encoded data ofcourse) you must decode region of "bufferView", after read finished + /// And when before you start to read data of current mesh (with encoded data of course) you must decode region of "bufferView", after read finished /// delete encoding mark. And after that you can repeat process: decode data of mesh, read, delete decoded data. /// /// Remark. Encoding all data at once is good in world with computers which do not has RAM limitation. So, you must use step by step encoding in diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl index 6f9eba50b..6b47b1607 100644 --- a/code/glTF2/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -282,9 +282,7 @@ Ref LazyDict::Retrieve(unsigned int i) template Ref LazyDict::Get(unsigned int i) { - return Ref(mObjs, i); - } template @@ -361,11 +359,11 @@ inline void Buffer::Read(Value& obj, Asset& r) const char* uri = it->GetString(); - Util::DataURI dataURI; + glTFCommon::Util::DataURI dataURI; if (ParseDataURI(uri, it->GetStringLength(), dataURI)) { if (dataURI.base64) { uint8_t* data = 0; - this->byteLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, data); + this->byteLength = glTFCommon::Util::DecodeBase64(dataURI.data, dataURI.dataLength, data); this->mData.reset(data, std::default_delete()); if (statedLength > 0 && this->byteLength != statedLength) { @@ -717,12 +715,12 @@ inline void Image::Read(Value& obj, Asset& r) if (Value* uri = FindString(obj, "uri")) { const char* uristr = uri->GetString(); - Util::DataURI dataURI; + glTFCommon::Util::DataURI dataURI; if (ParseDataURI(uristr, uri->GetStringLength(), dataURI)) { mimeType = dataURI.mediaType; if (dataURI.base64) { uint8_t *ptr = nullptr; - mDataLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, ptr); + mDataLength = glTFCommon::Util::DecodeBase64(dataURI.data, dataURI.dataLength, ptr); mData.reset(ptr); } } @@ -1100,8 +1098,11 @@ inline void Light::Read(Value& obj, Asset& /*r*/) } } -inline void Node::Read(Value& obj, Asset& r) -{ +inline +void Node::Read(Value& obj, Asset& r) { + if (name.empty()) { + name = id; + } if (Value* children = FindArray(obj, "children")) { this->children.reserve(children->Size()); @@ -1515,190 +1516,4 @@ inline std::string Asset::FindUniqueID(const std::string& str, const char* suffi return id; } -namespace Util { - - inline - bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) { - if ( NULL == const_uri ) { - return false; - } - - if (const_uri[0] != 0x10) { // we already parsed this uri? - if (strncmp(const_uri, "data:", 5) != 0) // not a data uri? - return false; - } - - // set defaults - out.mediaType = "text/plain"; - out.charset = "US-ASCII"; - out.base64 = false; - - char* uri = const_cast(const_uri); - if (uri[0] != 0x10) { - uri[0] = 0x10; - uri[1] = uri[2] = uri[3] = uri[4] = 0; - - size_t i = 5, j; - if (uri[i] != ';' && uri[i] != ',') { // has media type? - uri[1] = char(i); - for (; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { - // nothing to do! - } - } - while (uri[i] == ';' && i < uriLen) { - uri[i++] = '\0'; - for (j = i; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { - // nothing to do! - } - - if ( strncmp( uri + j, "charset=", 8 ) == 0 ) { - uri[2] = char(j + 8); - } else if ( strncmp( uri + j, "base64", 6 ) == 0 ) { - uri[3] = char(j); - } - } - if (i < uriLen) { - uri[i++] = '\0'; - uri[4] = char(i); - } else { - uri[1] = uri[2] = uri[3] = 0; - uri[4] = 5; - } - } - - if ( uri[ 1 ] != 0 ) { - out.mediaType = uri + uri[ 1 ]; - } - if ( uri[ 2 ] != 0 ) { - out.charset = uri + uri[ 2 ]; - } - if ( uri[ 3 ] != 0 ) { - out.base64 = true; - } - out.data = uri + uri[4]; - out.dataLength = (uri + uriLen) - out.data; - - return true; - } - - template - struct DATA - { - static const uint8_t tableDecodeBase64[128]; - }; - - template - const uint8_t DATA::tableDecodeBase64[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, - 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 - }; - - inline char EncodeCharBase64(uint8_t b) - { - return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)]; - } - - inline uint8_t DecodeCharBase64(char c) - { - return DATA::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs? - /*if (c >= 'A' && c <= 'Z') return c - 'A'; - if (c >= 'a' && c <= 'z') return c - 'a' + 26; - if (c >= '0' && c <= '9') return c - '0' + 52; - if (c == '+') return 62; - if (c == '/') return 63; - return 64; // '-' */ - } - - inline size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out) - { - ai_assert(inLength % 4 == 0); - - if (inLength < 4) { - out = 0; - return 0; - } - - int nEquals = int(in[inLength - 1] == '=') + - int(in[inLength - 2] == '='); - - size_t outLength = (inLength * 3) / 4 - nEquals; - out = new uint8_t[outLength]; - memset(out, 0, outLength); - - size_t i, j = 0; - - for (i = 0; i + 4 < inLength; i += 4) { - uint8_t b0 = DecodeCharBase64(in[i]); - uint8_t b1 = DecodeCharBase64(in[i + 1]); - uint8_t b2 = DecodeCharBase64(in[i + 2]); - uint8_t b3 = DecodeCharBase64(in[i + 3]); - - out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); - out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); - out[j++] = (uint8_t)((b2 << 6) | b3); - } - - { - uint8_t b0 = DecodeCharBase64(in[i]); - uint8_t b1 = DecodeCharBase64(in[i + 1]); - uint8_t b2 = DecodeCharBase64(in[i + 2]); - uint8_t b3 = DecodeCharBase64(in[i + 3]); - - out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); - if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); - if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3); - } - - return outLength; - } - - - - inline void EncodeBase64( - const uint8_t* in, size_t inLength, - std::string& out) - { - size_t outLength = ((inLength + 2) / 3) * 4; - - size_t j = out.size(); - out.resize(j + outLength); - - for (size_t i = 0; i < inLength; i += 3) { - uint8_t b = (in[i] & 0xFC) >> 2; - out[j++] = EncodeCharBase64(b); - - b = (in[i] & 0x03) << 4; - if (i + 1 < inLength) { - b |= (in[i + 1] & 0xF0) >> 4; - out[j++] = EncodeCharBase64(b); - - b = (in[i + 1] & 0x0F) << 2; - if (i + 2 < inLength) { - b |= (in[i + 2] & 0xC0) >> 6; - out[j++] = EncodeCharBase64(b); - - b = in[i + 2] & 0x3F; - out[j++] = EncodeCharBase64(b); - } - else { - out[j++] = EncodeCharBase64(b); - out[j++] = '='; - } - } - else { - out[j++] = EncodeCharBase64(b); - out[j++] = '='; - out[j++] = '='; - } - } - } - -} - } // ns glTF diff --git a/code/glTF2/glTF2AssetWriter.inl b/code/glTF2/glTF2AssetWriter.inl index 92168fa61..5d1b22064 100644 --- a/code/glTF2/glTF2AssetWriter.inl +++ b/code/glTF2/glTF2AssetWriter.inl @@ -218,7 +218,7 @@ namespace glTF2 { if (img.HasData()) { uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType); uri += ";base64,"; - Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri); + glTFCommon::Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri); } else { uri = img.uri; diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index c6e998b3a..c2106e26f 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -64,6 +64,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; using namespace glTF2; +using namespace glTFCommon; namespace { // generate bi-tangents from normals and tangents according to spec @@ -140,22 +141,23 @@ static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) } } -static void CopyValue(const glTF2::vec3& v, aiColor3D& out) +/*static void CopyValue(const glTF2::vec3& v, aiColor3D& out) { out.r = v[0]; out.g = v[1]; out.b = v[2]; } + static void CopyValue(const glTF2::vec4& v, aiColor4D& out) { out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = v[3]; -} +}*/ /*static void CopyValue(const glTF2::vec4& v, aiColor3D& out) { out.r = v[0]; out.g = v[1]; out.b = v[2]; }*/ -static void CopyValue(const glTF2::vec3& v, aiColor4D& out) +/*static void CopyValue(const glTF2::vec3& v, aiColor4D& out) { out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = 1.0; } @@ -168,15 +170,15 @@ static void CopyValue(const glTF2::vec3& v, aiVector3D& out) static void CopyValue(const glTF2::vec4& v, aiQuaternion& out) { out.x = v[0]; out.y = v[1]; out.z = v[2]; out.w = v[3]; -} +}*/ -static void CopyValue(const glTF2::mat4& v, aiMatrix4x4& o) +/*static void CopyValue(const glTF2::mat4& v, aiMatrix4x4& o) { o.a1 = v[ 0]; o.b1 = v[ 1]; o.c1 = v[ 2]; o.d1 = v[ 3]; o.a2 = v[ 4]; o.b2 = v[ 5]; o.c2 = v[ 6]; o.d2 = v[ 7]; o.a3 = v[ 8]; o.b3 = v[ 9]; o.c3 = v[10]; o.d3 = v[11]; o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15]; -} +}*/ inline void SetMaterialColorProperty(Asset& /*r*/, vec4& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx) { @@ -188,7 +190,7 @@ inline void SetMaterialColorProperty(Asset& /*r*/, vec4& prop, aiMaterial* mat, inline void SetMaterialColorProperty(Asset& /*r*/, vec3& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx) { aiColor4D col; - CopyValue(prop, col); + glTFCommon::CopyValue(prop, col); mat->AddProperty(&col, 1, pKey, type, idx); } @@ -383,7 +385,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) aim->mName = mesh.name.empty() ? mesh.id : mesh.name; if (mesh.primitives.size() > 1) { - size_t& len = aim->mName.length; + ai_uint32& len = aim->mName.length; aim->mName.data[len] = '-'; len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p); } @@ -442,7 +444,6 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) "\" does not match the vertex count"); continue; } - aim->mColors[c] = new aiColor4D[attr.color[c]->count]; attr.color[c]->ExtractData(aim->mColors[c]); } for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) { @@ -700,12 +701,17 @@ void glTF2Importer::ImportCameras(glTF2::Asset& r) if (cam.type == Camera::Perspective) { aicam->mAspect = cam.cameraProperties.perspective.aspectRatio; - aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * aicam->mAspect; + aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect); aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar; aicam->mClipPlaneNear = cam.cameraProperties.perspective.znear; - } - else { - // assimp does not support orthographic cameras + } else { + aicam->mClipPlaneFar = cam.cameraProperties.ortographic.zfar; + aicam->mClipPlaneNear = cam.cameraProperties.ortographic.znear; + aicam->mHorizontalFOV = 0.0; + aicam->mAspect = 1.0f; + if (0.f != cam.cameraProperties.ortographic.ymag ) { + aicam->mAspect = cam.cameraProperties.ortographic.xmag / cam.cameraProperties.ortographic.ymag; + } } } } @@ -901,6 +907,9 @@ aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector& std::vector> weighting(mesh->mNumBones); BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting); + mat4* pbindMatrices = nullptr; + node.skin->inverseBindMatrices->ExtractData(pbindMatrices); + for (uint32_t i = 0; i < mesh->mNumBones; ++i) { aiBone* bone = new aiBone(); @@ -916,6 +925,8 @@ aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector& } GetNodeTransform(bone->mOffsetMatrix, *joint); + CopyValue(pbindMatrices[i], bone->mOffsetMatrix); + std::vector& weights = weighting[i]; bone->mNumWeights = static_cast(weights.size()); @@ -931,6 +942,10 @@ aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector& } mesh->mBones[i] = bone; } + + if (pbindMatrices) { + delete[] pbindMatrices; + } } } @@ -987,11 +1002,18 @@ void glTF2Importer::ImportNodes(glTF2::Asset& r) } struct AnimationSamplers { - AnimationSamplers() : translation(nullptr), rotation(nullptr), scale(nullptr) {} + AnimationSamplers() + : translation(nullptr) + , rotation(nullptr) + , scale(nullptr) + , weight(nullptr) { + // empty + } Animation::Sampler* translation; Animation::Sampler* rotation; Animation::Sampler* scale; + Animation::Sampler* weight; }; aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers) @@ -1016,7 +1038,7 @@ aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& sampl delete[] values; } else if (node.translation.isPresent) { anim->mNumPositionKeys = 1; - anim->mPositionKeys = new aiVectorKey(); + anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; anim->mPositionKeys->mTime = 0.f; anim->mPositionKeys->mValue.x = node.translation.value[0]; anim->mPositionKeys->mValue.y = node.translation.value[1]; @@ -1041,7 +1063,7 @@ aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& sampl delete[] values; } else if (node.rotation.isPresent) { anim->mNumRotationKeys = 1; - anim->mRotationKeys = new aiQuatKey(); + anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; anim->mRotationKeys->mTime = 0.f; anim->mRotationKeys->mValue.x = node.rotation.value[0]; anim->mRotationKeys->mValue.y = node.rotation.value[1]; @@ -1064,7 +1086,7 @@ aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& sampl delete[] values; } else if (node.scale.isPresent) { anim->mNumScalingKeys = 1; - anim->mScalingKeys = new aiVectorKey(); + anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; anim->mScalingKeys->mTime = 0.f; anim->mScalingKeys->mValue.x = node.scale.value[0]; anim->mScalingKeys->mValue.y = node.scale.value[1]; @@ -1074,6 +1096,43 @@ aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& sampl return anim; } +aiMeshMorphAnim* CreateMeshMorphAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers) +{ + aiMeshMorphAnim* anim = new aiMeshMorphAnim(); + anim->mName = GetNodeName(node); + + static const float kMillisecondsFromSeconds = 1000.f; + + if (nullptr != samplers.weight) { + float* times = nullptr; + samplers.weight->input->ExtractData(times); + float* values = nullptr; + samplers.weight->output->ExtractData(values); + anim->mNumKeys = static_cast(samplers.weight->input->count); + + const unsigned int numMorphs = samplers.weight->output->count / anim->mNumKeys; + + anim->mKeys = new aiMeshMorphKey[anim->mNumKeys]; + unsigned int k = 0u; + for (unsigned int i = 0u; i < anim->mNumKeys; ++i) { + anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mKeys[i].mNumValuesAndWeights = numMorphs; + anim->mKeys[i].mValues = new unsigned int[numMorphs]; + anim->mKeys[i].mWeights = new double[numMorphs]; + + for (unsigned int j = 0u; j < numMorphs; ++j, ++k) { + anim->mKeys[i].mValues[j] = j; + anim->mKeys[i].mWeights[j] = ( 0.f > values[k] ) ? 0.f : values[k]; + } + } + + delete[] times; + delete[] values; + } + + return anim; +} + std::unordered_map GatherSamplers(Animation& anim) { std::unordered_map samplers; @@ -1092,6 +1151,8 @@ std::unordered_map GatherSamplers(Animation& an sampler.rotation = &anim.samplers[channel.sampler]; } else if (channel.target.path == AnimationPath_SCALE) { sampler.scale = &anim.samplers[channel.sampler]; + } else if (channel.target.path == AnimationPath_WEIGHTS) { + sampler.weight = &anim.samplers[channel.sampler]; } } @@ -1118,18 +1179,45 @@ void glTF2Importer::ImportAnimations(glTF2::Asset& r) std::unordered_map samplers = GatherSamplers(anim); - ai_anim->mNumChannels = static_cast(samplers.size()); + uint32_t numChannels = 0u; + uint32_t numMorphMeshChannels = 0u; + + for (auto& iter : samplers) { + if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { + ++numChannels; + } + if (nullptr != iter.second.weight) { + ++numMorphMeshChannels; + } + } + + ai_anim->mNumChannels = numChannels; if (ai_anim->mNumChannels > 0) { ai_anim->mChannels = new aiNodeAnim*[ai_anim->mNumChannels]; int j = 0; for (auto& iter : samplers) { - ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second); - ++j; + if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { + ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second); + ++j; + } + } + } + + ai_anim->mNumMorphMeshChannels = numMorphMeshChannels; + if (ai_anim->mNumMorphMeshChannels > 0) { + ai_anim->mMorphMeshChannels = new aiMeshMorphAnim*[ai_anim->mNumMorphMeshChannels]; + int j = 0; + for (auto& iter : samplers) { + if (nullptr != iter.second.weight) { + ai_anim->mMorphMeshChannels[j] = CreateMeshMorphAnim(r, r.nodes[iter.first], iter.second); + ++j; + } } } // Use the latest keyframe for the duration of the animation double maxDuration = 0; + unsigned int maxNumberOfKeys = 0; for (unsigned int j = 0; j < ai_anim->mNumChannels; ++j) { auto chan = ai_anim->mChannels[j]; if (chan->mNumPositionKeys) { @@ -1137,21 +1225,38 @@ void glTF2Importer::ImportAnimations(glTF2::Asset& r) if (lastPosKey.mTime > maxDuration) { maxDuration = lastPosKey.mTime; } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumPositionKeys); } if (chan->mNumRotationKeys) { auto lastRotKey = chan->mRotationKeys[chan->mNumRotationKeys - 1]; if (lastRotKey.mTime > maxDuration) { maxDuration = lastRotKey.mTime; } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumRotationKeys); } if (chan->mNumScalingKeys) { auto lastScaleKey = chan->mScalingKeys[chan->mNumScalingKeys - 1]; if (lastScaleKey.mTime > maxDuration) { maxDuration = lastScaleKey.mTime; } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumScalingKeys); } } + + for (unsigned int j = 0; j < ai_anim->mNumMorphMeshChannels; ++j) { + const auto* const chan = ai_anim->mMorphMeshChannels[j]; + + if (0u != chan->mNumKeys) { + const auto& lastKey = chan->mKeys[chan->mNumKeys - 1u]; + if (lastKey.mTime > maxDuration) { + maxDuration = lastKey.mTime; + } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumKeys); + } + } + ai_anim->mDuration = maxDuration; + ai_anim->mTicksPerSecond = 1000.0; mScene->mAnimations[i] = ai_anim; } diff --git a/contrib/gtest/test/gtest-param-test_test.cc b/contrib/gtest/test/gtest-param-test_test.cc index 8b278bb94..857f6c5e5 100644 --- a/contrib/gtest/test/gtest-param-test_test.cc +++ b/contrib/gtest/test/gtest-param-test_test.cc @@ -141,7 +141,7 @@ void VerifyGenerator(const ParamGenerator& generator, << ", expected_values[i] is " << PrintValue(expected_values[i]) << ", *it is " << PrintValue(*it) << ", and 'it' is an iterator created with the copy constructor.\n"; - it++; + ++it; } EXPECT_TRUE(it == generator.end()) << "At the presumed end of sequence when accessing via an iterator " @@ -161,7 +161,7 @@ void VerifyGenerator(const ParamGenerator& generator, << ", expected_values[i] is " << PrintValue(expected_values[i]) << ", *it is " << PrintValue(*it) << ", and 'it' is an iterator created with the copy constructor.\n"; - it++; + ++it; } EXPECT_TRUE(it == generator.end()) << "At the presumed end of sequence when accessing via an iterator " @@ -196,7 +196,7 @@ TEST(IteratorTest, ParamIteratorConformsToForwardIteratorConcept) { << "element same as its source points to"; // Verifies that iterator assignment works as expected. - it++; + ++it; EXPECT_FALSE(*it == *it2); it2 = it; EXPECT_TRUE(*it == *it2) << "Assigned iterators must point to the " @@ -215,7 +215,7 @@ TEST(IteratorTest, ParamIteratorConformsToForwardIteratorConcept) { // Verifies that prefix and postfix operator++() advance an iterator // all the same. it2 = it; - it++; + ++it; ++it2; EXPECT_TRUE(*it == *it2); } diff --git a/contrib/irrXML/irrXML.h b/contrib/irrXML/irrXML.h index d596ec062..d724b3162 100644 --- a/contrib/irrXML/irrXML.h +++ b/contrib/irrXML/irrXML.h @@ -215,7 +215,7 @@ namespace io two methods to read your data and give a pointer to an instance of your implementation when calling createIrrXMLReader(), createIrrXMLReaderUTF16() or createIrrXMLReaderUTF32() */ - class IFileReadCallBack + class IRRXML_API IFileReadCallBack { public: diff --git a/include/assimp/BaseImporter.h b/include/assimp/BaseImporter.h index 79a9b1b94..bd0451be3 100644 --- a/include/assimp/BaseImporter.h +++ b/include/assimp/BaseImporter.h @@ -41,9 +41,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Definition of the base class for all importer worker classes. */ +#pragma once #ifndef INCLUDED_AI_BASEIMPORTER_H #define INCLUDED_AI_BASEIMPORTER_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include "Exceptional.h" #include @@ -82,6 +87,10 @@ class IOStream; class ASSIMP_API BaseImporter { friend class Importer; +private: + /* Pushes state into importer for the importer scale */ + virtual void UpdateImporterScale( Importer* pImp ); + public: /** Constructor to be privately used by #Importer */ @@ -134,7 +143,7 @@ public: * a suitable response to the caller. */ aiScene* ReadFile( - const Importer* pImp, + Importer* pImp, const std::string& pFile, IOSystem* pIOHandler ); @@ -209,14 +218,6 @@ public: return applicationUnits; } - /* Returns scale used by application called by ScaleProcess */ - double GetImporterScale() const - { - ai_assert(importerScale != 0); - ai_assert(fileScale != 0); - return importerScale * fileScale; - } - // ------------------------------------------------------------------- /** Called by #Importer::GetExtensionList for each loaded importer. * Take the extension list contained in the structure returned by @@ -230,6 +231,7 @@ protected: double fileScale = 1.0; + // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. The * function is expected to throw an ImportErrorException if there is diff --git a/include/assimp/Bitmap.h b/include/assimp/Bitmap.h index e6b5fb132..4c3f5a437 100644 --- a/include/assimp/Bitmap.h +++ b/include/assimp/Bitmap.h @@ -46,10 +46,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Used for file formats which embed their textures into the model file. */ - +#pragma once #ifndef AI_BITMAP_H_INC #define AI_BITMAP_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include "defs.h" #include #include diff --git a/include/assimp/ByteSwapper.h b/include/assimp/ByteSwapper.h index 20a2463fb..3f14c471a 100644 --- a/include/assimp/ByteSwapper.h +++ b/include/assimp/ByteSwapper.h @@ -42,9 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Helper class tp perform various byte oder swappings (e.g. little to big endian) */ +#pragma once #ifndef AI_BYTESWAPPER_H_INC #define AI_BYTESWAPPER_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include diff --git a/include/assimp/CreateAnimMesh.h b/include/assimp/CreateAnimMesh.h index a60173588..1266d1de1 100644 --- a/include/assimp/CreateAnimMesh.h +++ b/include/assimp/CreateAnimMesh.h @@ -43,16 +43,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file CreateAnimMesh.h * Create AnimMesh from Mesh */ +#pragma once #ifndef INCLUDED_AI_CREATE_ANIM_MESH_H #define INCLUDED_AI_CREATE_ANIM_MESH_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include -namespace Assimp { +namespace Assimp { -/** Create aiAnimMesh from aiMesh. */ +/** + * Create aiAnimMesh from aiMesh. + * @param mesh The input mesh to create an animated mesh from. + * @return The new created animated mesh. + */ ASSIMP_API aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh); } // end of namespace Assimp + #endif // INCLUDED_AI_CREATE_ANIM_MESH_H diff --git a/include/assimp/DefaultIOStream.h b/include/assimp/DefaultIOStream.h index 994d728ff..c6d382c1b 100644 --- a/include/assimp/DefaultIOStream.h +++ b/include/assimp/DefaultIOStream.h @@ -41,15 +41,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Default file I/O using fXXX()-family of functions */ +#pragma once #ifndef AI_DEFAULTIOSTREAM_H_INC #define AI_DEFAULTIOSTREAM_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include #include -namespace Assimp { +namespace Assimp { // ---------------------------------------------------------------------------------- //! @class DefaultIOStream @@ -57,8 +62,7 @@ namespace Assimp { //! @note An instance of this class can exist without a valid file handle //! attached to it. All calls fail, but the instance can nevertheless be //! used with no restrictions. -class ASSIMP_API DefaultIOStream : public IOStream -{ +class ASSIMP_API DefaultIOStream : public IOStream { friend class DefaultIOSystem; #if __ANDROID__ # if __ANDROID_API__ > 9 @@ -82,7 +86,6 @@ public: size_t pSize, size_t pCount); - // ------------------------------------------------------------------- /// Write to stream size_t Write(const void* pvBuffer, @@ -107,16 +110,13 @@ public: void Flush(); private: - // File data-structure, using clib FILE* mFile; - // Filename std::string mFilename; - // Cached file size mutable size_t mCachedSize; }; // ---------------------------------------------------------------------------------- -inline +AI_FORCE_INLINE DefaultIOStream::DefaultIOStream() AI_NO_EXCEPT : mFile(nullptr) , mFilename("") @@ -125,7 +125,7 @@ DefaultIOStream::DefaultIOStream() AI_NO_EXCEPT } // ---------------------------------------------------------------------------------- -inline +AI_FORCE_INLINE DefaultIOStream::DefaultIOStream (FILE* pFile, const std::string &strFilename) : mFile(pFile) , mFilename(strFilename) @@ -137,4 +137,3 @@ DefaultIOStream::DefaultIOStream (FILE* pFile, const std::string &strFilename) } // ns assimp #endif //!!AI_DEFAULTIOSTREAM_H_INC - diff --git a/include/assimp/DefaultIOSystem.h b/include/assimp/DefaultIOSystem.h index 2dd5c801b..46f6d447c 100644 --- a/include/assimp/DefaultIOSystem.h +++ b/include/assimp/DefaultIOSystem.h @@ -41,9 +41,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Default implementation of IOSystem using the standard C file functions */ +#pragma once #ifndef AI_DEFAULTIOSYSTEM_H_INC #define AI_DEFAULTIOSYSTEM_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include namespace Assimp { diff --git a/include/assimp/Defines.h b/include/assimp/Defines.h index 15e1d83c2..be3e2fafd 100644 --- a/include/assimp/Defines.h +++ b/include/assimp/Defines.h @@ -38,6 +38,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +#pragma once +#ifndef AI_DEFINES_H_INC +#define AI_DEFINES_H_INC + +#ifdef __GNUC__ +# pragma GCC system_header +#endif + // We need those constants, workaround for any platforms where nobody defined them yet #if (!defined SIZE_MAX) # define SIZE_MAX (~((size_t)0)) @@ -47,3 +55,4 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # define UINT_MAX (~((unsigned int)0)) #endif +#endif // AI_DEINES_H_INC diff --git a/include/assimp/Exceptional.h b/include/assimp/Exceptional.h index 5109b8f07..6bb6ce1e3 100644 --- a/include/assimp/Exceptional.h +++ b/include/assimp/Exceptional.h @@ -38,11 +38,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -#ifndef INCLUDED_EXCEPTIONAL_H -#define INCLUDED_EXCEPTIONAL_H +#pragma once +#ifndef AI_INCLUDED_EXCEPTIONAL_H +#define AI_INCLUDED_EXCEPTIONAL_H + +#ifdef __GNUC__ +# pragma GCC system_header +#endif #include #include + using std::runtime_error; #ifdef _MSC_VER @@ -53,17 +59,14 @@ using std::runtime_error; /** FOR IMPORTER PLUGINS ONLY: Simple exception class to be thrown if an * unrecoverable error occurs while importing. Loading APIs return * NULL instead of a valid aiScene then. */ -class DeadlyImportError - : public runtime_error -{ +class DeadlyImportError : public runtime_error { public: /** Constructor with arguments */ explicit DeadlyImportError( const std::string& errorText) - : runtime_error(errorText) - { + : runtime_error(errorText) { + // empty } -private: }; typedef DeadlyImportError DeadlyExportError; @@ -84,7 +87,7 @@ struct ExceptionSwallower { template struct ExceptionSwallower { T* operator ()() const { - return NULL; + return nullptr; } }; @@ -122,4 +125,4 @@ struct ExceptionSwallower { }\ } -#endif // INCLUDED_EXCEPTIONAL_H +#endif // AI_INCLUDED_EXCEPTIONAL_H diff --git a/include/assimp/Exporter.hpp b/include/assimp/Exporter.hpp index ea0303e80..2612e1f9d 100644 --- a/include/assimp/Exporter.hpp +++ b/include/assimp/Exporter.hpp @@ -48,6 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_EXPORT_HPP_INC #define AI_EXPORT_HPP_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifndef ASSIMP_BUILD_NO_EXPORT #include "cexport.h" diff --git a/include/assimp/GenericProperty.h b/include/assimp/GenericProperty.h index 183ecd519..7796d595b 100644 --- a/include/assimp/GenericProperty.h +++ b/include/assimp/GenericProperty.h @@ -40,12 +40,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +#pragma once #ifndef AI_GENERIC_PROPERTY_H_INCLUDED #define AI_GENERIC_PROPERTY_H_INCLUDED +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include -#include "Hash.h" +#include #include diff --git a/include/assimp/Hash.h b/include/assimp/Hash.h index 30657be19..905644078 100644 --- a/include/assimp/Hash.h +++ b/include/assimp/Hash.h @@ -39,10 +39,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ - +#pragma once #ifndef AI_HASH_H_INCLUDED #define AI_HASH_H_INCLUDED +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/IOStream.hpp b/include/assimp/IOStream.hpp index 0623d0f70..39932cd94 100644 --- a/include/assimp/IOStream.hpp +++ b/include/assimp/IOStream.hpp @@ -48,14 +48,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_IOSTREAM_H_INC #define AI_IOSTREAM_H_INC -#include "types.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #ifndef __cplusplus # error This header requires C++ to be used. aiFileIO.h is the \ corresponding C interface. #endif -namespace Assimp { +namespace Assimp { // ---------------------------------------------------------------------------------- /** @brief CPP-API: Class to handle file I/O for C++ @@ -125,13 +129,13 @@ public: }; //! class IOStream // ---------------------------------------------------------------------------------- -inline +AI_FORCE_INLINE IOStream::IOStream() AI_NO_EXCEPT { // empty } // ---------------------------------------------------------------------------------- -inline +AI_FORCE_INLINE IOStream::~IOStream() { // empty } diff --git a/include/assimp/IOStreamBuffer.h b/include/assimp/IOStreamBuffer.h index 58abd97a0..97c84b23e 100644 --- a/include/assimp/IOStreamBuffer.h +++ b/include/assimp/IOStreamBuffer.h @@ -1,5 +1,3 @@ -#pragma once - /* Open Asset Import Library (assimp) ---------------------------------------------------------------------- @@ -42,10 +40,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +#pragma once +#ifndef AI_IOSTREAMBUFFER_H_INC +#define AI_IOSTREAMBUFFER_H_INC + +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include - -#include "ParsingUtils.h" +#include #include @@ -124,7 +129,7 @@ private: }; template -inline +AI_FORCE_INLINE IOStreamBuffer::IOStreamBuffer( size_t cache ) : m_stream( nullptr ) , m_filesize( 0 ) @@ -138,13 +143,13 @@ IOStreamBuffer::IOStreamBuffer( size_t cache ) } template -inline +AI_FORCE_INLINE IOStreamBuffer::~IOStreamBuffer() { // empty } template -inline +AI_FORCE_INLINE bool IOStreamBuffer::open( IOStream *stream ) { // file still opened! if ( nullptr != m_stream ) { @@ -174,7 +179,7 @@ bool IOStreamBuffer::open( IOStream *stream ) { } template -inline +AI_FORCE_INLINE bool IOStreamBuffer::close() { if ( nullptr == m_stream ) { return false; @@ -192,19 +197,19 @@ bool IOStreamBuffer::close() { } template -inline +AI_FORCE_INLINE size_t IOStreamBuffer::size() const { return m_filesize; } template -inline +AI_FORCE_INLINE size_t IOStreamBuffer::cacheSize() const { return m_cacheSize; } template -inline +AI_FORCE_INLINE bool IOStreamBuffer::readNextBlock() { m_stream->Seek( m_filePos, aiOrigin_SET ); size_t readLen = m_stream->Read( &m_cache[ 0 ], sizeof( T ), m_cacheSize ); @@ -222,25 +227,25 @@ bool IOStreamBuffer::readNextBlock() { } template -inline +AI_FORCE_INLINE size_t IOStreamBuffer::getNumBlocks() const { return m_numBlocks; } template -inline +AI_FORCE_INLINE size_t IOStreamBuffer::getCurrentBlockIndex() const { return m_blockIdx; } template -inline +AI_FORCE_INLINE size_t IOStreamBuffer::getFilePos() const { return m_filePos; } template -inline +AI_FORCE_INLINE bool IOStreamBuffer::getNextDataLine( std::vector &buffer, T continuationToken ) { buffer.resize( m_cacheSize ); if ( m_cachePos >= m_cacheSize || 0 == m_filePos ) { @@ -289,13 +294,13 @@ bool IOStreamBuffer::getNextDataLine( std::vector &buffer, T continuationT return true; } -static inline +static AI_FORCE_INLINE bool isEndOfCache( size_t pos, size_t cacheSize ) { return ( pos == cacheSize ); } template -inline +AI_FORCE_INLINE bool IOStreamBuffer::getNextLine(std::vector &buffer) { buffer.resize(m_cacheSize); if ( isEndOfCache( m_cachePos, m_cacheSize ) || 0 == m_filePos) { @@ -335,7 +340,7 @@ bool IOStreamBuffer::getNextLine(std::vector &buffer) { } template -inline +AI_FORCE_INLINE bool IOStreamBuffer::getNextBlock( std::vector &buffer) { // Return the last block-value if getNextLine was used before if ( 0 != m_cachePos ) { @@ -353,3 +358,5 @@ bool IOStreamBuffer::getNextBlock( std::vector &buffer) { } } // !ns Assimp + +#endif // AI_IOSTREAMBUFFER_H_INC diff --git a/include/assimp/IOSystem.hpp b/include/assimp/IOSystem.hpp index 78139c283..f1fb3b0c2 100644 --- a/include/assimp/IOSystem.hpp +++ b/include/assimp/IOSystem.hpp @@ -50,6 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_IOSYSTEM_H_INC #define AI_IOSYSTEM_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifndef __cplusplus # error This header requires C++ to be used. aiFileIO.h is the \ corresponding C interface. diff --git a/include/assimp/Importer.hpp b/include/assimp/Importer.hpp index 4941df412..bf449a9a2 100644 --- a/include/assimp/Importer.hpp +++ b/include/assimp/Importer.hpp @@ -48,6 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_ASSIMP_HPP_INC #define AI_ASSIMP_HPP_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifndef __cplusplus # error This header requires C++ to be used. Use assimp.h for plain C. #endif // __cplusplus diff --git a/include/assimp/LineSplitter.h b/include/assimp/LineSplitter.h index 4afe45b92..6c1097bb6 100644 --- a/include/assimp/LineSplitter.h +++ b/include/assimp/LineSplitter.h @@ -48,9 +48,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef INCLUDED_LINE_SPLITTER_H #define INCLUDED_LINE_SPLITTER_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include -#include "StreamReader.h" -#include "ParsingUtils.h" +#include +#include namespace Assimp { @@ -140,7 +144,7 @@ private: bool mSwallow, mSkip_empty_lines, mTrim; }; -inline +AI_FORCE_INLINE LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool trim ) : mIdx(0) , mCur() @@ -153,12 +157,12 @@ LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool t mIdx = 0; } -inline +AI_FORCE_INLINE LineSplitter::~LineSplitter() { // empty } -inline +AI_FORCE_INLINE LineSplitter& LineSplitter::operator++() { if (mSwallow) { mSwallow = false; @@ -199,12 +203,12 @@ LineSplitter& LineSplitter::operator++() { return *this; } -inline +AI_FORCE_INLINE LineSplitter &LineSplitter::operator++(int) { return ++(*this); } -inline +AI_FORCE_INLINE const char *LineSplitter::operator[] (size_t idx) const { const char* s = operator->()->c_str(); @@ -222,7 +226,7 @@ const char *LineSplitter::operator[] (size_t idx) const { } template -inline +AI_FORCE_INLINE void LineSplitter::get_tokens(const char* (&tokens)[N]) const { const char* s = operator->()->c_str(); @@ -238,44 +242,44 @@ void LineSplitter::get_tokens(const char* (&tokens)[N]) const { } } -inline +AI_FORCE_INLINE const std::string* LineSplitter::operator -> () const { return &mCur; } -inline +AI_FORCE_INLINE std::string LineSplitter::operator* () const { return mCur; } -inline +AI_FORCE_INLINE LineSplitter::operator bool() const { return mStream.GetRemainingSize() > 0; } -inline +AI_FORCE_INLINE LineSplitter::operator line_idx() const { return mIdx; } -inline +AI_FORCE_INLINE LineSplitter::line_idx LineSplitter::get_index() const { return mIdx; } -inline +AI_FORCE_INLINE StreamReaderLE &LineSplitter::get_stream() { return mStream; } -inline +AI_FORCE_INLINE bool LineSplitter::match_start(const char* check) { const size_t len = ::strlen(check); return len <= mCur.length() && std::equal(check, check + len, mCur.begin()); } -inline +AI_FORCE_INLINE void LineSplitter::swallow_next_increment() { mSwallow = true; } diff --git a/include/assimp/LogAux.h b/include/assimp/LogAux.h index 558485272..bcead78dd 100644 --- a/include/assimp/LogAux.h +++ b/include/assimp/LogAux.h @@ -43,9 +43,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file LogAux.h * @brief Common logging usage patterns for importer implementations */ +#pragma once #ifndef INCLUDED_AI_LOGAUX_H #define INCLUDED_AI_LOGAUX_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include diff --git a/include/assimp/Macros.h b/include/assimp/Macros.h deleted file mode 100644 index 651530337..000000000 --- a/include/assimp/Macros.h +++ /dev/null @@ -1,49 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/* Helper macro to set a pointer to NULL in debug builds - */ -#if (defined ASSIMP_BUILD_DEBUG) -# define AI_DEBUG_INVALIDATE_PTR(x) x = NULL; -#else -# define AI_DEBUG_INVALIDATE_PTR(x) -#endif - diff --git a/include/assimp/MathFunctions.h b/include/assimp/MathFunctions.h index cb3b69607..b6c5872a7 100644 --- a/include/assimp/MathFunctions.h +++ b/include/assimp/MathFunctions.h @@ -39,22 +39,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ +#pragma once + +#ifdef __GNUC__ +# pragma GCC system_header +#endif + /** @file MathFunctions.h - * @brief Implementation of the math functions (gcd and lcm) +* @brief Implementation of math utility functions. * - * Copied from BoostWorkaround/math - */ +*/ + +#include namespace Assimp { namespace Math { // TODO: use binary GCD for unsigned integers .... template < typename IntegerType > -IntegerType gcd( IntegerType a, IntegerType b ) -{ +inline +IntegerType gcd( IntegerType a, IntegerType b ) { const IntegerType zero = (IntegerType)0; - while ( true ) - { + while ( true ) { if ( a == zero ) return b; b %= a; @@ -66,12 +72,19 @@ IntegerType gcd( IntegerType a, IntegerType b ) } template < typename IntegerType > -IntegerType lcm( IntegerType a, IntegerType b ) -{ +inline +IntegerType lcm( IntegerType a, IntegerType b ) { const IntegerType t = gcd (a,b); - if (!t)return t; + if (!t) + return t; return a / t * b; } +template +inline +T getEpsilon() { + return std::numeric_limits::epsilon(); +} + } } diff --git a/include/assimp/MemoryIOWrapper.h b/include/assimp/MemoryIOWrapper.h index c52278718..5598d4fc5 100644 --- a/include/assimp/MemoryIOWrapper.h +++ b/include/assimp/MemoryIOWrapper.h @@ -42,12 +42,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file MemoryIOWrapper.h * Handy IOStream/IOSystem implemetation to read directly from a memory buffer */ +#pragma once #ifndef AI_MEMORYIOSTREAM_H_INC #define AI_MEMORYIOSTREAM_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include + #include namespace Assimp { diff --git a/include/assimp/ParsingUtils.h b/include/assimp/ParsingUtils.h index 6b9574fc6..302560124 100644 --- a/include/assimp/ParsingUtils.h +++ b/include/assimp/ParsingUtils.h @@ -44,11 +44,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file ParsingUtils.h * @brief Defines helper functions for text parsing */ +#pragma once #ifndef AI_PARSING_UTILS_H_INC #define AI_PARSING_UTILS_H_INC -#include "StringComparison.h" -#include "StringUtils.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include +#include #include namespace Assimp { diff --git a/include/assimp/Profiler.h b/include/assimp/Profiler.h index 6ff9d41c0..624029be9 100644 --- a/include/assimp/Profiler.h +++ b/include/assimp/Profiler.h @@ -43,12 +43,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Profiler.h * @brief Utility to measure the respective runtime of each import step */ -#ifndef INCLUDED_PROFILER_H -#define INCLUDED_PROFILER_H +#pragma once +#ifndef AI_INCLUDED_PROFILER_H +#define AI_INCLUDED_PROFILER_H + +#ifdef __GNUC__ +# pragma GCC system_header +#endif #include #include -#include "TinyFormatter.h" +#include #include @@ -67,7 +72,6 @@ public: // empty } -public: /** Start a named timer */ void BeginRegion(const std::string& region) { @@ -95,5 +99,5 @@ private: } } -#endif +#endif // AI_INCLUDED_PROFILER_H diff --git a/include/assimp/ProgressHandler.hpp b/include/assimp/ProgressHandler.hpp index 4e47f1d0a..8991a6461 100644 --- a/include/assimp/ProgressHandler.hpp +++ b/include/assimp/ProgressHandler.hpp @@ -47,9 +47,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_PROGRESSHANDLER_H_INC #define AI_PROGRESSHANDLER_H_INC -#include "types.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif -namespace Assimp { +#include + +namespace Assimp { // ------------------------------------------------------------------------------------ /** @brief CPP-API: Abstract interface for custom progress report receivers. diff --git a/include/assimp/RemoveComments.h b/include/assimp/RemoveComments.h index 404b49671..f12942053 100644 --- a/include/assimp/RemoveComments.h +++ b/include/assimp/RemoveComments.h @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -43,9 +42,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Declares a helper class, "CommentRemover", which can be * used to remove comments (single and multi line) from a text file. */ +#pragma once #ifndef AI_REMOVE_COMMENTS_H_INC #define AI_REMOVE_COMMENTS_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif #include @@ -58,8 +61,7 @@ namespace Assimp { * to those in C or C++ so this code has been moved to a separate * module. */ -class ASSIMP_API CommentRemover -{ +class ASSIMP_API CommentRemover { // class cannot be instanced CommentRemover() {} diff --git a/include/assimp/SGSpatialSort.h b/include/assimp/SGSpatialSort.h index 5b4f3f41f..fdb5ce817 100644 --- a/include/assimp/SGSpatialSort.h +++ b/include/assimp/SGSpatialSort.h @@ -42,9 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** Small helper classes to optimize finding vertices close to a given location */ +#pragma once #ifndef AI_D3DSSPATIALSORT_H_INC #define AI_D3DSSPATIALSORT_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include diff --git a/include/assimp/SceneCombiner.h b/include/assimp/SceneCombiner.h index 679a2acea..0683c1e05 100644 --- a/include/assimp/SceneCombiner.h +++ b/include/assimp/SceneCombiner.h @@ -43,17 +43,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Declares a helper class, "SceneCombiner" providing various * utilities to merge scenes. */ +#pragma once #ifndef AI_SCENE_COMBINER_H_INC #define AI_SCENE_COMBINER_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include + #include #include #include #include - #include struct aiScene; @@ -65,8 +70,10 @@ struct aiLight; struct aiMetadata; struct aiBone; struct aiMesh; +struct aiAnimMesh; struct aiAnimation; struct aiNodeAnim; +struct aiMeshMorphAnim; namespace Assimp { @@ -363,6 +370,7 @@ public: static void Copy (aiMesh** dest, const aiMesh* src); // similar to Copy(): + static void Copy (aiAnimMesh** dest, const aiAnimMesh* src); static void Copy (aiMaterial** dest, const aiMaterial* src); static void Copy (aiTexture** dest, const aiTexture* src); static void Copy (aiAnimation** dest, const aiAnimation* src); @@ -370,6 +378,7 @@ public: static void Copy (aiBone** dest, const aiBone* src); static void Copy (aiLight** dest, const aiLight* src); static void Copy (aiNodeAnim** dest, const aiNodeAnim* src); + static void Copy (aiMeshMorphAnim** dest, const aiMeshMorphAnim* src); static void Copy (aiMetadata** dest, const aiMetadata* src); // recursive, of course diff --git a/include/assimp/SkeletonMeshBuilder.h b/include/assimp/SkeletonMeshBuilder.h index f9b8d9f55..ad979a33f 100644 --- a/include/assimp/SkeletonMeshBuilder.h +++ b/include/assimp/SkeletonMeshBuilder.h @@ -47,9 +47,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * for animation skeletons. */ +#pragma once #ifndef AI_SKELETONMESHBUILDER_H_INC #define AI_SKELETONMESHBUILDER_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/SmoothingGroups.h b/include/assimp/SmoothingGroups.h index 92d65cea0..c1a93947f 100644 --- a/include/assimp/SmoothingGroups.h +++ b/include/assimp/SmoothingGroups.h @@ -43,10 +43,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Defines the helper data structures for importing 3DS files. http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */ +#pragma once #ifndef AI_SMOOTHINGGROUPS_H_INC #define AI_SMOOTHINGGROUPS_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include + #include #include diff --git a/include/assimp/SmoothingGroups.inl b/include/assimp/SmoothingGroups.inl index 84ea4a1b0..37ea083db 100644 --- a/include/assimp/SmoothingGroups.inl +++ b/include/assimp/SmoothingGroups.inl @@ -41,13 +41,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Generation of normal vectors basing on smoothing groups */ +#pragma once #ifndef AI_SMOOTHINGGROUPS_INL_INCLUDED #define AI_SMOOTHINGGROUPS_INL_INCLUDED -// internal headers +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include -// CRT header #include using namespace Assimp; diff --git a/include/assimp/SpatialSort.h b/include/assimp/SpatialSort.h index 61b345bcb..9f9354315 100644 --- a/include/assimp/SpatialSort.h +++ b/include/assimp/SpatialSort.h @@ -41,9 +41,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** Small helper classes to optimise finding vertizes close to a given location */ +#pragma once #ifndef AI_SPATIALSORT_H_INC #define AI_SPATIALSORT_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/StandardShapes.h b/include/assimp/StandardShapes.h index 3791569b8..c594cb63f 100644 --- a/include/assimp/StandardShapes.h +++ b/include/assimp/StandardShapes.h @@ -41,11 +41,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Declares a helper class, "StandardShapes" which generates - * vertices for standard shapes, such as cylnders, cones, spheres .. + * vertices for standard shapes, such as cylinders, cones, spheres .. */ +#pragma once #ifndef AI_STANDARD_SHAPES_H_INC #define AI_STANDARD_SHAPES_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/StreamReader.h b/include/assimp/StreamReader.h index 9116c1426..cb24f1595 100644 --- a/include/assimp/StreamReader.h +++ b/include/assimp/StreamReader.h @@ -44,15 +44,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Defines the StreamReader class which reads data from * a binary stream with a well-defined endianness. */ - +#pragma once #ifndef AI_STREAMREADER_H_INCLUDED #define AI_STREAMREADER_H_INCLUDED +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include +#include +#include -#include "ByteSwapper.h" -#include "Exceptional.h" #include namespace Assimp { diff --git a/include/assimp/StreamWriter.h b/include/assimp/StreamWriter.h index c7cf6c0d7..489e8adfe 100644 --- a/include/assimp/StreamWriter.h +++ b/include/assimp/StreamWriter.h @@ -43,11 +43,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Defines the StreamWriter class which writes data to * a binary stream with a well-defined endianness. */ - +#pragma once #ifndef AI_STREAMWRITER_H_INCLUDED #define AI_STREAMWRITER_H_INCLUDED -#include "ByteSwapper.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #include #include diff --git a/include/assimp/StringComparison.h b/include/assimp/StringComparison.h index 8acef277b..d3ca3e971 100644 --- a/include/assimp/StringComparison.h +++ b/include/assimp/StringComparison.h @@ -49,12 +49,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. These functions are not consistently available on all platforms, or the provided implementations behave too differently. */ +#pragma once #ifndef INCLUDED_AI_STRING_WORKERS_H #define INCLUDED_AI_STRING_WORKERS_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include -#include "StringComparison.h" +#include #include #include diff --git a/include/assimp/StringUtils.h b/include/assimp/StringUtils.h index d68b7fa47..af481f819 100644 --- a/include/assimp/StringUtils.h +++ b/include/assimp/StringUtils.h @@ -39,9 +39,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +#pragma once #ifndef INCLUDED_AI_STRINGUTILS_H #define INCLUDED_AI_STRINGUTILS_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/Subdivision.h b/include/assimp/Subdivision.h index 43feb73b3..e9450267e 100644 --- a/include/assimp/Subdivision.h +++ b/include/assimp/Subdivision.h @@ -45,7 +45,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_SUBDISIVION_H_INC #define AI_SUBDISIVION_H_INC -#include +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include struct aiMesh; diff --git a/include/assimp/TinyFormatter.h b/include/assimp/TinyFormatter.h index 1226b482e..6227e42c5 100644 --- a/include/assimp/TinyFormatter.h +++ b/include/assimp/TinyFormatter.h @@ -45,9 +45,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * to get rid of the boost::format dependency. Much slinker, * basically just extends stringstream. */ +#pragma once #ifndef INCLUDED_TINY_FORMATTER_H #define INCLUDED_TINY_FORMATTER_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include namespace Assimp { @@ -65,24 +70,15 @@ namespace Formatter { * @endcode */ template < typename T, typename CharTraits = std::char_traits, - typename Allocator = std::allocator -> -class basic_formatter -{ - + typename Allocator = std::allocator > +class basic_formatter { public: + typedef class std::basic_string string; + typedef class std::basic_ostringstream stringstream; - typedef class std::basic_string< - T,CharTraits,Allocator - > string; - - typedef class std::basic_ostringstream< - T,CharTraits,Allocator - > stringstream; - -public: - - basic_formatter() {} + basic_formatter() { + // empty + } /* Allow basic_formatter's to be used almost interchangeably * with std::(w)string or const (w)char* arguments because the @@ -104,14 +100,10 @@ public: } #endif - -public: - operator string () const { return underlying.str(); } - /* note - this is declared const because binding temporaries does only * work for const references, so many function prototypes will * include const basic_formatter& s but might still want to diff --git a/include/assimp/Vertex.h b/include/assimp/Vertex.h index 2a7f0256a..5e63db5fe 100644 --- a/include/assimp/Vertex.h +++ b/include/assimp/Vertex.h @@ -47,12 +47,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. that are not currently well-defined (and would cause compile errors due to missing operators in the math library), are commented. */ +#pragma once #ifndef AI_VERTEX_H_INC #define AI_VERTEX_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include + #include namespace Assimp { @@ -91,23 +97,14 @@ namespace Assimp { * to *all* vertex components equally. This is useful for stuff like interpolation * or subdivision, but won't work if special handling is required for some vertex components. */ // ------------------------------------------------------------------------------------------------ -class Vertex -{ +class Vertex { friend Vertex operator + (const Vertex&,const Vertex&); friend Vertex operator - (const Vertex&,const Vertex&); - -// friend Vertex operator + (const Vertex&,ai_real); -// friend Vertex operator - (const Vertex&,ai_real); friend Vertex operator * (const Vertex&,ai_real); friend Vertex operator / (const Vertex&,ai_real); - -// friend Vertex operator + (ai_real, const Vertex&); -// friend Vertex operator - (ai_real, const Vertex&); friend Vertex operator * (ai_real, const Vertex&); -// friend Vertex operator / (ai_real, const Vertex&); public: - Vertex() {} // ---------------------------------------------------------------------------- @@ -158,8 +155,6 @@ public: } } -public: - Vertex& operator += (const Vertex& v) { *this = *this+v; return *this; @@ -170,18 +165,6 @@ public: return *this; } - -/* - Vertex& operator += (ai_real v) { - *this = *this+v; - return *this; - } - - Vertex& operator -= (ai_real v) { - *this = *this-v; - return *this; - } -*/ Vertex& operator *= (ai_real v) { *this = *this*v; return *this; @@ -192,12 +175,9 @@ public: return *this; } -public: - // ---------------------------------------------------------------------------- /** Convert back to non-interleaved storage */ void SortBack(aiMesh* out, unsigned int idx) const { - ai_assert(idxmNumVertices); out->mVertices[idx] = position; @@ -291,8 +271,6 @@ public: aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS]; }; - - // ------------------------------------------------------------------------------------------------ AI_FORCE_INLINE Vertex operator + (const Vertex& v0,const Vertex& v1) { return Vertex::BinaryOp(v0,v1); @@ -302,19 +280,6 @@ AI_FORCE_INLINE Vertex operator - (const Vertex& v0,const Vertex& v1) { return Vertex::BinaryOp(v0,v1); } - -// ------------------------------------------------------------------------------------------------ -/* -AI_FORCE_INLINE Vertex operator + (const Vertex& v0,ai_real f) { - return Vertex::BinaryOp(v0,f); -} - -AI_FORCE_INLINE Vertex operator - (const Vertex& v0,ai_real f) { - return Vertex::BinaryOp(v0,f); -} - -*/ - AI_FORCE_INLINE Vertex operator * (const Vertex& v0,ai_real f) { return Vertex::BinaryOp(v0,f); } @@ -323,26 +288,10 @@ AI_FORCE_INLINE Vertex operator / (const Vertex& v0,ai_real f) { return Vertex::BinaryOp(v0,1.f/f); } -// ------------------------------------------------------------------------------------------------ -/* -AI_FORCE_INLINE Vertex operator + (ai_real f,const Vertex& v0) { - return Vertex::BinaryOp(f,v0); -} - -AI_FORCE_INLINE Vertex operator - (ai_real f,const Vertex& v0) { - return Vertex::BinaryOp(f,v0); -} -*/ - AI_FORCE_INLINE Vertex operator * (ai_real f,const Vertex& v0) { return Vertex::BinaryOp(f,v0); } -/* -AI_FORCE_INLINE Vertex operator / (ai_real f,const Vertex& v0) { - return Vertex::BinaryOp(f,v0); } -*/ -} -#endif +#endif // AI_VERTEX_H_INC diff --git a/include/assimp/XMLTools.h b/include/assimp/XMLTools.h index b0d327687..95f12cdeb 100644 --- a/include/assimp/XMLTools.h +++ b/include/assimp/XMLTools.h @@ -40,9 +40,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +#pragma once #ifndef INCLUDED_ASSIMP_XML_TOOLS_H #define INCLUDED_ASSIMP_XML_TOOLS_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include namespace Assimp { diff --git a/include/assimp/ZipArchiveIOSystem.h b/include/assimp/ZipArchiveIOSystem.h index 38cbbf2a7..516ea84de 100644 --- a/include/assimp/ZipArchiveIOSystem.h +++ b/include/assimp/ZipArchiveIOSystem.h @@ -45,43 +45,50 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of IOSystem to read a ZIP file from another IOSystem */ +#pragma once #ifndef AI_ZIPARCHIVEIOSYSTEM_H_INC #define AI_ZIPARCHIVEIOSYSTEM_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include namespace Assimp { - class ZipArchiveIOSystem : public IOSystem { - public: - //! Open a Zip using the proffered IOSystem - ZipArchiveIOSystem(IOSystem* pIOHandler, const char *pFilename, const char* pMode = "r"); - ZipArchiveIOSystem(IOSystem* pIOHandler, const std::string& rFilename, const char* pMode = "r"); - virtual ~ZipArchiveIOSystem(); - bool Exists(const char* pFilename) const override; - char getOsSeparator() const override; - IOStream* Open(const char* pFilename, const char* pMode = "rb") override; - void Close(IOStream* pFile) override; - // Specific to ZIP - //! The file was opened and is a ZIP - bool isOpen() const; +class ZipArchiveIOSystem : public IOSystem { +public: + //! Open a Zip using the proffered IOSystem + ZipArchiveIOSystem(IOSystem* pIOHandler, const char *pFilename, const char* pMode = "r"); + ZipArchiveIOSystem(IOSystem* pIOHandler, const std::string& rFilename, const char* pMode = "r"); + virtual ~ZipArchiveIOSystem(); + bool Exists(const char* pFilename) const override; + char getOsSeparator() const override; + IOStream* Open(const char* pFilename, const char* pMode = "rb") override; + void Close(IOStream* pFile) override; - //! Get the list of all files with their simplified paths - //! Intended for use within Assimp library boundaries - void getFileList(std::vector& rFileList) const; + // Specific to ZIP + //! The file was opened and is a ZIP + bool isOpen() const; - //! Get the list of all files with extension (must be lowercase) - //! Intended for use within Assimp library boundaries - void getFileListExtension(std::vector& rFileList, const std::string& extension) const; + //! Get the list of all files with their simplified paths + //! Intended for use within Assimp library boundaries + void getFileList(std::vector& rFileList) const; - static bool isZipArchive(IOSystem* pIOHandler, const char *pFilename); - static bool isZipArchive(IOSystem* pIOHandler, const std::string& rFilename); + //! Get the list of all files with extension (must be lowercase) + //! Intended for use within Assimp library boundaries + void getFileListExtension(std::vector& rFileList, const std::string& extension) const; + + static bool isZipArchive(IOSystem* pIOHandler, const char *pFilename); + static bool isZipArchive(IOSystem* pIOHandler, const std::string& rFilename); + +private: + class Implement; + Implement *pImpl = nullptr; +}; - private: - class Implement; - Implement *pImpl = nullptr; - }; } // Namespace Assimp #endif // AI_ZIPARCHIVEIOSYSTEM_H_INC diff --git a/include/assimp/aabb.h b/include/assimp/aabb.h index a20f31742..83bb62256 100644 --- a/include/assimp/aabb.h +++ b/include/assimp/aabb.h @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -45,6 +43,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_AABB_H_INC #define AI_AABB_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include struct aiAABB { @@ -69,8 +71,9 @@ struct aiAABB { // empty } -#endif +#endif // __cplusplus + }; -#endif +#endif // AI_AABB_H_INC diff --git a/include/assimp/ai_assert.h b/include/assimp/ai_assert.h index e5de5d3f3..2b32b01d3 100644 --- a/include/assimp/ai_assert.h +++ b/include/assimp/ai_assert.h @@ -44,6 +44,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_ASSERT_H_INC #define AI_ASSERT_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifdef ASSIMP_BUILD_DEBUG # include # define ai_assert(expression) assert( expression ) diff --git a/include/assimp/anim.h b/include/assimp/anim.h index 02e92739e..e208b11ad 100644 --- a/include/assimp/anim.h +++ b/include/assimp/anim.h @@ -50,6 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_ANIM_H_INC #define AI_ANIM_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/camera.h b/include/assimp/camera.h index e573eea5d..adb749ff5 100644 --- a/include/assimp/camera.h +++ b/include/assimp/camera.h @@ -47,6 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_CAMERA_H_INC #define AI_CAMERA_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include "types.h" #ifdef __cplusplus @@ -113,7 +117,6 @@ struct aiCamera */ C_STRUCT aiVector3D mPosition; - /** 'Up' - vector of the camera coordinate system relative to * the coordinate space defined by the corresponding node. * @@ -134,7 +137,6 @@ struct aiCamera */ C_STRUCT aiVector3D mLookAt; - /** Half horizontal field of view angle, in radians. * * The field of view angle is the angle between the center diff --git a/include/assimp/cexport.h b/include/assimp/cexport.h index 1d62dc26b..cbc0253d5 100644 --- a/include/assimp/cexport.h +++ b/include/assimp/cexport.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2011, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,6 +46,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_EXPORT_H_INC #define AI_EXPORT_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifndef ASSIMP_BUILD_NO_EXPORT // Public ASSIMP data structures diff --git a/include/assimp/cfileio.h b/include/assimp/cfileio.h index 8f7ca4546..be90999d8 100644 --- a/include/assimp/cfileio.h +++ b/include/assimp/cfileio.h @@ -48,10 +48,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_FILEIO_H_INC #define AI_FILEIO_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include + #ifdef __cplusplus extern "C" { #endif + struct aiFileIO; struct aiFile; diff --git a/include/assimp/cimport.h b/include/assimp/cimport.h index dbd10f137..66b1c9a17 100644 --- a/include/assimp/cimport.h +++ b/include/assimp/cimport.h @@ -48,8 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_ASSIMP_H_INC #define AI_ASSIMP_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include -#include "importerdesc.h" +#include #ifdef __cplusplus extern "C" { diff --git a/include/assimp/color4.h b/include/assimp/color4.h index 3c97c8eda..fa86128f4 100644 --- a/include/assimp/color4.h +++ b/include/assimp/color4.h @@ -47,7 +47,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_COLOR4D_H_INC #define AI_COLOR4D_H_INC -#include "defs.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #ifdef __cplusplus @@ -56,8 +60,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * alpha component. Color values range from 0 to 1. */ // ---------------------------------------------------------------------------------- template -class aiColor4t -{ +class aiColor4t { public: aiColor4t() AI_NO_EXCEPT : r(), g(), b(), a() {} aiColor4t (TReal _r, TReal _g, TReal _b, TReal _a) @@ -65,14 +68,12 @@ public: explicit aiColor4t (TReal _r) : r(_r), g(_r), b(_r), a(_r) {} aiColor4t (const aiColor4t& o) = default; -public: // combined operators const aiColor4t& operator += (const aiColor4t& o); const aiColor4t& operator -= (const aiColor4t& o); const aiColor4t& operator *= (TReal f); const aiColor4t& operator /= (TReal f); -public: // comparison bool operator == (const aiColor4t& other) const; bool operator != (const aiColor4t& other) const; @@ -85,8 +86,6 @@ public: /** check whether a color is (close to) black */ inline bool IsBlack() const; -public: - // Red, green, blue and alpha color values TReal r, g, b, a; }; // !struct aiColor4D diff --git a/include/assimp/color4.inl b/include/assimp/color4.inl index afa53dcb5..d4a2a9810 100644 --- a/include/assimp/color4.inl +++ b/include/assimp/color4.inl @@ -48,36 +48,61 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_COLOR4D_INL_INC #define AI_COLOR4D_INL_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifdef __cplusplus -#include "color4.h" +#include // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE const aiColor4t& aiColor4t::operator += (const aiColor4t& o) { - r += o.r; g += o.g; b += o.b; a += o.a; +AI_FORCE_INLINE +const aiColor4t& aiColor4t::operator += (const aiColor4t& o) { + r += o.r; + g += o.g; + b += o.b; + a += o.a; + return *this; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE const aiColor4t& aiColor4t::operator -= (const aiColor4t& o) { - r -= o.r; g -= o.g; b -= o.b; a -= o.a; +AI_FORCE_INLINE +const aiColor4t& aiColor4t::operator -= (const aiColor4t& o) { + r -= o.r; + g -= o.g; + b -= o.b; + a -= o.a; + return *this; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE const aiColor4t& aiColor4t::operator *= (TReal f) { - r *= f; g *= f; b *= f; a *= f; +AI_FORCE_INLINE +const aiColor4t& aiColor4t::operator *= (TReal f) { + r *= f; + g *= f; + b *= f; + a *= f; + return *this; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE const aiColor4t& aiColor4t::operator /= (TReal f) { - r /= f; g /= f; b /= f; a /= f; +AI_FORCE_INLINE +const aiColor4t& aiColor4t::operator /= (TReal f) { + r /= f; + g /= f; + b /= f; + a /= f; + return *this; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE TReal aiColor4t::operator[](unsigned int i) const { +AI_FORCE_INLINE +TReal aiColor4t::operator[](unsigned int i) const { switch ( i ) { case 0: return r; @@ -94,7 +119,8 @@ AI_FORCE_INLINE TReal aiColor4t::operator[](unsigned int i) const { } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE TReal& aiColor4t::operator[](unsigned int i) { +AI_FORCE_INLINE +TReal& aiColor4t::operator[](unsigned int i) { switch ( i ) { case 0: return r; @@ -111,17 +137,20 @@ AI_FORCE_INLINE TReal& aiColor4t::operator[](unsigned int i) { } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE bool aiColor4t::operator== (const aiColor4t& other) const { +AI_FORCE_INLINE +bool aiColor4t::operator== (const aiColor4t& other) const { return r == other.r && g == other.g && b == other.b && a == other.a; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE bool aiColor4t::operator!= (const aiColor4t& other) const { +AI_FORCE_INLINE +bool aiColor4t::operator!= (const aiColor4t& other) const { return r != other.r || g != other.g || b != other.b || a != other.a; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE bool aiColor4t::operator< (const aiColor4t& other) const { +AI_FORCE_INLINE +bool aiColor4t::operator< (const aiColor4t& other) const { return r < other.r || ( r == other.r && ( g < other.g || ( @@ -136,14 +165,17 @@ AI_FORCE_INLINE bool aiColor4t::operator< (const aiColor4t& other) ) ); } + // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator + (const aiColor4t& v1, const aiColor4t& v2) { +AI_FORCE_INLINE +aiColor4t operator + (const aiColor4t& v1, const aiColor4t& v2) { return aiColor4t( v1.r + v2.r, v1.g + v2.g, v1.b + v2.b, v1.a + v2.a); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator - (const aiColor4t& v1, const aiColor4t& v2) { +AI_FORCE_INLINE +aiColor4t operator - (const aiColor4t& v1, const aiColor4t& v2) { return aiColor4t( v1.r - v2.r, v1.g - v2.g, v1.b - v2.b, v1.a - v2.a); } // ------------------------------------------------------------------------------------------------ @@ -153,53 +185,63 @@ AI_FORCE_INLINE aiColor4t operator * (const aiColor4t& v1, const a } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator / (const aiColor4t& v1, const aiColor4t& v2) { +AI_FORCE_INLINE +aiColor4t operator / (const aiColor4t& v1, const aiColor4t& v2) { return aiColor4t( v1.r / v2.r, v1.g / v2.g, v1.b / v2.b, v1.a / v2.a); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator * ( TReal f, const aiColor4t& v) { +AI_FORCE_INLINE +aiColor4t operator * ( TReal f, const aiColor4t& v) { return aiColor4t( f*v.r, f*v.g, f*v.b, f*v.a); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator * ( const aiColor4t& v, TReal f) { +AI_FORCE_INLINE +aiColor4t operator * ( const aiColor4t& v, TReal f) { return aiColor4t( f*v.r, f*v.g, f*v.b, f*v.a); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator / ( const aiColor4t& v, TReal f) { +AI_FORCE_INLINE +aiColor4t operator / ( const aiColor4t& v, TReal f) { return v * (1/f); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator / ( TReal f,const aiColor4t& v) { +AI_FORCE_INLINE +aiColor4t operator / ( TReal f,const aiColor4t& v) { return aiColor4t(f,f,f,f)/v; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator + ( const aiColor4t& v, TReal f) { +AI_FORCE_INLINE +aiColor4t operator + ( const aiColor4t& v, TReal f) { return aiColor4t( f+v.r, f+v.g, f+v.b, f+v.a); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator - ( const aiColor4t& v, TReal f) { +AI_FORCE_INLINE +aiColor4t operator - ( const aiColor4t& v, TReal f) { return aiColor4t( v.r-f, v.g-f, v.b-f, v.a-f); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator + ( TReal f, const aiColor4t& v) { +AI_FORCE_INLINE +aiColor4t operator + ( TReal f, const aiColor4t& v) { return aiColor4t( f+v.r, f+v.g, f+v.b, f+v.a); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator - ( TReal f, const aiColor4t& v) { +AI_FORCE_INLINE +aiColor4t operator - ( TReal f, const aiColor4t& v) { return aiColor4t( f-v.r, f-v.g, f-v.b, f-v.a); } // ------------------------------------------------------------------------------------------------ template -inline bool aiColor4t :: IsBlack() const { +AI_FORCE_INLINE +bool aiColor4t::IsBlack() const { // The alpha component doesn't care here. black is black. static const TReal epsilon = 10e-3f; return std::fabs( r ) < epsilon && std::fabs( g ) < epsilon && std::fabs( b ) < epsilon; diff --git a/include/assimp/defs.h b/include/assimp/defs.h index 05a5e3fd4..71579a5c7 100644 --- a/include/assimp/defs.h +++ b/include/assimp/defs.h @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -50,6 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_DEFINES_H_INC #define AI_DEFINES_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include ////////////////////////////////////////////////////////////////////////// @@ -291,9 +293,10 @@ static const ai_real ai_epsilon = (ai_real) 0.00001; #endif -/* To avoid running out of memory - * This can be adjusted for specific use cases - * It's NOT a total limit, just a limit for individual allocations +/** + * To avoid running out of memory + * This can be adjusted for specific use cases + * It's NOT a total limit, just a limit for individual allocations */ #define AI_MAX_ALLOC(type) ((256U * 1024 * 1024) / sizeof(type)) @@ -307,4 +310,13 @@ static const ai_real ai_epsilon = (ai_real) 0.00001; # endif #endif // _MSC_VER +/** + * Helper macro to set a pointer to NULL in debug builds + */ +#if (defined ASSIMP_BUILD_DEBUG) +# define AI_DEBUG_INVALIDATE_PTR(x) x = NULL; +#else +# define AI_DEBUG_INVALIDATE_PTR(x) +#endif + #endif // !! AI_DEFINES_H_INC diff --git a/include/assimp/fast_atof.h b/include/assimp/fast_atof.h index 62ea969e9..6e9a1bba7 100644 --- a/include/assimp/fast_atof.h +++ b/include/assimp/fast_atof.h @@ -13,10 +13,14 @@ // to ensure long numbers are handled correctly // ------------------------------------------------------------------------------------ - +#pragma once #ifndef FAST_A_TO_F_H_INCLUDED #define FAST_A_TO_F_H_INCLUDED +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include diff --git a/include/assimp/importerdesc.h b/include/assimp/importerdesc.h index 36e387f01..0a6919c1a 100644 --- a/include/assimp/importerdesc.h +++ b/include/assimp/importerdesc.h @@ -48,11 +48,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_IMPORTER_DESC_H_INC #define AI_IMPORTER_DESC_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + /** Mixed set of flags for #aiImporterDesc, indicating some features * common to many importers*/ -enum aiImporterFlags -{ +enum aiImporterFlags { /** Indicates that there is a textual encoding of the * file format; and that it is supported.*/ aiImporterFlags_SupportTextFlavour = 0x1, @@ -87,8 +90,7 @@ enum aiImporterFlags * as importers/exporters are added to Assimp, so it might be useful * to have a common mechanism to query some rough importer * characteristics. */ -struct aiImporterDesc -{ +struct aiImporterDesc { /** Full name of the importer (i.e. Blender3D importer)*/ const char* mName; diff --git a/include/assimp/light.h b/include/assimp/light.h index 1667cfb8c..bdb2368c4 100644 --- a/include/assimp/light.h +++ b/include/assimp/light.h @@ -49,7 +49,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_LIGHT_H_INC #define AI_LIGHT_H_INC -#include "types.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #ifdef __cplusplus extern "C" { diff --git a/include/assimp/material.h b/include/assimp/material.h index 4b5a1293d..19a7c6970 100644 --- a/include/assimp/material.h +++ b/include/assimp/material.h @@ -48,7 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MATERIAL_H_INC #define AI_MATERIAL_H_INC -#include "types.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #ifdef __cplusplus extern "C" { @@ -196,34 +200,40 @@ enum aiTextureType * (#aiMaterialProperty::mSemantic) for all material properties * *not* related to textures. */ - aiTextureType_NONE = 0x0, + aiTextureType_NONE = 0, + + /** LEGACY API MATERIALS + * Legacy refers to materials which + * Were originally implemented in the specifications around 2000. + * These must never be removed, as most engines support them. + */ /** The texture is combined with the result of the diffuse * lighting equation. */ - aiTextureType_DIFFUSE = 0x1, + aiTextureType_DIFFUSE = 1, /** The texture is combined with the result of the specular * lighting equation. */ - aiTextureType_SPECULAR = 0x2, + aiTextureType_SPECULAR = 2, /** The texture is combined with the result of the ambient * lighting equation. */ - aiTextureType_AMBIENT = 0x3, + aiTextureType_AMBIENT = 3, /** The texture is added to the result of the lighting * calculation. It isn't influenced by incoming light. */ - aiTextureType_EMISSIVE = 0x4, + aiTextureType_EMISSIVE = 4, /** The texture is a height map. * * By convention, higher gray-scale values stand for * higher elevations from the base height. */ - aiTextureType_HEIGHT = 0x5, + aiTextureType_HEIGHT = 5, /** The texture is a (tangent space) normal-map. * @@ -231,7 +241,7 @@ enum aiTextureType * normal maps. Assimp does (intentionally) not * distinguish here. */ - aiTextureType_NORMALS = 0x6, + aiTextureType_NORMALS = 6, /** The texture defines the glossiness of the material. * @@ -240,21 +250,21 @@ enum aiTextureType * function defined to map the linear color values in the * texture to a suitable exponent. Have fun. */ - aiTextureType_SHININESS = 0x7, + aiTextureType_SHININESS = 7, /** The texture defines per-pixel opacity. * * Usually 'white' means opaque and 'black' means * 'transparency'. Or quite the opposite. Have fun. */ - aiTextureType_OPACITY = 0x8, + aiTextureType_OPACITY = 8, /** Displacement texture * * The exact purpose and format is application-dependent. * Higher color values stand for higher vertex displacements. */ - aiTextureType_DISPLACEMENT = 0x9, + aiTextureType_DISPLACEMENT = 9, /** Lightmap texture (aka Ambient Occlusion) * @@ -263,14 +273,28 @@ enum aiTextureType * scaling value for the final color value of a pixel. Its * intensity is not affected by incoming light. */ - aiTextureType_LIGHTMAP = 0xA, + aiTextureType_LIGHTMAP = 10, /** Reflection texture * * Contains the color of a perfect mirror reflection. * Rarely used, almost never for real-time applications. */ - aiTextureType_REFLECTION = 0xB, + aiTextureType_REFLECTION = 11, + + /** PBR Materials + * PBR definitions from maya and other modelling packages now use this standard. + * This was originally introduced around 2012. + * Support for this is in game engines like Godot, Unreal or Unity3D. + * Modelling packages which use this are very common now. + */ + + aiTextureType_BASE_COLOR = 12, + aiTextureType_NORMAL_CAMERA = 13, + aiTextureType_EMISSION_COLOR = 14, + aiTextureType_METALNESS = 15, + aiTextureType_DIFFUSE_ROUGHNESS = 16, + aiTextureType_AMBIENT_OCCLUSION = 17, /** Unknown texture * @@ -278,7 +302,7 @@ enum aiTextureType * above is considered to be 'unknown'. It is still imported, * but is excluded from any further post-processing. */ - aiTextureType_UNKNOWN = 0xC, + aiTextureType_UNKNOWN = 18, #ifndef SWIG diff --git a/include/assimp/material.inl b/include/assimp/material.inl index b05d6af6c..8ae6b88d3 100644 --- a/include/assimp/material.inl +++ b/include/assimp/material.inl @@ -49,14 +49,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MATERIAL_INL_INC #define AI_MATERIAL_INL_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + // --------------------------------------------------------------------------- -inline aiPropertyTypeInfo ai_real_to_property_type_info(float) -{ +AI_FORCE_INLINE +aiPropertyTypeInfo ai_real_to_property_type_info(float) { return aiPTI_Float; } -inline aiPropertyTypeInfo ai_real_to_property_type_info(double) -{ +AI_FORCE_INLINE +aiPropertyTypeInfo ai_real_to_property_type_info(double) { return aiPTI_Double; } // --------------------------------------------------------------------------- @@ -64,30 +68,30 @@ inline aiPropertyTypeInfo ai_real_to_property_type_info(double) //! @cond never // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::GetTexture( aiTextureType type, - unsigned int index, - C_STRUCT aiString* path, - aiTextureMapping* mapping /*= NULL*/, - unsigned int* uvindex /*= NULL*/, - ai_real* blend /*= NULL*/, - aiTextureOp* op /*= NULL*/, - aiTextureMapMode* mapmode /*= NULL*/) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::GetTexture( aiTextureType type, + unsigned int index, + C_STRUCT aiString* path, + aiTextureMapping* mapping /*= NULL*/, + unsigned int* uvindex /*= NULL*/, + ai_real* blend /*= NULL*/, + aiTextureOp* op /*= NULL*/, + aiTextureMapMode* mapmode /*= NULL*/) const { return ::aiGetMaterialTexture(this,type,index,path,mapping,uvindex,blend,op,mapmode); } // --------------------------------------------------------------------------- -inline unsigned int aiMaterial::GetTextureCount(aiTextureType type) const -{ +AI_FORCE_INLINE +unsigned int aiMaterial::GetTextureCount(aiTextureType type) const { return ::aiGetMaterialTextureCount(this,type); } // --------------------------------------------------------------------------- template -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx, Type* pOut, - unsigned int* pMax) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx, Type* pOut, + unsigned int* pMax) const { unsigned int iNum = pMax ? *pMax : 1; const aiMaterialProperty* prop; @@ -114,9 +118,9 @@ inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, // --------------------------------------------------------------------------- template -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,Type& pOut) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,Type& pOut) const { const aiMaterialProperty* prop; const aiReturn ret = ::aiGetMaterialProperty(this,pKey,type,idx, (const aiMaterialProperty**)&prop); @@ -136,60 +140,56 @@ inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,ai_real* pOut, - unsigned int* pMax) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,ai_real* pOut, + unsigned int* pMax) const { return ::aiGetMaterialFloatArray(this,pKey,type,idx,pOut,pMax); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,int* pOut, - unsigned int* pMax) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,int* pOut, + unsigned int* pMax) const { return ::aiGetMaterialIntegerArray(this,pKey,type,idx,pOut,pMax); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,ai_real& pOut) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,ai_real& pOut) const { return aiGetMaterialFloat(this,pKey,type,idx,&pOut); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,int& pOut) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,int& pOut) const { return aiGetMaterialInteger(this,pKey,type,idx,&pOut); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,aiColor4D& pOut) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiColor4D& pOut) const { return aiGetMaterialColor(this,pKey,type,idx,&pOut); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,aiColor3D& pOut) const -{ +AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiColor3D& pOut) const { aiColor4D c; const aiReturn ret = aiGetMaterialColor(this,pKey,type,idx,&c); pOut = aiColor3D(c.r,c.g,c.b); return ret; } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,aiString& pOut) const -{ +AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiString& pOut) const { return aiGetMaterialString(this,pKey,type,idx,&pOut); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,aiUVTransform& pOut) const -{ +AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiUVTransform& pOut) const { return aiGetMaterialUVTransform(this,pKey,type,idx,&pOut); } - // --------------------------------------------------------------------------- template aiReturn aiMaterial::AddProperty (const TYPE* pInput, @@ -204,84 +204,83 @@ aiReturn aiMaterial::AddProperty (const TYPE* pInput, } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const float* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE aiReturn aiMaterial::AddProperty(const float* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(float), pKey,type,index,aiPTI_Float); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const double* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const double* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(double), pKey,type,index,aiPTI_Double); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiUVTransform), pKey,type,index,ai_real_to_property_type_info(pInput->mRotation)); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const aiColor4D* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiColor4D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor4D), pKey,type,index,ai_real_to_property_type_info(pInput->a)); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const aiColor3D* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiColor3D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor3D), pKey,type,index,ai_real_to_property_type_info(pInput->b)); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const aiVector3D* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiVector3D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiVector3D), pKey,type,index,ai_real_to_property_type_info(pInput->x)); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const int* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const int* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(int), pKey,type,index,aiPTI_Integer); @@ -296,12 +295,12 @@ inline aiReturn aiMaterial::AddProperty(const int* pInput, // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const float* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const float* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(float), pKey,type,index,aiPTI_Float); @@ -309,12 +308,12 @@ inline aiReturn aiMaterial::AddProperty(const float* pInput, // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const double* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const double* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(double), pKey,type,index,aiPTI_Double); @@ -322,12 +321,12 @@ inline aiReturn aiMaterial::AddProperty(const double* pInput, // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiUVTransform), pKey,type,index,aiPTI_Float); @@ -335,12 +334,12 @@ inline aiReturn aiMaterial::AddProperty(const aiUVTransform* pInp // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const aiColor4D* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiColor4D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor4D), pKey,type,index,aiPTI_Float); @@ -348,12 +347,12 @@ inline aiReturn aiMaterial::AddProperty(const aiColor4D* pInput, // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const aiColor3D* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiColor3D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor3D), pKey,type,index,aiPTI_Float); @@ -361,12 +360,12 @@ inline aiReturn aiMaterial::AddProperty(const aiColor3D* pInput, // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const aiVector3D* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiVector3D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiVector3D), pKey,type,index,aiPTI_Float); @@ -374,12 +373,12 @@ inline aiReturn aiMaterial::AddProperty(const aiVector3D* pInput, // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const int* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const int* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(int), pKey,type,index,aiPTI_Integer); diff --git a/include/assimp/matrix3x3.h b/include/assimp/matrix3x3.h index 22b69561f..2c26cf92b 100644 --- a/include/assimp/matrix3x3.h +++ b/include/assimp/matrix3x3.h @@ -48,7 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MATRIX3X3_H_INC #define AI_MATRIX3X3_H_INC -#include "defs.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #ifdef __cplusplus @@ -65,10 +69,8 @@ template class aiVector2t; * defined thereby. */ template -class aiMatrix3x3t -{ +class aiMatrix3x3t { public: - aiMatrix3x3t() AI_NO_EXCEPT : a1(static_cast(1.0f)), a2(), a3(), b1(), b2(static_cast(1.0f)), b3(), @@ -82,8 +84,6 @@ public: c1(_c1), c2(_c2), c3(_c3) {} -public: - // matrix multiplication. aiMatrix3x3t& operator *= (const aiMatrix3x3t& m); aiMatrix3x3t operator * (const aiMatrix3x3t& m) const; @@ -101,8 +101,6 @@ public: template operator aiMatrix3x3t () const; -public: - // ------------------------------------------------------------------- /** @brief Construction from a 4x4 matrix. The remaining parts * of the matrix are ignored. @@ -122,7 +120,6 @@ public: aiMatrix3x3t& Inverse(); TReal Determinant() const; -public: // ------------------------------------------------------------------- /** @brief Returns a rotation matrix for a rotation around z * @param a Rotation angle, in radians diff --git a/include/assimp/matrix3x3.inl b/include/assimp/matrix3x3.inl index d9d45a3e9..1ce8c9691 100644 --- a/include/assimp/matrix3x3.inl +++ b/include/assimp/matrix3x3.inl @@ -48,10 +48,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MATRIX3X3_INL_INC #define AI_MATRIX3X3_INL_INC -#ifdef __cplusplus -#include "matrix3x3.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#ifdef __cplusplus +#include +#include -#include "matrix4x4.h" #include #include #include @@ -59,8 +63,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ------------------------------------------------------------------------------------------------ // Construction from a 4x4 matrix. The remaining parts of the matrix are ignored. template -inline aiMatrix3x3t::aiMatrix3x3t( const aiMatrix4x4t& pMatrix) -{ +AI_FORCE_INLINE +aiMatrix3x3t::aiMatrix3x3t( const aiMatrix4x4t& pMatrix) { a1 = pMatrix.a1; a2 = pMatrix.a2; a3 = pMatrix.a3; b1 = pMatrix.b1; b2 = pMatrix.b2; b3 = pMatrix.b3; c1 = pMatrix.c1; c2 = pMatrix.c2; c3 = pMatrix.c3; @@ -68,8 +72,8 @@ inline aiMatrix3x3t::aiMatrix3x3t( const aiMatrix4x4t& pMatrix) // ------------------------------------------------------------------------------------------------ template -inline aiMatrix3x3t& aiMatrix3x3t::operator *= (const aiMatrix3x3t& m) -{ +AI_FORCE_INLINE +aiMatrix3x3t& aiMatrix3x3t::operator *= (const aiMatrix3x3t& m) { *this = aiMatrix3x3t(m.a1 * a1 + m.b1 * a2 + m.c1 * a3, m.a2 * a1 + m.b2 * a2 + m.c2 * a3, m.a3 * a1 + m.b3 * a2 + m.c3 * a3, @@ -85,8 +89,7 @@ inline aiMatrix3x3t& aiMatrix3x3t::operator *= (const aiMatrix3x3t // ------------------------------------------------------------------------------------------------ template template -aiMatrix3x3t::operator aiMatrix3x3t () const -{ +aiMatrix3x3t::operator aiMatrix3x3t () const { return aiMatrix3x3t(static_cast(a1),static_cast(a2),static_cast(a3), static_cast(b1),static_cast(b2),static_cast(b3), static_cast(c1),static_cast(c2),static_cast(c3)); @@ -94,8 +97,8 @@ aiMatrix3x3t::operator aiMatrix3x3t () const // ------------------------------------------------------------------------------------------------ template -inline aiMatrix3x3t aiMatrix3x3t::operator* (const aiMatrix3x3t& m) const -{ +AI_FORCE_INLINE +aiMatrix3x3t aiMatrix3x3t::operator* (const aiMatrix3x3t& m) const { aiMatrix3x3t temp( *this); temp *= m; return temp; @@ -103,7 +106,8 @@ inline aiMatrix3x3t aiMatrix3x3t::operator* (const aiMatrix3x3t -inline TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) { +AI_FORCE_INLINE +TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) { switch ( p_iIndex ) { case 0: return &a1; @@ -119,7 +123,8 @@ inline TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) { // ------------------------------------------------------------------------------------------------ template -inline const TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) const { +AI_FORCE_INLINE +const TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) const { switch ( p_iIndex ) { case 0: return &a1; @@ -135,8 +140,8 @@ inline const TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) cons // ------------------------------------------------------------------------------------------------ template -inline bool aiMatrix3x3t::operator== (const aiMatrix4x4t& m) const -{ +AI_FORCE_INLINE +bool aiMatrix3x3t::operator== (const aiMatrix4x4t& m) const { return a1 == m.a1 && a2 == m.a2 && a3 == m.a3 && b1 == m.b1 && b2 == m.b2 && b3 == m.b3 && c1 == m.c1 && c2 == m.c2 && c3 == m.c3; @@ -144,14 +149,15 @@ inline bool aiMatrix3x3t::operator== (const aiMatrix4x4t& m) const // ------------------------------------------------------------------------------------------------ template -inline bool aiMatrix3x3t::operator!= (const aiMatrix4x4t& m) const -{ +AI_FORCE_INLINE +bool aiMatrix3x3t::operator!= (const aiMatrix4x4t& m) const { return !(*this == m); } // --------------------------------------------------------------------------- template -inline bool aiMatrix3x3t::Equal(const aiMatrix4x4t& m, TReal epsilon) const { +AI_FORCE_INLINE +bool aiMatrix3x3t::Equal(const aiMatrix4x4t& m, TReal epsilon) const { return std::abs(a1 - m.a1) <= epsilon && std::abs(a2 - m.a2) <= epsilon && @@ -166,8 +172,8 @@ inline bool aiMatrix3x3t::Equal(const aiMatrix4x4t& m, TReal epsil // ------------------------------------------------------------------------------------------------ template -inline aiMatrix3x3t& aiMatrix3x3t::Transpose() -{ +AI_FORCE_INLINE +aiMatrix3x3t& aiMatrix3x3t::Transpose() { // (TReal&) don't remove, GCC complains cause of packed fields std::swap( (TReal&)a2, (TReal&)b1); std::swap( (TReal&)a3, (TReal&)c1); @@ -177,15 +183,15 @@ inline aiMatrix3x3t& aiMatrix3x3t::Transpose() // ---------------------------------------------------------------------------------------- template -inline TReal aiMatrix3x3t::Determinant() const -{ +AI_FORCE_INLINE +TReal aiMatrix3x3t::Determinant() const { return a1*b2*c3 - a1*b3*c2 + a2*b3*c1 - a2*b1*c3 + a3*b1*c2 - a3*b2*c1; } // ---------------------------------------------------------------------------------------- template -inline aiMatrix3x3t& aiMatrix3x3t::Inverse() -{ +AI_FORCE_INLINE +aiMatrix3x3t& aiMatrix3x3t::Inverse() { // Compute the reciprocal determinant TReal det = Determinant(); if(det == static_cast(0.0)) @@ -219,8 +225,8 @@ inline aiMatrix3x3t& aiMatrix3x3t::Inverse() // ------------------------------------------------------------------------------------------------ template -inline aiMatrix3x3t& aiMatrix3x3t::RotationZ(TReal a, aiMatrix3x3t& out) -{ +AI_FORCE_INLINE +aiMatrix3x3t& aiMatrix3x3t::RotationZ(TReal a, aiMatrix3x3t& out) { out.a1 = out.b2 = std::cos(a); out.b1 = std::sin(a); out.a2 = - out.b1; @@ -234,8 +240,8 @@ inline aiMatrix3x3t& aiMatrix3x3t::RotationZ(TReal a, aiMatrix3x3t // ------------------------------------------------------------------------------------------------ // Returns a rotation matrix for a rotation around an arbitrary axis. template -inline aiMatrix3x3t& aiMatrix3x3t::Rotation( TReal a, const aiVector3t& axis, aiMatrix3x3t& out) -{ +AI_FORCE_INLINE +aiMatrix3x3t& aiMatrix3x3t::Rotation( TReal a, const aiVector3t& axis, aiMatrix3x3t& out) { TReal c = std::cos( a), s = std::sin( a), t = 1 - c; TReal x = axis.x, y = axis.y, z = axis.z; @@ -249,8 +255,8 @@ inline aiMatrix3x3t& aiMatrix3x3t::Rotation( TReal a, const aiVect // ------------------------------------------------------------------------------------------------ template -inline aiMatrix3x3t& aiMatrix3x3t::Translation( const aiVector2t& v, aiMatrix3x3t& out) -{ +AI_FORCE_INLINE +aiMatrix3x3t& aiMatrix3x3t::Translation( const aiVector2t& v, aiMatrix3x3t& out) { out = aiMatrix3x3t(); out.a3 = v.x; out.b3 = v.y; @@ -268,9 +274,8 @@ inline aiMatrix3x3t& aiMatrix3x3t::Translation( const aiVector2t -inline aiMatrix3x3t& aiMatrix3x3t::FromToMatrix(const aiVector3t& from, - const aiVector3t& to, aiMatrix3x3t& mtx) -{ +AI_FORCE_INLINE aiMatrix3x3t& aiMatrix3x3t::FromToMatrix(const aiVector3t& from, + const aiVector3t& to, aiMatrix3x3t& mtx) { const TReal e = from * to; const TReal f = (e < 0)? -e:e; @@ -352,6 +357,5 @@ inline aiMatrix3x3t& aiMatrix3x3t::FromToMatrix(const aiVector3t +#include #ifdef __cplusplus @@ -66,8 +70,7 @@ template class aiQuaterniont; * defined thereby. */ template -class aiMatrix4x4t -{ +class aiMatrix4x4t { public: /** set to identity */ @@ -91,8 +94,6 @@ public: aiMatrix4x4t(const aiVector3t& scaling, const aiQuaterniont& rotation, const aiVector3t& position); -public: - // array access operators /** @fn TReal* operator[] (unsigned int p_iIndex) * @param [in] p_iIndex - index of the row. @@ -120,8 +121,6 @@ public: template operator aiMatrix4x4t () const; -public: - // ------------------------------------------------------------------- /** @brief Transpose the matrix */ aiMatrix4x4t& Transpose(); @@ -182,7 +181,6 @@ public: void DecomposeNoScaling (aiQuaterniont& rotation, aiVector3t& position) const; - // ------------------------------------------------------------------- /** @brief Creates a trafo matrix from a set of euler angles * @param x Rotation angle for the x-axis, in radians @@ -192,7 +190,6 @@ public: aiMatrix4x4t& FromEulerAnglesXYZ(TReal x, TReal y, TReal z); aiMatrix4x4t& FromEulerAnglesXYZ(const aiVector3t& blubb); -public: // ------------------------------------------------------------------- /** @brief Returns a rotation matrix for a rotation around the x axis * @param a Rotation angle, in radians @@ -256,7 +253,6 @@ public: static aiMatrix4x4t& FromToMatrix(const aiVector3t& from, const aiVector3t& to, aiMatrix4x4t& out); -public: TReal a1, a2, a3, a4; TReal b1, b2, b3, b4; TReal c1, c2, c3, c4; diff --git a/include/assimp/matrix4x4.inl b/include/assimp/matrix4x4.inl index ebc67a06e..84079974f 100644 --- a/include/assimp/matrix4x4.inl +++ b/include/assimp/matrix4x4.inl @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -53,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "matrix4x4.h" #include "matrix3x3.h" #include "quaternion.h" +#include "MathFunctions.h" #include #include @@ -61,12 +60,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ---------------------------------------------------------------------------------------- template aiMatrix4x4t::aiMatrix4x4t() AI_NO_EXCEPT : - a1(1.0f), a2(), a3(), a4(), - b1(), b2(1.0f), b3(), b4(), - c1(), c2(), c3(1.0f), c4(), - d1(), d2(), d3(), d4(1.0f) -{ - + a1(1.0f), a2(), a3(), a4(), + b1(), b2(1.0f), b3(), b4(), + c1(), c2(), c3(1.0f), c4(), + d1(), d2(), d3(), d4(1.0f) { + // empty } // ---------------------------------------------------------------------------------------- @@ -75,19 +73,17 @@ aiMatrix4x4t::aiMatrix4x4t (TReal _a1, TReal _a2, TReal _a3, TReal _a4, TReal _b1, TReal _b2, TReal _b3, TReal _b4, TReal _c1, TReal _c2, TReal _c3, TReal _c4, TReal _d1, TReal _d2, TReal _d3, TReal _d4) : - a1(_a1), a2(_a2), a3(_a3), a4(_a4), - b1(_b1), b2(_b2), b3(_b3), b4(_b4), - c1(_c1), c2(_c2), c3(_c3), c4(_c4), - d1(_d1), d2(_d2), d3(_d3), d4(_d4) -{ - + a1(_a1), a2(_a2), a3(_a3), a4(_a4), + b1(_b1), b2(_b2), b3(_b3), b4(_b4), + c1(_c1), c2(_c2), c3(_c3), c4(_c4), + d1(_d1), d2(_d2), d3(_d3), d4(_d4) { + // empty } // ------------------------------------------------------------------------------------------------ template template -aiMatrix4x4t::operator aiMatrix4x4t () const -{ +aiMatrix4x4t::operator aiMatrix4x4t () const { return aiMatrix4x4t(static_cast(a1),static_cast(a2),static_cast(a3),static_cast(a4), static_cast(b1),static_cast(b2),static_cast(b3),static_cast(b4), static_cast(c1),static_cast(c2),static_cast(c3),static_cast(c4), @@ -97,8 +93,8 @@ aiMatrix4x4t::operator aiMatrix4x4t () const // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t::aiMatrix4x4t (const aiMatrix3x3t& m) -{ +AI_FORCE_INLINE +aiMatrix4x4t::aiMatrix4x4t (const aiMatrix3x3t& m) { a1 = m.a1; a2 = m.a2; a3 = m.a3; a4 = static_cast(0.0); b1 = m.b1; b2 = m.b2; b3 = m.b3; b4 = static_cast(0.0); c1 = m.c1; c2 = m.c2; c3 = m.c3; c4 = static_cast(0.0); @@ -107,8 +103,8 @@ inline aiMatrix4x4t::aiMatrix4x4t (const aiMatrix3x3t& m) // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t::aiMatrix4x4t (const aiVector3t& scaling, const aiQuaterniont& rotation, const aiVector3t& position) -{ +AI_FORCE_INLINE +aiMatrix4x4t::aiMatrix4x4t (const aiVector3t& scaling, const aiQuaterniont& rotation, const aiVector3t& position) { // build a 3x3 rotation matrix aiMatrix3x3t m = rotation.GetMatrix(); @@ -135,8 +131,8 @@ inline aiMatrix4x4t::aiMatrix4x4t (const aiVector3t& scaling, cons // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::operator *= (const aiMatrix4x4t& m) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::operator *= (const aiMatrix4x4t& m) { *this = aiMatrix4x4t( m.a1 * a1 + m.b1 * a2 + m.c1 * a3 + m.d1 * a4, m.a2 * a1 + m.b2 * a2 + m.c2 * a3 + m.d2 * a4, @@ -159,8 +155,7 @@ inline aiMatrix4x4t& aiMatrix4x4t::operator *= (const aiMatrix4x4t // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t aiMatrix4x4t::operator* (const TReal& aFloat) const -{ +AI_FORCE_INLINE aiMatrix4x4t aiMatrix4x4t::operator* (const TReal& aFloat) const { aiMatrix4x4t temp( a1 * aFloat, a2 * aFloat, @@ -183,8 +178,8 @@ inline aiMatrix4x4t aiMatrix4x4t::operator* (const TReal& aFloat) // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t aiMatrix4x4t::operator+ (const aiMatrix4x4t& m) const -{ +AI_FORCE_INLINE +aiMatrix4x4t aiMatrix4x4t::operator+ (const aiMatrix4x4t& m) const { aiMatrix4x4t temp( m.a1 + a1, m.a2 + a2, @@ -207,18 +202,16 @@ inline aiMatrix4x4t aiMatrix4x4t::operator+ (const aiMatrix4x4t -inline aiMatrix4x4t aiMatrix4x4t::operator* (const aiMatrix4x4t& m) const -{ +AI_FORCE_INLINE +aiMatrix4x4t aiMatrix4x4t::operator* (const aiMatrix4x4t& m) const { aiMatrix4x4t temp( *this); temp *= m; return temp; } - // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::Transpose() -{ +AI_FORCE_INLINE aiMatrix4x4t& aiMatrix4x4t::Transpose() { // (TReal&) don't remove, GCC complains cause of packed fields std::swap( (TReal&)b1, (TReal&)a2); std::swap( (TReal&)c1, (TReal&)a3); @@ -229,11 +222,10 @@ inline aiMatrix4x4t& aiMatrix4x4t::Transpose() return *this; } - // ---------------------------------------------------------------------------------------- template -inline TReal aiMatrix4x4t::Determinant() const -{ +AI_FORCE_INLINE +TReal aiMatrix4x4t::Determinant() const { return a1*b2*c3*d4 - a1*b2*c4*d3 + a1*b3*c4*d2 - a1*b3*c2*d4 + a1*b4*c2*d3 - a1*b4*c3*d2 - a2*b3*c4*d1 + a2*b3*c1*d4 - a2*b4*c1*d3 + a2*b4*c3*d1 - a2*b1*c3*d4 + a2*b1*c4*d3 @@ -244,8 +236,8 @@ inline TReal aiMatrix4x4t::Determinant() const // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::Inverse() -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::Inverse() { // Compute the reciprocal determinant const TReal det = Determinant(); if(det == static_cast(0.0)) @@ -289,9 +281,10 @@ inline aiMatrix4x4t& aiMatrix4x4t::Inverse() // ---------------------------------------------------------------------------------------- template -inline TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) { +AI_FORCE_INLINE +TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) { if (p_iIndex > 3) { - return NULL; + return nullptr; } switch ( p_iIndex ) { case 0: @@ -310,9 +303,10 @@ inline TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) { // ---------------------------------------------------------------------------------------- template -inline const TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) const { +AI_FORCE_INLINE +const TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) const { if (p_iIndex > 3) { - return NULL; + return nullptr; } switch ( p_iIndex ) { @@ -332,8 +326,8 @@ inline const TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) const // ---------------------------------------------------------------------------------------- template -inline bool aiMatrix4x4t::operator== (const aiMatrix4x4t& m) const -{ +AI_FORCE_INLINE +bool aiMatrix4x4t::operator== (const aiMatrix4x4t& m) const { return (a1 == m.a1 && a2 == m.a2 && a3 == m.a3 && a4 == m.a4 && b1 == m.b1 && b2 == m.b2 && b3 == m.b3 && b4 == m.b4 && c1 == m.c1 && c2 == m.c2 && c3 == m.c3 && c4 == m.c4 && @@ -342,14 +336,15 @@ inline bool aiMatrix4x4t::operator== (const aiMatrix4x4t& m) const // ---------------------------------------------------------------------------------------- template -inline bool aiMatrix4x4t::operator!= (const aiMatrix4x4t& m) const -{ +AI_FORCE_INLINE +bool aiMatrix4x4t::operator!= (const aiMatrix4x4t& m) const { return !(*this == m); } // --------------------------------------------------------------------------- template -inline bool aiMatrix4x4t::Equal(const aiMatrix4x4t& m, TReal epsilon) const { +AI_FORCE_INLINE +bool aiMatrix4x4t::Equal(const aiMatrix4x4t& m, TReal epsilon) const { return std::abs(a1 - m.a1) <= epsilon && std::abs(a2 - m.a2) <= epsilon && @@ -401,13 +396,10 @@ inline bool aiMatrix4x4t::Equal(const aiMatrix4x4t& m, TReal epsil \ do {} while(false) - - - template -inline void aiMatrix4x4t::Decompose (aiVector3t& pScaling, aiQuaterniont& pRotation, - aiVector3t& pPosition) const -{ +AI_FORCE_INLINE +void aiMatrix4x4t::Decompose (aiVector3t& pScaling, aiQuaterniont& pRotation, + aiVector3t& pPosition) const { ASSIMP_MATRIX4_4_DECOMPOSE_PART; // build a 3x3 rotation matrix @@ -420,8 +412,8 @@ inline void aiMatrix4x4t::Decompose (aiVector3t& pScaling, aiQuate } template -inline void aiMatrix4x4t::Decompose(aiVector3t& pScaling, aiVector3t& pRotation, aiVector3t& pPosition) const -{ +AI_FORCE_INLINE +void aiMatrix4x4t::Decompose(aiVector3t& pScaling, aiVector3t& pRotation, aiVector3t& pPosition) const { ASSIMP_MATRIX4_4_DECOMPOSE_PART; /* @@ -442,7 +434,7 @@ inline void aiMatrix4x4t::Decompose(aiVector3t& pScaling, aiVector */ // Use a small epsilon to solve floating-point inaccuracies - const TReal epsilon = 10e-3f; + const TReal epsilon = Assimp::Math::getEpsilon(); pRotation.y = std::asin(-vCols[0].z);// D. Angle around oY. @@ -475,10 +467,10 @@ inline void aiMatrix4x4t::Decompose(aiVector3t& pScaling, aiVector #undef ASSIMP_MATRIX4_4_DECOMPOSE_PART template -inline void aiMatrix4x4t::Decompose(aiVector3t& pScaling, aiVector3t& pRotationAxis, TReal& pRotationAngle, - aiVector3t& pPosition) const -{ -aiQuaterniont pRotation; +AI_FORCE_INLINE +void aiMatrix4x4t::Decompose(aiVector3t& pScaling, aiVector3t& pRotationAxis, TReal& pRotationAngle, + aiVector3t& pPosition) const { + aiQuaterniont pRotation; Decompose(pScaling, pRotation, pPosition); pRotation.Normalize(); @@ -500,9 +492,9 @@ aiQuaterniont pRotation; // ---------------------------------------------------------------------------------------- template -inline void aiMatrix4x4t::DecomposeNoScaling (aiQuaterniont& rotation, - aiVector3t& position) const -{ +AI_FORCE_INLINE +void aiMatrix4x4t::DecomposeNoScaling (aiQuaterniont& rotation, + aiVector3t& position) const { const aiMatrix4x4t& _this = *this; // extract translation @@ -516,15 +508,15 @@ inline void aiMatrix4x4t::DecomposeNoScaling (aiQuaterniont& rotat // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(const aiVector3t& blubb) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(const aiVector3t& blubb) { return FromEulerAnglesXYZ(blubb.x,blubb.y,blubb.z); } // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(TReal x, TReal y, TReal z) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(TReal x, TReal y, TReal z) { aiMatrix4x4t& _this = *this; TReal cx = std::cos(x); @@ -552,8 +544,8 @@ inline aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(TReal x, TRe // ---------------------------------------------------------------------------------------- template -inline bool aiMatrix4x4t::IsIdentity() const -{ +AI_FORCE_INLINE +bool aiMatrix4x4t::IsIdentity() const { // Use a small epsilon to solve floating-point inaccuracies const static TReal epsilon = 10e-3f; @@ -577,8 +569,8 @@ inline bool aiMatrix4x4t::IsIdentity() const // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::RotationX(TReal a, aiMatrix4x4t& out) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::RotationX(TReal a, aiMatrix4x4t& out) { /* | 1 0 0 0 | M = | 0 cos(A) -sin(A) 0 | @@ -592,8 +584,8 @@ inline aiMatrix4x4t& aiMatrix4x4t::RotationX(TReal a, aiMatrix4x4t // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::RotationY(TReal a, aiMatrix4x4t& out) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::RotationY(TReal a, aiMatrix4x4t& out) { /* | cos(A) 0 sin(A) 0 | M = | 0 1 0 0 | @@ -608,8 +600,8 @@ inline aiMatrix4x4t& aiMatrix4x4t::RotationY(TReal a, aiMatrix4x4t // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::RotationZ(TReal a, aiMatrix4x4t& out) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::RotationZ(TReal a, aiMatrix4x4t& out) { /* | cos(A) -sin(A) 0 0 | M = | sin(A) cos(A) 0 0 | @@ -624,26 +616,25 @@ inline aiMatrix4x4t& aiMatrix4x4t::RotationZ(TReal a, aiMatrix4x4t // ---------------------------------------------------------------------------------------- // Returns a rotation matrix for a rotation around an arbitrary axis. template -inline aiMatrix4x4t& aiMatrix4x4t::Rotation( TReal a, const aiVector3t& axis, aiMatrix4x4t& out) -{ - TReal c = std::cos( a), s = std::sin( a), t = 1 - c; - TReal x = axis.x, y = axis.y, z = axis.z; +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::Rotation( TReal a, const aiVector3t& axis, aiMatrix4x4t& out) { + TReal c = std::cos( a), s = std::sin( a), t = 1 - c; + TReal x = axis.x, y = axis.y, z = axis.z; - // Many thanks to MathWorld and Wikipedia - out.a1 = t*x*x + c; out.a2 = t*x*y - s*z; out.a3 = t*x*z + s*y; - out.b1 = t*x*y + s*z; out.b2 = t*y*y + c; out.b3 = t*y*z - s*x; - out.c1 = t*x*z - s*y; out.c2 = t*y*z + s*x; out.c3 = t*z*z + c; - out.a4 = out.b4 = out.c4 = static_cast(0.0); - out.d1 = out.d2 = out.d3 = static_cast(0.0); - out.d4 = static_cast(1.0); + // Many thanks to MathWorld and Wikipedia + out.a1 = t*x*x + c; out.a2 = t*x*y - s*z; out.a3 = t*x*z + s*y; + out.b1 = t*x*y + s*z; out.b2 = t*y*y + c; out.b3 = t*y*z - s*x; + out.c1 = t*x*z - s*y; out.c2 = t*y*z + s*x; out.c3 = t*z*z + c; + out.a4 = out.b4 = out.c4 = static_cast(0.0); + out.d1 = out.d2 = out.d3 = static_cast(0.0); + out.d4 = static_cast(1.0); - return out; + return out; } // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::Translation( const aiVector3t& v, aiMatrix4x4t& out) -{ +AI_FORCE_INLINE aiMatrix4x4t& aiMatrix4x4t::Translation( const aiVector3t& v, aiMatrix4x4t& out) { out = aiMatrix4x4t(); out.a4 = v.x; out.b4 = v.y; @@ -653,8 +644,8 @@ inline aiMatrix4x4t& aiMatrix4x4t::Translation( const aiVector3t -inline aiMatrix4x4t& aiMatrix4x4t::Scaling( const aiVector3t& v, aiMatrix4x4t& out) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::Scaling( const aiVector3t& v, aiMatrix4x4t& out) { out = aiMatrix4x4t(); out.a1 = v.x; out.b2 = v.y; @@ -673,9 +664,9 @@ inline aiMatrix4x4t& aiMatrix4x4t::Scaling( const aiVector3t -inline aiMatrix4x4t& aiMatrix4x4t::FromToMatrix(const aiVector3t& from, - const aiVector3t& to, aiMatrix4x4t& mtx) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::FromToMatrix(const aiVector3t& from, + const aiVector3t& to, aiMatrix4x4t& mtx) { aiMatrix3x3t m3; aiMatrix3x3t::FromToMatrix(from,to,m3); mtx = aiMatrix4x4t(m3); diff --git a/include/assimp/mesh.h b/include/assimp/mesh.h index f1628f1f5..eb30ad5df 100644 --- a/include/assimp/mesh.h +++ b/include/assimp/mesh.h @@ -48,6 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MESH_H_INC #define AI_MESH_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/metadata.h b/include/assimp/metadata.h index 3a1dd1442..849d90f48 100644 --- a/include/assimp/metadata.h +++ b/include/assimp/metadata.h @@ -48,6 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_METADATA_H_INC #define AI_METADATA_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #if defined(_MSC_VER) && (_MSC_VER <= 1500) # include "Compiler/pstdint.h" #else diff --git a/include/assimp/pbrmaterial.h b/include/assimp/pbrmaterial.h index ce5f82217..892a6347f 100644 --- a/include/assimp/pbrmaterial.h +++ b/include/assimp/pbrmaterial.h @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -44,9 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file pbrmaterial.h * @brief Defines the material system of the library */ +#pragma once #ifndef AI_PBRMATERIAL_H_INC #define AI_PBRMATERIAL_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR "$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0 #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0 #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0 diff --git a/include/assimp/postprocess.h b/include/assimp/postprocess.h index 2a7441421..77d387c7e 100644 --- a/include/assimp/postprocess.h +++ b/include/assimp/postprocess.h @@ -47,7 +47,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_POSTPROCESS_H_INC #define AI_POSTPROCESS_H_INC -#include "types.h" +#include + +#ifdef __GNUC__ +# pragma GCC system_header +#endif #ifdef __cplusplus extern "C" { diff --git a/include/assimp/qnan.h b/include/assimp/qnan.h index 0918bde5e..06780da5b 100644 --- a/include/assimp/qnan.h +++ b/include/assimp/qnan.h @@ -50,19 +50,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * but last time I checked compiler coverage was so bad that I decided * to reinvent the wheel. */ - +#pragma once #ifndef AI_QNAN_H_INCLUDED #define AI_QNAN_H_INCLUDED +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include + #include #include // --------------------------------------------------------------------------- /** Data structure to represent the bit pattern of a 32 Bit * IEEE 754 floating-point number. */ -union _IEEESingle -{ +union _IEEESingle { float Float; struct { @@ -75,8 +79,7 @@ union _IEEESingle // --------------------------------------------------------------------------- /** Data structure to represent the bit pattern of a 64 Bit * IEEE 754 floating-point number. */ -union _IEEEDouble -{ +union _IEEEDouble { double Double; struct { @@ -89,8 +92,7 @@ union _IEEEDouble // --------------------------------------------------------------------------- /** Check whether a given float is qNaN. * @param in Input value */ -AI_FORCE_INLINE bool is_qnan(float in) -{ +AI_FORCE_INLINE bool is_qnan(float in) { // the straightforward solution does not work: // return (in != in); // compiler generates code like this @@ -107,8 +109,7 @@ AI_FORCE_INLINE bool is_qnan(float in) // --------------------------------------------------------------------------- /** Check whether a given double is qNaN. * @param in Input value */ -AI_FORCE_INLINE bool is_qnan(double in) -{ +AI_FORCE_INLINE bool is_qnan(double in) { // the straightforward solution does not work: // return (in != in); // compiler generates code like this @@ -127,8 +128,7 @@ AI_FORCE_INLINE bool is_qnan(double in) * * Denorms return false, they're treated like normal values. * @param in Input value */ -AI_FORCE_INLINE bool is_special_float(float in) -{ +AI_FORCE_INLINE bool is_special_float(float in) { _IEEESingle temp; memcpy(&temp, &in, sizeof(float)); return (temp.IEEE.Exp == (1u << 8)-1); @@ -139,8 +139,7 @@ AI_FORCE_INLINE bool is_special_float(float in) * * Denorms return false, they're treated like normal values. * @param in Input value */ -AI_FORCE_INLINE bool is_special_float(double in) -{ +AI_FORCE_INLINE bool is_special_float(double in) { _IEEESingle temp; memcpy(&temp, &in, sizeof(float)); return (temp.IEEE.Exp == (1u << 11)-1); @@ -150,15 +149,13 @@ AI_FORCE_INLINE bool is_special_float(double in) /** Check whether a float is NOT qNaN. * @param in Input value */ template -AI_FORCE_INLINE bool is_not_qnan(TReal in) -{ +AI_FORCE_INLINE bool is_not_qnan(TReal in) { return !is_qnan(in); } // --------------------------------------------------------------------------- /** @brief Get a fresh qnan. */ -AI_FORCE_INLINE ai_real get_qnan() -{ +AI_FORCE_INLINE ai_real get_qnan() { return std::numeric_limits::quiet_NaN(); } diff --git a/include/assimp/quaternion.h b/include/assimp/quaternion.h index 96574d24b..ae45959b4 100644 --- a/include/assimp/quaternion.h +++ b/include/assimp/quaternion.h @@ -49,7 +49,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef __cplusplus -#include "defs.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include template class aiVector3t; template class aiMatrix3x3t; diff --git a/include/assimp/quaternion.inl b/include/assimp/quaternion.inl index c26648215..3ce514d1b 100644 --- a/include/assimp/quaternion.inl +++ b/include/assimp/quaternion.inl @@ -48,8 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_QUATERNION_INL_INC #define AI_QUATERNION_INL_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifdef __cplusplus -#include "quaternion.h" +#include #include diff --git a/include/assimp/scene.h b/include/assimp/scene.h index 2667db85b..e69c81803 100644 --- a/include/assimp/scene.h +++ b/include/assimp/scene.h @@ -48,14 +48,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_SCENE_H_INC #define AI_SCENE_H_INC -#include "types.h" -#include "texture.h" -#include "mesh.h" -#include "light.h" -#include "camera.h" -#include "material.h" -#include "anim.h" -#include "metadata.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include +#include +#include +#include +#include +#include +#include +#include #ifdef __cplusplus # include diff --git a/include/assimp/texture.h b/include/assimp/texture.h index dc6cbef65..0867659f4 100644 --- a/include/assimp/texture.h +++ b/include/assimp/texture.h @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -53,13 +51,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_TEXTURE_H_INC #define AI_TEXTURE_H_INC -#include "types.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #ifdef __cplusplus extern "C" { #endif - // -------------------------------------------------------------------------------- /** \def AI_EMBEDDED_TEXNAME_PREFIX @@ -79,7 +80,6 @@ extern "C" { # define AI_MAKE_EMBEDDED_TEXNAME(_n_) AI_EMBEDDED_TEXNAME_PREFIX # _n_ #endif - #include "./Compiler/pushpack1.h" // -------------------------------------------------------------------------------- @@ -87,8 +87,7 @@ extern "C" { * * Used by aiTexture. */ -struct aiTexel -{ +struct aiTexel { unsigned char b,g,r,a; #ifdef __cplusplus diff --git a/include/assimp/types.h b/include/assimp/types.h index 331b8cd03..e32cae331 100644 --- a/include/assimp/types.h +++ b/include/assimp/types.h @@ -48,22 +48,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_TYPES_H_INC #define AI_TYPES_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + // Some runtime headers #include #include #include #include +#include // Our compile configuration -#include "defs.h" +#include // Some types moved to separate header due to size of operators -#include "vector3.h" -#include "vector2.h" -#include "color4.h" -#include "matrix3x3.h" -#include "matrix4x4.h" -#include "quaternion.h" +#include +#include +#include +#include +#include +#include + +typedef int32_t ai_int32; +typedef uint32_t ai_uint32 ; #ifdef __cplusplus #include @@ -71,7 +79,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // for aiString::Set(const std::string&) namespace Assimp { - //! @cond never +//! @cond never namespace Intern { // -------------------------------------------------------------------- /** @brief Internal helper class to utilize our internal new/delete @@ -269,8 +277,8 @@ struct aiString } /** Copy constructor */ - aiString(const aiString& rOther) : - length(rOther.length) + aiString(const aiString& rOther) + : length(rOther.length) { // Crop the string to the maximum length length = length>=MAXLEN?MAXLEN-1:length; @@ -280,7 +288,7 @@ struct aiString /** Constructor from std::string */ explicit aiString(const std::string& pString) : - length(pString.length()) + length( (ai_uint32) pString.length()) { length = length>=MAXLEN?MAXLEN-1:length; memcpy( data, pString.c_str(), length); @@ -292,15 +300,15 @@ struct aiString if( pString.length() > MAXLEN - 1) { return; } - length = pString.length(); + length = (ai_uint32)pString.length(); memcpy( data, pString.c_str(), length); data[length] = 0; } /** Copy a const char* to the aiString */ void Set( const char* sz) { - const size_t len = ::strlen(sz); - if( len > MAXLEN - 1) { + const ai_int32 len = (ai_uint32) ::strlen(sz); + if( len > (ai_int32)MAXLEN - 1) { return; } length = len; @@ -346,7 +354,7 @@ struct aiString /** Append a string to the string */ void Append (const char* app) { - const size_t len = ::strlen(app); + const ai_uint32 len = (ai_uint32) ::strlen(app); if (!len) { return; } @@ -379,7 +387,7 @@ struct aiString /** Binary length of the string excluding the terminal 0. This is NOT the * logical length of strings containing UTF-8 multi-byte sequences! It's * the number of bytes from the beginning of the string to its end.*/ - size_t length; + ai_uint32 length; /** String buffer. Size limit is MAXLEN */ char data[MAXLEN]; diff --git a/include/assimp/vector2.h b/include/assimp/vector2.h index d5ef00154..c8b1ebbbc 100644 --- a/include/assimp/vector2.h +++ b/include/assimp/vector2.h @@ -47,6 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_VECTOR2D_H_INC #define AI_VECTOR2D_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifdef __cplusplus # include #else diff --git a/include/assimp/vector2.inl b/include/assimp/vector2.inl index 3b7a7beab..4bbf432ff 100644 --- a/include/assimp/vector2.inl +++ b/include/assimp/vector2.inl @@ -48,8 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_VECTOR2D_INL_INC #define AI_VECTOR2D_INL_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifdef __cplusplus -#include "vector2.h" +#include #include diff --git a/include/assimp/vector3.h b/include/assimp/vector3.h index 7ff25cf0a..fffeb12ad 100644 --- a/include/assimp/vector3.h +++ b/include/assimp/vector3.h @@ -47,13 +47,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_VECTOR3D_H_INC #define AI_VECTOR3D_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifdef __cplusplus # include #else # include #endif -#include "defs.h" +#include #ifdef __cplusplus @@ -63,16 +67,13 @@ template class aiMatrix4x4t; // --------------------------------------------------------------------------- /** Represents a three-dimensional vector. */ template -class aiVector3t -{ +class aiVector3t { public: aiVector3t() AI_NO_EXCEPT : x(), y(), z() {} aiVector3t(TReal _x, TReal _y, TReal _z) : x(_x), y(_y), z(_z) {} explicit aiVector3t (TReal _xyz ) : x(_xyz), y(_xyz), z(_xyz) {} aiVector3t( const aiVector3t& o ) = default; -public: - // combined operators const aiVector3t& operator += (const aiVector3t& o); const aiVector3t& operator -= (const aiVector3t& o); @@ -97,7 +98,6 @@ public: template operator aiVector3t () const; -public: /** @brief Set the components of a vector * @param pX X component * @param pY Y component diff --git a/include/assimp/vector3.inl b/include/assimp/vector3.inl index 2fce6edde..6682d3b32 100644 --- a/include/assimp/vector3.inl +++ b/include/assimp/vector3.inl @@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_VECTOR3D_INL_INC #ifdef __cplusplus -#include "vector3.h" +#include #include diff --git a/include/assimp/version.h b/include/assimp/version.h index c62a40e11..2fdd37a43 100644 --- a/include/assimp/version.h +++ b/include/assimp/version.h @@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_VERSION_H_INC #define AI_VERSION_H_INC -#include "defs.h" +#include #ifdef __cplusplus extern "C" { diff --git a/port/PyAssimp/pyassimp/helper.py b/port/PyAssimp/pyassimp/helper.py index 4003fb5ad..5c1aca827 100644 --- a/port/PyAssimp/pyassimp/helper.py +++ b/port/PyAssimp/pyassimp/helper.py @@ -274,8 +274,8 @@ def hasattr_silent(object, name): """ try: - if not object: - return False + if not object: + return False return hasattr(object, name) except AttributeError: return False diff --git a/samples/SimpleOpenGL/CMakeLists.txt b/samples/SimpleOpenGL/CMakeLists.txt index e594f2dae..93f389741 100644 --- a/samples/SimpleOpenGL/CMakeLists.txt +++ b/samples/SimpleOpenGL/CMakeLists.txt @@ -25,6 +25,7 @@ INCLUDE_DIRECTORIES( ${Assimp_SOURCE_DIR}/include ${Assimp_SOURCE_DIR}/code ${OPENGL_INCLUDE_DIR} + ${GLUT_INCLUDE_DIR} ${Assimp_SOURCE_DIR}/samples/freeglut/include ) diff --git a/samples/SimpleOpenGL/Sample_SimpleOpenGL.c b/samples/SimpleOpenGL/Sample_SimpleOpenGL.c index 2dec5bc01..a8a3532cf 100644 --- a/samples/SimpleOpenGL/Sample_SimpleOpenGL.c +++ b/samples/SimpleOpenGL/Sample_SimpleOpenGL.c @@ -26,9 +26,9 @@ #include /* the global Assimp scene object */ -const struct aiScene* scene = NULL; +const C_STRUCT aiScene* scene = NULL; GLuint scene_list = 0; -struct aiVector3D scene_min, scene_max, scene_center; +C_STRUCT aiVector3D scene_min, scene_max, scene_center; /* current rotation angle */ static float angle = 0.f; @@ -49,22 +49,22 @@ void reshape(int width, int height) } /* ---------------------------------------------------------------------------- */ -void get_bounding_box_for_node (const struct aiNode* nd, - struct aiVector3D* min, - struct aiVector3D* max, - struct aiMatrix4x4* trafo +void get_bounding_box_for_node (const C_STRUCT aiNode* nd, + C_STRUCT aiVector3D* min, + C_STRUCT aiVector3D* max, + C_STRUCT aiMatrix4x4* trafo ){ - struct aiMatrix4x4 prev; + C_STRUCT aiMatrix4x4 prev; unsigned int n = 0, t; prev = *trafo; aiMultiplyMatrix4(trafo,&nd->mTransformation); for (; n < nd->mNumMeshes; ++n) { - const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; + const C_STRUCT aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; for (t = 0; t < mesh->mNumVertices; ++t) { - struct aiVector3D tmp = mesh->mVertices[t]; + C_STRUCT aiVector3D tmp = mesh->mVertices[t]; aiTransformVecByMatrix4(&tmp,trafo); min->x = aisgl_min(min->x,tmp.x); @@ -84,9 +84,9 @@ void get_bounding_box_for_node (const struct aiNode* nd, } /* ---------------------------------------------------------------------------- */ -void get_bounding_box (struct aiVector3D* min, struct aiVector3D* max) +void get_bounding_box(C_STRUCT aiVector3D* min, C_STRUCT aiVector3D* max) { - struct aiMatrix4x4 trafo; + C_STRUCT aiMatrix4x4 trafo; aiIdentityMatrix4(&trafo); min->x = min->y = min->z = 1e10f; @@ -95,7 +95,7 @@ void get_bounding_box (struct aiVector3D* min, struct aiVector3D* max) } /* ---------------------------------------------------------------------------- */ -void color4_to_float4(const struct aiColor4D *c, float f[4]) +void color4_to_float4(const C_STRUCT aiColor4D *c, float f[4]) { f[0] = c->r; f[1] = c->g; @@ -113,16 +113,16 @@ void set_float4(float f[4], float a, float b, float c, float d) } /* ---------------------------------------------------------------------------- */ -void apply_material(const struct aiMaterial *mtl) +void apply_material(const C_STRUCT aiMaterial *mtl) { float c[4]; GLenum fill_mode; int ret1, ret2; - struct aiColor4D diffuse; - struct aiColor4D specular; - struct aiColor4D ambient; - struct aiColor4D emission; + C_STRUCT aiColor4D diffuse; + C_STRUCT aiColor4D specular; + C_STRUCT aiColor4D ambient; + C_STRUCT aiColor4D emission; ai_real shininess, strength; int two_sided; int wireframe; @@ -179,11 +179,11 @@ void apply_material(const struct aiMaterial *mtl) } /* ---------------------------------------------------------------------------- */ -void recursive_render (const struct aiScene *sc, const struct aiNode* nd) +void recursive_render (const C_STRUCT aiScene *sc, const C_STRUCT aiNode* nd) { unsigned int i; unsigned int n = 0, t; - struct aiMatrix4x4 m = nd->mTransformation; + C_STRUCT aiMatrix4x4 m = nd->mTransformation; /* update transform */ aiTransposeMatrix4(&m); @@ -192,7 +192,7 @@ void recursive_render (const struct aiScene *sc, const struct aiNode* nd) /* draw all meshes assigned to this node */ for (; n < nd->mNumMeshes; ++n) { - const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; + const C_STRUCT aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; apply_material(sc->mMaterials[mesh->mMaterialIndex]); @@ -203,7 +203,7 @@ void recursive_render (const struct aiScene *sc, const struct aiNode* nd) } for (t = 0; t < mesh->mNumFaces; ++t) { - const struct aiFace* face = &mesh->mFaces[t]; + const C_STRUCT aiFace* face = &mesh->mFaces[t]; GLenum face_mode; switch(face->mNumIndices) { @@ -324,7 +324,7 @@ int loadasset (const char* path) /* ---------------------------------------------------------------------------- */ int main(int argc, char **argv) { - struct aiLogStream stream; + C_STRUCT aiLogStream stream; glutInitWindowSize(900,600); glutInitWindowPosition(100,100); diff --git a/test/models/FBX/transparentTest.fbx b/test/models/FBX/transparentTest.fbx new file mode 100644 index 000000000..2c4f1cd82 --- /dev/null +++ b/test/models/FBX/transparentTest.fbx @@ -0,0 +1,839 @@ +Kaydara FBX Binary    FBXHeaderExtension\   FBXHeaderVersionI x   +FBXVersionI   EncryptionTypeI  CreationTimeStamp   VersionI   YearI   MonthI    DayI '   HourI ?   MinuteI W   SecondI t   MillisecondID   ' CreatorS" FBX SDK/FBX Plugins version 2017.1  ' SceneInfoS GlobalInfo SceneInfoS UserData  TypeS UserData0   VersionId  MetaData^   VersionId u   TitleS    SubjectS    AuthorS    KeywordsS    RevisionS    CommentS  Properties70  q PS DocumentUrlS KStringS UrlS SC C:\Users\Destranix\Documents\maya\projects\Test\transparentTest.fbx  t PS SrcDocumentUrlS KStringS UrlS SC C:\Users\Destranix\Documents\maya\projects\Test\transparentTest.fbxL  $ PS OriginalS CompoundS S   B PS Original|ApplicationVendorS KStringS S S Autodesk  < PS Original|ApplicationNameS KStringS S S Maya3  ? PS Original|ApplicationVersionS KStringS S S 2017  M PS Original|DateTime_GMTS DateTimeS S S 11/09/2019 14:11:05.265  t PS Original|FileNameS KStringS S SC C:\Users\Destranix\Documents\maya\projects\Test\transparentTest.fbxC  % PS LastSavedS CompoundS S   C PS LastSaved|ApplicationVendorS KStringS S S Autodesk  = PS LastSaved|ApplicationNameS KStringS S S Maya-  @ PS LastSaved|ApplicationVersionS KStringS S S 2017  N PS LastSaved|DateTime_GMTS DateTimeS S S 11/09/2019 14:11:05.265  p PS! Original|ApplicationActiveProjectS KStringS S S/ C:\Users\Destranix\Documents\maya\projects\Test  PS Original|ApplicationNativeFileS KStringS S SB C:\Users\Destranix\Documents\maya\projects\Test\transparentTest.mb    FileIdR (//ȶø+%   CreationTimeS 2019-09-11 16:11:05:324c  6 CreatorS1 FBX SDK/FBX Plugins version 2017.1 build=20161007 GlobalSettings   VersionI  Properties70  ) PS UpAxisS intS IntegerS I " +  - PS + UpAxisSignS intS IntegerS I \ +  , PS FrontAxisS intS IntegerS I +  0 PS FrontAxisSignS intS IntegerS I +  , PS CoordAxisS intS IntegerS I   0 PS CoordAxisSignS intS IntegerS I Q  1 PS OriginalUpAxisS intS IntegerS I  5 PS OriginalUpAxisSignS intS IntegerS I  8 PS UnitScaleFactorS doubleS NumberS D ?(  @ PS OriginalUnitScaleFactorS doubleS NumberS D ?~  H PS AmbientColorS ColorRGBS ColorS D D D  A PS DefaultCameraS KStringS S S Producer Perspective  % PS TimeModeS enumS S I 7  ) PS TimeProtocolS enumS S I q  , PS SnapOnFrameModeS enumS S I  3 PS TimeSpanStartS KTimeS TimeS LR^r  2 PS TimeSpanStopS KTimeS TimeS LY 8  8 PS CustomFrameRateS doubleS NumberS D l  & PS + TimeMarkerS CompoundS S   4 PS CurrentTimeMarkerS intS IntegerS I  Documents   CountI    DocumentL@q S S Scene Properties70o  & PS SourceObjectS objectS S   ; PS ActiveAnimStackNameS KStringS S S Take 001   RootNodeL ! +References (\ DefinitionsR   VersionId i   CountI@    +ObjectTypeS GlobalSettings   CountI    +ObjectTypeS AnimationStack   CountI    PropertyTemplateS FbxAnimStack Properties70x  + PS DescriptionS KStringS S S   0 PS + LocalStartS KTimeS TimeS L   / PS LocalStopS KTimeS TimeS L 5  4 PS ReferenceStartS KTimeS TimeS L v  3 PS ReferenceStopS KTimeS TimeS L Z   +ObjectTypeS AnimationLayer   CountI M   PropertyTemplateS FbxAnimLayer@ Properties70]  * PS WeightS NumberS S AD Y@  ! PS MuteS boolS S I   ! PS SoloS boolS S I   ! PS LockS boolS S I 9  A PS ColorS ColorRGBS ColorS D?D?D?m  & PS BlendModeS enumS S I   5 PS RotationAccumulationModeS enumS S I   2 PS ScaleAccumulationModeS enumS S I 3  5 PS BlendModeBypassS ULongLongS S L   +ObjectTypeS Geometry   CountI   PropertyTemplateS FbxMesh Properties70&  A PS ColorS ColorRGBS ColorS D?D?D?x  D PS BBoxMinS Vector3DS VectorS D D D   D PS BBoxMaxS Vector3DS VectorS D D D   / PS Primary VisibilityS boolS S I ?  * PS Casts ShadowsS boolS S I y  , PS Receive ShadowsS boolS S I   +ObjectTypeS Material   CountI    PropertyTemplateS FbxSurfacePhong Properties70d  1 PS ShadingModelS KStringS S S Phong  ' PS + MultiLayerS boolS S I   B PS EmissiveColorS ColorS S AD D D )  2 PS EmissiveFactorS NumberS S AD ?x  A PS AmbientColorS ColorS S AD?D?D?  1 PS AmbientFactorS NumberS S AD ?  A PS DiffuseColorS ColorS S AD?D?D?E  1 PS DiffuseFactorS NumberS S AD ?  A PS BumpS Vector3DS VectorS D D D   F PS NormalMapS Vector3DS VectorS D D D )  3 PS + BumpFactorS doubleS NumberS D ?|  E PS TransparentColorS ColorS S AD D D   6 PS TransparencyFactorS NumberS S AD   M PS DisplacementColorS ColorRGBS ColorS D D D d  ; PS DisplacementFactorS doubleS NumberS D ?  S PS VectorDisplacementColorS ColorRGBS ColorS D D D   A PS VectorDisplacementFactorS doubleS NumberS D ?d  B PS SpecularColorS ColorS S AD?D?D?  2 PS SpecularFactorS NumberS S AD ?  5 PS ShininessExponentS NumberS S AD 4@9  D PS ReflectionColorS ColorS S AD D D {  4 PS ReflectionFactorS NumberS S AD ? ^#  +ObjectTypeS Texture   CountI Q#   PropertyTemplateS FbxFileTextureD# Properties70^  + PS TextureTypeUseS enumS S I   1 PS Texture alphaS NumberS S AD ?  / PS CurrentMappingTypeS enumS S I   & PS WrapModeUS enumS S I B  & PS WrapModeVS enumS S I s  # PS UVSwapS boolS S I  - PS PremultiplyAlphaS boolS S I  A PS TranslationS VectorS S AD D D I!  > PS RotationS VectorS S AD D D !  = PS ScalingS VectorS S AD ?D ?D ?!  Q PS TextureRotationPivotS Vector3DS VectorS D D D Q"  P PS TextureScalingPivotS Vector3DS VectorS D D D "  4 PS CurrentTextureBlendModeS enumS S I "  , PS UVSetS KStringS S S default#  ( PS UseMaterialS boolS S I 7#  & PS UseMipMapS boolS S I 7  + +ObjectTypeS Model#   CountI 6  PropertyTemplateS FbxNode6 Properties70$  2 PS QuaternionInterpolateS enumS S I q$  K PS RotationOffsetS Vector3DS VectorS D D D $  J PS RotationPivotS Vector3DS VectorS D D D !%  J PS ScalingOffsetS Vector3DS VectorS D D D x%  I PS ScalingPivotS Vector3DS VectorS D D D %  . PS TranslationActiveS boolS S I &  K PS TranslationMinS Vector3DS VectorS D D D f&  K PS TranslationMaxS Vector3DS VectorS D D D &  , PS TranslationMinXS boolS S I &  , PS TranslationMinYS boolS S I '  , PS TranslationMinZS boolS S I N'  , PS TranslationMaxXS boolS S I '  , PS TranslationMaxYS boolS S I '  , PS TranslationMaxZS boolS S I '  * PS RotationOrderS enumS S I >(  6 PS RotationSpaceForLimitOnlyS boolS S I (  ; PS RotationStiffnessXS doubleS NumberS D (  ; PS RotationStiffnessYS doubleS NumberS D )  ; PS RotationStiffnessZS doubleS NumberS D W)  0 PS AxisLenS doubleS NumberS D $@)  H PS PreRotationS Vector3DS VectorS D D D *  I PS PostRotationS Vector3DS VectorS D D D =*  + PS RotationActiveS boolS S I *  H PS RotationMinS Vector3DS VectorS D D D *  H PS RotationMaxS Vector3DS VectorS D D D +  ) PS RotationMinXS boolS S I W+  ) PS RotationMinYS boolS S I +  ) PS RotationMinZS boolS S I +  ) PS RotationMaxXS boolS S I +  ) PS RotationMaxYS boolS S I 3,  ) PS RotationMaxZS boolS S I i,  ( PS InheritTypeS enumS S I ,  * PS ScalingActiveS boolS S I ,  G PS + ScalingMinS Vector3DS VectorS D D D K-  G PS + ScalingMaxS Vector3DS VectorS D ?D ?D ?-  ( PS ScalingMinXS boolS S I -  ( PS ScalingMinYS boolS S I -  ( PS ScalingMinZS boolS S I #.  ( PS ScalingMaxXS boolS S I Y.  ( PS ScalingMaxYS boolS S I .  ( PS ScalingMaxZS boolS S I .  Q PS GeometricTranslationS Vector3DS VectorS D D D J/  N PS GeometricRotationS Vector3DS VectorS D D D /  M PS GeometricScalingS Vector3DS VectorS D ?D ?D ?/  6 PS MinDampRangeXS doubleS NumberS D -0  6 PS MinDampRangeYS doubleS NumberS D q0  6 PS MinDampRangeZS doubleS NumberS D 0  6 PS MaxDampRangeXS doubleS NumberS D 0  6 PS MaxDampRangeYS doubleS NumberS D =1  6 PS MaxDampRangeZS doubleS NumberS D 1  9 PS MinDampStrengthXS doubleS NumberS D 1  9 PS MinDampStrengthYS doubleS NumberS D 2  9 PS MinDampStrengthZS doubleS NumberS D Y2  9 PS MaxDampStrengthXS doubleS NumberS D 2  9 PS MaxDampStrengthYS doubleS NumberS D 2  9 PS MaxDampStrengthZS doubleS NumberS D ,3  7 PS PreferedAngleXS doubleS NumberS D q3  7 PS PreferedAngleYS doubleS NumberS D 3  7 PS PreferedAngleZS doubleS NumberS D 3  ( PS LookAtPropertyS objectS S $4  * PS UpVectorPropertyS objectS S S4  ! PS ShowS boolS S I 4  8 PS NegativePercentShapeSupportS boolS S I 4  8 PS DefaultAttributeIndexS intS IntegerS I5  # PS FreezeS boolS S I A5  # PS LODBoxS boolS S I 5  N PS Lcl TranslationS Lcl TranslationS S AD D D 5  H PS Lcl RotationS Lcl RotationS S AD D D G6  F PS Lcl ScalingS Lcl ScalingS S AD ?D ?D ?6  2 PS + VisibilityS + VisibilityS S AD ?6  E PS Visibility InheritanceS Visibility InheritanceS S I R   +ObjectTypeS NodeAttributeA7   CountI R   PropertyTemplateS FbxCamera R Properties707  A PS ColorS ColorRGBS ColorS D?D?D? 8  > PS PositionS VectorS S AD D D l8  > PS UpVectorS VectorS S AD D ?D 8  F PS InterestPositionS VectorS S AD D D 8  & PS RollS RollS S AD <9  : PS OpticalCenterXS OpticalCenterXS S AD 9  : PS OpticalCenterYS OpticalCenterYS S AD 9  D PS BackgroundColorS ColorS S AD)\(?D)\(?D)\(?:  - PS TurnTableS NumberS S AD P:  1 PS DisplayTurnTableIconS boolS S I :  * PS UseMotionBlurS boolS S I :  2 PS UseRealTimeMotionBlurS boolS S I ;  9 PS Motion Blur IntensityS NumberS S AD ?I;  , PS AspectRatioModeS enumS S I ;  4 PS AspectWidthS doubleS NumberS D t@;  5 PS AspectHeightS doubleS NumberS D i@<  9 PS PixelAspectRatioS doubleS NumberS D ?R<  / PS FilmOffsetXS NumberS S AD <  / PS FilmOffsetYS NumberS S AD <  2 PS FilmWidthS doubleS NumberS D&1?=  3 PS + FilmHeightS doubleS NumberS D/$?V=  8 PS FilmAspectRatioS doubleS NumberS DUUUUUU?=  9 PS FilmSqueezeRatioS doubleS NumberS D ?=  , PS FilmFormatIndexS enumS S I >  , PS PreScaleS NumberS S AD ?Q>  2 PS FilmTranslateXS NumberS S AD >  2 PS FilmTranslateYS NumberS S AD >  2 PS FilmRollPivotXS NumberS S AD ?  2 PS FilmRollPivotYS NumberS S AD P?  1 PS FilmRollValueS NumberS S AD ?  * PS FilmRollOrderS enumS S I ?  ) PS ApertureModeS enumS S I ?  $ PS GateFitS enumS S I 3@  4 PS FieldOfViewS FieldOfViewS S AD p9@w@  6 PS FieldOfViewXS FieldOfViewXS S AD D@@  6 PS FieldOfViewYS FieldOfViewYS S AD D@@  / PS FocalLengthS NumberS S AD&VrA@/A  ) PS CameraFormatS enumS S I gA  * PS UseFrameColorS boolS S I A  F PS + FrameColorS ColorRGBS ColorS D333333?D333333?D333333?A  % PS ShowNameS boolS S I )B  - PS ShowInfoOnMovingS boolS S I \B  % PS ShowGridS boolS S I B  . PS ShowOpticalCenterS boolS S I B  ' PS + ShowAzimutS boolS S I C  ) PS ShowTimeCodeS boolS S I 8C  & PS ShowAudioS boolS S I C  G PS + AudioColorS Vector3DS VectorS D D ?D C  2 PS NearPlaneS doubleS NumberS D $@ D  1 PS FarPlaneS doubleS NumberS D @@KD  1 PS AutoComputeClipPanesS boolS S I D  / PS ViewCameraToLookAtS boolS S I D  4 PS ViewFrustumNearFarPlaneS boolS S I E  5 PS ViewFrustumBackPlaneModeS enumS S I PE  5 PS BackPlaneDistanceS NumberS S AD @@E  2 PS BackPlaneDistanceModeS enumS S I E  6 PS ViewFrustumFrontPlaneModeS enumS S I F  6 PS FrontPlaneDistanceS NumberS S AD $@YF  3 PS FrontPlaneDistanceModeS enumS S I F  % PS LockModeS boolS S I F  3 PS LockInterestNavigationS boolS S I G  . PS BackPlateFitImageS boolS S I AG  * PS BackPlateCropS boolS S I {G  , PS BackPlateCenterS boolS S I G  / PS BackPlateKeepRatioS boolS S I H  @ PS BackgroundAlphaTresholdS doubleS NumberS D ?>H  * PS ShowBackplateS boolS S I H  4 PS BackPlaneOffsetXS NumberS S AD H  4 PS BackPlaneOffsetYS NumberS S AD I  5 PS BackPlaneRotationS NumberS S AD FI  3 PS BackPlaneScaleXS NumberS S AD ?I  3 PS BackPlaneScaleYS NumberS S AD ?I  , PS Background TextureS objectS S I  / PS FrontPlateFitImageS boolS S I 7J  + PS FrontPlateCropS boolS S I rJ  - PS FrontPlateCenterS boolS S I J  0 PS FrontPlateKeepRatioS boolS S I J  ; PS Foreground OpacityS doubleS NumberS D ?2K  + PS ShowFrontplateS boolS S I uK  5 PS FrontPlaneOffsetXS NumberS S AD K  5 PS FrontPlaneOffsetYS NumberS S AD K  6 PS FrontPlaneRotationS NumberS S AD >L  4 PS FrontPlaneScaleXS NumberS S AD ?L  4 PS FrontPlaneScaleYS NumberS S AD ?L  , PS Foreground TextureS objectS S L  , PS DisplaySafeAreaS boolS S I 6M  4 PS DisplaySafeAreaOnRenderS boolS S I uM  1 PS SafeAreaDisplayStyleS enumS S I M  < PS SafeAreaAspectRatioS doubleS NumberS DFUUUUU?M  / PS Use2DMagnifierZoomS boolS S I ?N  5 PS 2D Magnifier ZoomS NumberS S AD Y@N  2 PS 2D Magnifier XS NumberS S AD I@N  2 PS 2D Magnifier YS NumberS S AD I@N  1 PS CameraProjectionTypeS enumS S I >O  2 PS OrthoZoomS doubleS NumberS D ?|O  0 PS UseRealTimeDOFAndAAS boolS S I O  , PS UseDepthOfFieldS boolS S I O  ( PS FocusSourceS enumS S I -P  3 PS + FocusAngleS doubleS NumberS D @qP  6 PS FocusDistanceS doubleS NumberS D i@P  , PS UseAntialiasingS boolS S I P  > PS AntialiasingIntensityS doubleS NumberS D9}?4Q  / PS AntialiasingMethodS enumS S I tQ  2 PS UseAccumulationBufferS boolS S I Q  5 PS FrameSamplingCountS intS IntegerS I Q  . PS FrameSamplingTypeS enumS S I FT   +ObjectTypeS Implementation[R   CountI 9T   PropertyTemplateS FbxImplementation,T Properties70R  9 PS ShaderLanguageS KStringS S S MentalRaySL1S  5 PS ShaderLanguageVersionS KStringS S S qS  2 PS RenderAPIS KStringS S S MentalRayS  0 PS RenderAPIVersionS KStringS S S S  / PS RootBindingNameS KStringS S S T  % PS ConstantsS CompoundS S V   +ObjectTypeS BindingTableT   CountI V   PropertyTemplateS FbxBindingTableV Properties70U  * PS + TargetNameS KStringS S S ?U  * PS + TargetTypeS KStringS S S U  6 PS CodeAbsoluteURLS KStringS XRefUrlS S U  6 PS CodeRelativeURLS KStringS XRefUrlS S V  - PS CodeTAGS KStringS S S shaderFV  6 PS DescAbsoluteURLS KStringS XRefUrlS S V  6 PS DescRelativeURLS KStringS XRefUrlS S V  - PS DescTAGS KStringS S S shader W   +ObjectTypeS AnimationCurveNode1W   CountI W   PropertyTemplateS FbxAnimCurveNodeW Properties70W   PS dS CompoundS S X   +ObjectTypeS AnimationCurveX   CountI + \  + +ObjectTypeS VideoTX   CountI \  PropertyTemplateS FbxVideo\ Properties70X  * PS ImageSequenceS boolS S I Y  6 PS ImageSequenceOffsetS intS IntegerS I SY  2 PS FrameRateS doubleS NumberS D Y  , PS LastFrameS intS IntegerS I Y  ( PS WidthS intS IntegerS I Y  ) PS HeightS intS IntegerS I 3Z  + PS PathS KStringS XRefUrlS S nZ  - PS + StartFrameS intS IntegerS I Z  , PS StopFrameS intS IntegerS I Z  2 PS PlaySpeedS doubleS NumberS D "[  , PS OffsetS KTimeS TimeS L Z[  * PS InterlaceModeS enumS S I [  ( PS FreeRunningS boolS S I [  ! PS LoopS boolS S I [  ' PS + AccessModeS enumS S I  Objects8f  ! GeometryL* S + GeometryS MeshT]  Verticesd +  ~@ +@  ~@ + @ ~@ +@ @ ~@ + @ ~ +@ @ ~ +  ~ +@  ~]  m PolygonVertexIndexi `                 /^  = Edgesi 0   +      P^   GeometryVersionI| xa   LayerElementNormalI ^   VersionIe ^   NameS ^   MappingInformationTypeS ByPolygonVertex +_  ReferenceInformationTypeS Directka  M NormalsdH @ ? ? ? ? ? ? ? ? ? ? ? ? c   LayerElementUVI a   VersionIe a  NameS map1b   MappingInformationTypeS ByPolygonVertex9b   ReferenceInformationTypeS IndexToDirect5c  UVd ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c  m UVIndexi `                +   d   LayerElementMaterialI d   VersionIe d   NameS Gd  MappingInformationTypeS AllSame~d   ReferenceInformationTypeS IndexToDirectd   Materialsi  +f   LayerI d   VersionId Le LayerElement#e   TypeS LayerElementNormal?e   +TypedIndexI e LayerElemente   TypeS LayerElementMateriale   +TypedIndexI f LayerElemente   TypeS LayerElementUVf   +TypedIndexI   ! GeometryLҍ* S + GeometryS Mesh1  \ VerticesdTW  O xly?j[(~>B(ZQ[>&SKjR[rO" DpYB"=s朸$|u3{랙|G1=?U}Ogɂu9?v,qse >w56EiGS=qoL<͉5gA5qޫj>j{\\s3S{35|~MasNC56ԯү8q 5Sse&39/ySΣCk;INڽYs3|~xYޢzW-*qiOFj?DAW'񸦌C<2_ ̯G~oV`Pdu~/{URoNmn5wψ~ռeW8-q]G7R8nJ^zJBc$ĢԟuE]~ z5Ы : Jp*>w(7jޓ=xЫ^[sՃc\UsոġWT_wULz%8* (Nl~ߚC.OC=J *sY^_5^QWzEq^=Ps z5+3#39/+>77סo7_Hh>:7]Sjn&B~iRiT͘1 TqN;5ynߞ9grE}ܟp#7#Ljy`u?nwi_7p^;=1ƈy+u#L/j_8xMur \sus]SjNy(Gؾ>(y?[zwJSknOʩu}JQ8q忟 +5dڷ.W3qwE=ꪓ+vo3~uUSO; uE8Ud}Od;Aճ+M32j|YUj nu{JwsV9yA]ǁR-z7yJ1sW*vza~5_]Jp̯'OItOH ++_eT/\'_x:s̯2/#J]1dc~E1_e?__5Ur]̯(_ ̯(Θ_M̯?WG̯__ݑ+1:>Whյ=䨫1`~E+z?Cd1qe">>W"_xe<=♸Q?)e/GYQC0P֏E]%;vLQgU=7~&{\gWmCjnہI\xu9noQWyG]DUagS_@yΛ_ uGSN}&xƠf7 +77C*NQ%g ޼Ğҳ}G^uՃx5ʾE]%?x6gjS{U8x+q| #σ _+'NA]oSC]<>xU϶\שo~~v_j|yt"΂oܾ9/@u>.zlӢR{{J}zj~ƞ|$ps5ogHymvAطKH}ҥhz }\F}?;Ψ޹O T\W֑qz81y>qv~I{5Bjos'qnSs_Ạ~~ռy q)q[帵SlqFcx<oM`(Ez7+q#:G]%I}kԾ,⿓lڇǪ{?|[FOܠ::Eg [UC8K~uU?֒f >]Өzn6mg>c_5oCmC ,ǯ?! /uJROځ%ﳥr4Eq~pug+qj|[4qJws_ }s.WK~ߘճ麸#h\/6ɵb`q* s3}'6`qOWϺ=__5+_#W_QpJ_QqJIx&];y+9_OEuW/ uL%՝=W+_8+?_ͤCdq_-DGܿ('pJpܿuGSz#+Bf__a@yǓus⟎ BcI_TYy8q^q?_]|nGe~9jy%.do5ANּ)m}_5w/ġ9q-q s rۏ& }h*y~ԙs-^1땼NߪveķQ[_"~!;x3qA|y'k!qdfPW\WVէ-vMuU?ѯ~RW@j8h7L:9~-*E^j; 5w[<-DcQWCS8>$p>op}Aq}2>vp=i7oq[ay^qC4f?q=yeZ} kf5}u~}}+/5Skt]oߞ9UvZ.Sp~; ۅ~;ۅ~;Yyv򗯋ps~[+Iq퓉o*v<oq>/iY:>~'x}io:3ep>\$4Np]J(ۉ~o'>ot]ogWm۳~"5v5v~K5v3os~;_>9v7so:vє^,i~9~z/+xM{V~n$O4Vg6Vqh^&;\!aw^NP_ox3#gόf_KMo8p! o{u7uQMy(vs+uno_5orCmC ^ǧs-"9/yy{cko~_8ݡNvHTnJ1jĝǢoK-*qۢd+CE< xG62_qh4OGzH'./GܣuU͛b'z~]3q/8Oq0z<~w WsJڎA][>X3RO *qw";7Azndu7~Pp|?Hܶ 1|?Q_T7~P3qHO|?Hߣ|?HnNF|?( N'{ A9$'c3uk~gWRRj)~kg7|?(t RХ81_lR`(y?[p|?Hu~IT{|?`|?X~Piހ~a%iAO|?HD A]y4|?ϵ~ q|?(p|?(R{|?(u|?H~~~s~`_~x/bڭrA~s3LO?X@gc=Wz_gKT|w2X@EDD~ 3zzXp[']7/v _c=qg dD=c=qg Y'xz3 q7 ggX\z 3}z#3dKaz{3[3P`=Ń㖚i;uߏğ*xL'؛^y~6up_^N'n!ՙ4RiɟWwcb<~I/U.Yd`ȣ57_N<킻2_϶'! +^s‚YgmӢ_5~ġ%[C8<^ܾ0%/1't11>9 y$x\' nn8崤WjPW=ھC]%?Ϳ^yW;%;-2 I_f%4,ꪃwe=xCY?A]Y ++ٕFYof?UsAPcCjl!WĹy[0/w>8UkQW}J7GUC]<5M/zX5WcıJq!:W/X%t hb hbի?XE딨_3+?X5G_M9_e>ߝ5'3gWSkW25+3XEWk"fWBWBWRgW/믨NO#ͯT{;X%XUX%+7`^Cd!_-DJzҮnP'J7'^X/LchzQca >E: X/* /.qj^!Uw̱^֋uqX/Jʭy}%wB?H~b'gOEukı^5lLchPs8`Ga( E.a(E.ah.s^49֋漣NjVN,8֋_X/:qzQaEg% E_N^TE_#~!xb(CzQczQ{/֋8zQQX/JEE`;zzQX/*E֋zޤ\W?֋f?ѯ>֋R^T/ztX/+9KmE)/X/*E)X/*EgzRoX/Ju,x +Yz~a}S&u豢`ىE uJoi ?͓м!3ѯynCS3l/C3'Bͼ'aX߬Kl~Ox;UҌ>RqOJCqO=USx3m5Ŏd|Cnu{SL='Cl nuf78 os;3 u{pX?9?Ss4%_nIyTx\(iWxX7dg㓸Q g͍2R7V7ٱ~rڇи1ޣn3bz>7_u{WL/jV#nuf}i>}r R0#"5w}r?V*8(^XQm'wo}>ooo(vzv/'C<|搇l|dFbC ɐovַz}{XNq+/%c};]i^~b};٢_u{oz8)XNͱBB_9X.a};\'-8ַN+':so*6qoc};]_O}$"XNEEs/ַ8?~G~o's{o'>ot]ogWm۩_q9ַSc}[X^ͱbc};/o\O~gw~-W}{Y[78{n80 Cw{ţʹNk7IA+>zGotӉ[A]%n_&ve<-♸[Q? dt/|%m:ƃzHoq]Eܠ9p Cn?k;ԯүqysRCDjQWq)9^0hu>zbQWdw]?uE_I|R8tGpǡu m+ ;؏؏Z؏#qs_T/^a?b?d H׹=8~u؏C q&؏C +qIy~7Ws!8s{؏dͱc?^ q؏C8'<9PG|~W_זa?%ǡ8c?7ۏ`?q(؏]7y~q~3i~c?#)؏#{U؏#~9gq^KGq//~Ǿǡzu|a?b?84~qƾ؏#9,vG3uG?㐟_|]ǡ~a?_؏Cq~w8r)qF^؏Cy~򋯋89F *qNM8Bp՘%u??~swo7{#v=kuPؾ{d ͳ%Ny;rj̢(Nlǯi{YQ<_Yo}{sp92@>qSuoNZo@牻i+<@|1O;~ޕ|~v*qěu O<^,۠#Wg12Oܢ:%";7@?.$?qěޘ,vZUώ?gWo~9ġ!n5oG-8<,l9/uMrR5NY,&ٟ뾹~c GAaIP*qAz\/<.=!͉y)8>;8z 8AW?H +gOSc q|0c qUs׭9ulfD?HJq9R0w[\' < +)?OyA3?HyJNO$=NAPycαP4oA_y.dE<!ىc C>=Bi<`ZY??He>cgb$?SRް0K/8`?Hl)?(9/?()?Q +%Pp:jS ++|nZ͖_?I]w8/c=pqjo*t8v;ǯMq8f0ՙCW{.q?}cTq"_MFuo?>7s{T'7;B͆yY?Y{?~rXxg5Nuknun_ԯ-rCÝ9 VsS=5w{ksb&伴'J݈#r^o7y@pm Ǟʟi~Uh}JQ8UN?q_J|E|xz3q?Cƿ]<wÇ8x {zhƏ.gz>=Qlu~_:W 5w8}xW&'ǯG]o>>%^E]P'uEv֒Ӡ78 ;~,csc1weE*;;K4ߙꅯ4ߙt{=޿ɺ^#;B|w&]~~goޔz2. +\EgMv[y,w9Gso.w&]gqǒd'ܸhQO\_W{; _ߡqxbNެ +j?d?tۙO̩yz5o;-'Uܯ8rks,\g܏yc9yyغ(vJܱ_W_ӟA%"~ǝe#xsIܪx3񰖌@ 2_d~-KzhBmg4 *nQW5o95+Wm'e?q[ݾf}qsME^jy1c-?HA]%\,>$.s,ũM/em3L|38g:sgo}[B| t3"gq>C >Mvp>`xC@|Wx=Eߚ~I3tjLq>C'88gx&> d3<8!~vp>CPs@q b^(nx77%8A[p>C X G@Bjq> g3W=g;8A /$?8>|?g98A3y×f$8A38 "83||8A38 p>qzs2 p@3 d3z q>@~~q> 3( V+r|3gn(/8Ag<|o/gx!=g~s|p> g<ū={;bvQo.ߙ#ῒiU׾vHl(N׷{?7=%Gy?dk Kv9~f/NqP; }nkqg1+C;a5w~J}1]0 ؉n9~ּLy8;!5o8ğ=%ƣ-qku§u{'ǹu쿿/% ԍ<佶\Q')Nl'ޒefQg''VҾC]%n?uxPګW'`Lzdp\_W윰@UI.ΓF|]'C~~vp ySdr=Γ<od(8OF[p ]y2GWd(8OFp'Cudy2A:Tq -Γ<s'#y2<_'Cz[:>=Γy2>sWDq </'C8OF7 pL? d<8OFԛ+ɈtΓdΓdԯo'8Pp'5y24y2b<3ΓP^p'Cyy29p dNp +£?n1EJ#ݚ_7J fq)Nd%u|Ӹ3[J݈4N?'o:GGsWP݇}.p%+Ԗ95b|͛#Ɠ<~r^]c'\(u#7󳟩_51bWo99 Vooqs]st%"i1Yی<\nP'5o>uW:EpF$'qeߡʟ+-*Go?Z:>[πx&T Od x2ui\U;UǼ!VgSxUϮ\l3殓e7g84[ *!58r;Uj߷qJ#R"x%4WeU}7qoy& +򧏤˄CsNsB>؃꥛MnE<ݳh~;߽9οʺ>_ ;?+ӷϳ)>}ooM'}9Ѣ׭y{hn57ԯrpЫ0/e~9Ĺ(ey3%/OdX7y">kn52qړ=+u8+ *foD㓸QybyW[[+~սo@~̷z-ꪓ~_ x@]%>qyn]n?k;٢_5~01Ʒ|"5oqݢzJBc3HC]kR"*qw?9>'lvsT27Wvqat_޷1W5)>>?+Rn> tMoyMi'n {*ܖWnx3w*p.q{޺|V)v#|~ԯrPI&M9nq-qc:y?Cɛ9MerޛNs/-~}TʾC]%( ꊸ?3AסxRp'Eƿ_& +ȗ7~pxOCN.ǡ9iޘ_Nٕ63g~ܔ~5C9qy|kg~u99/yyx#5ROꊮԟux<޵ zz//_:hTc=}/⎜!nGۧO|la(l-9o ؑ ~s=4o5Θ89x4eqin%I;и7?ŃyLꞇ2='}(;[{6nou[)?SjSr[o j7qù|IC^R?;K{ W9탣us ꤶ^ubfm,IC]$;UQcQWAw K">2LyT8O +R7w;v.}o&qvuiU>QW5lG3 Uf?Sj;#5w'87x4Ԯ o8ǹYO8;"Ws@ΣEknQWɾCԼA]jcє^#'^5'}G暫H8O^˘ ?ن ^syCy<sq@~~0_]q7[W18WW"Կfǭyo9ߪ/ /9*uՃ8zeߡ7?+w?yM<^t|*'{ߥ~rql~2a=.!9MPWqzo lGs.ו~_RW{_v'^W1~9#9S9/zqǸ!'w Dpm_#r^G:f#w`<?lo9ǽzu9yϿ<혻V5v7>se4"_hѓ^:a u^⪧x G''>==W]˝_Hcb\?I_~ԯү8<ܙ.827sqCS؟`ssخB9/yyoMf;ڜ$뤹|wHt{PW[O.uڷPk{eW2_Ju2Y4 !#]m:hYop{vlz.׍PL/C |EGs94 +s=׃A]{9-*0EC{EΣAk;u[U*x\rbN豢}` ++#iv%nkH7~&]f4ohv؁߸/?!]g 7vMyzøqsź_w!4pl>%͐3&ܭuS?Wt/U +C}Ej_o5~9yI` *}PA]%zbPW*A]QqbF<9v`Wf㤎;~cnwN& +.'t+N\V|n{MzwI} Oÿ_q ڔ_b&J0qЫpywrox3dG[,ܿy+_6]\7|]Ys[L~!5%q78׼YlХ0#%p%Sڎ.=b'zڎ/~~ܕ~9ġq[l zĹ|]CpJ~4xUqO +|b?^c_ЫKI5Q蕝1*aھ sN>.2[l|o-'GzcW^ *n^\:_Uyjk~d?SR\\zEjn\‸Ū=νĹfxA^j4}Hqtcl?~Üw|mN,uo4C] ¾C]Wxl Oܪ:W'qwt<'nPW4Wb_ϟuUy46~È ޚ-*5lGs._ ?Sj;8> qC]~Ǩ|_qv ]ቜ< RO *aP'J~izooӧ;~<4c M}nQv;z/&s%O ^Csn}'r _CwECq(OoƉ|_Z;Ϯݔ'o|xP]ž/ +^4 G}\7Ϻ}`3_ߋ!"n/ߓ֮tG5rRsDKiB7,)|]nQ'5G:iF'^ucPo>*FONAAW'qO'M2_J}U7lC !x_#zsu};Qճ+׍3_5_r|ş8X=ニ>Z99q99/Rs ^1+W/?ux;'. V}*v_c{>4?I~>mO^.:ϗ.&-?{|~1>;(t_;R>N3퀏)Q>%*~xͽ#܉?wH|Ы0 +^b?lRc|b#5on']7>n o䥚{d;E=r ?UO_q+q[/[~瀼@v>"yc oup-vgWg?SjnK}M;\|߇۟e?SjJ*q+ *qZmzc^8n onŎ Zmnuf^Ӣ_5k~8Wq;.#/5xQ9y)ߘuo;Hp32+ޡz 󐲏J*ZC\Nףn>gv'VrWna?'Yǹ~WVA]~pqN%q_~s_57/!Û9j'jOqWuݽk߁%gr.!r~"Y9\5Yt]s U{K4o Vl'{a{ a8|QN=O=clnf#;GlޖWWy}3J6k8Dĭ 5o+q^w5s(/ή.{Jw~xkr n^4jT{Ju>ꊸ?o.m_qhĉx3q<'N U' EuUs<''$?q<'x3M[~O<'zsⲎe?SR<(](Ǘ)qszu_9 +ωwg<'Nw?%%+;qzi;'ɻ%o Zg|7-o 'gv#g.I^P$;ԃCBaT~^>nHWH#zuVYޞ+Y{3rWvֱà 2w Ŏmn?Sq(~~t?ۻߞJЎ#i6 zΣy>7;zԚǿ 5`jo:蕚3׭+׵yl=!%ڗ~9!7G8Xĭawor009~p+</t).(f :q'b폵^9ޡzП;UAcPWĕuWo͘Lπx&'^$呯\K0~xzH\KQ?/[UjNvt=r]=>Ug~Ṗb|q[i9w?k)x#Ź}_wo#ȏץ9~FwJ+?ɕ +!x6ҫx8WL zu{f@1.qܷ?ϫ‹Wq?D<h`?~8tǝ!|UwU~ۇ x3[)!.7wXQ?a(ұ|v;E}bu;+_ו6͒g?JqS78<쐗7s^_[ՐG9?G]juv.σC]5ʾC]%(,*PE]#۠ct|*9h?|Y+0~?[zgK^ 'LE_"3WٕFI($UoQ˕8č^皷/8;Es^ϥ>UÎzRԟuD/R)x^+TO֫.Wz\sW]+Z\sW̵^1z\sW̵^1zJkb+Zkb+ZkrW̵^1z\U+b+Zkb+Zkb+Zkb˕^u+ZkbyV_}_ɟCAZ\sW̵^u+ZkrW̵^1z\sW̵^1z\U+b+Zkb+Zkb˕^1z\sW]+Zkb+Zkb+Zkb֫.WzJkb+ZڽX>sW]+Z\sW̵^u+Zkb+Zkb˕^1z\sW̵^1z\sW̵^1zJkb֫.Wz\sW̵^1z\sW̵^1z\sW̵^1z\U+rW̵^1z\sWv~+Z\sW̵^u+ZkrW̵^1z\sW̵^1z\U+b+Zkb+Zkb˕^1z\sW]+Zkb+Zkb+Zkb֫.WzJkb+Zk{W̵^u+ZkrW̵^1zJkb+Zkb֫.Wz\sW̵^1z\sW̵^1z\U+b+Z\sW̵^1z\sW̵^1z\sW̵^1z\sW]˕^1z\sW̵^5ŵ^1zJkb˕^1z\U+b+Zkb+Z\sW̵^1z\sW̵^1z\sW]+ZkrW̵^1z\sW̵^1z\sW̵^1z\sW̵^uҫ.Wz\sW̵^1z$Z֫.Wz\sW]+Z\sW̵^1z\sW̵^1zJkb+Zkb+ZkrW̵^1z\U+b+Zkb+Zkb+Zkb˕^u+Zkb+tZkrW̵^1zJkb˕^1z\sW̵^1z\sW]+Zkb+Zkb֫.Wz\sW̵^u+Zkb+Zkb+Zkb+Z\U+b+ZkA롵^1zJkb˕^1z\U+b+Zkb+Z\sW̵^1z\sW̵^1z\sW]+ZkrW̵^1z\sW̵^1z\sW̵^1z\sW̵^uҫ.Wz\sW̵^1z~?/AsW]+Z\sW̵^u+Zkb+Zkb˕^1z\sW̵^1z\sW̵^1zJkb֫.Wz\sW̵^1z\sW̵^1z\sW̵^1z\U+rW̵^1z\sWq W̵^u+ZkrW̵^1zJkb+Zkb֫.Wz\sW̵^1z\sW̵^1z\U+b+Z\sW̵^1z\sW̵^1z\sW̵^1z\sW]˕^1z\sW̵^V^1zJkb˕^1z\U+b+Zkb+Z\sW̵^1z\sW̵^1z\sW]+ZkrW̵^1z\sW̵^1z\sW̵^1z\sW̵^uҫ.Wz\sW̵^1zyz\U+b֫.Wz\sW]+Zkb+ZkrW̵^1z\sW̵^1z\sW̵^u+Zkb˕^1z\sW̵^1z\sW̵^1z\sW̵^1zJ\sW̵^1z\|/֫.Wz\sW]+Z\sW̵^1z\sW̵^1zJkb+Zkb+ZkrW̵^1z\U+b+Zkb+Zkb+Zkb˕^u+[IQfDvD\XҊ4,! Q\@@ht%J +-$1DIp4!hrDNӟ:ϝ֭:ު~W+r*w˓+rW+rW+rW+r\}E"W_F."W_W+r\}E"W_\|E"W_F."W_W+r\}E"W_W+rW#_W+rUƞC"W_\|E"W_\|E"W_\|E"W_W+rj+r\}E"W_W+rW+rj+r\}E"W_W+r\}E"W_\|5r\}E"W_u;"W_\|E"W_\|E"W_\|E"W_W+rj+r\}E"W_W+rW+rj+r\}E"W_W+r\}E"W_\|5r\}E"W_-ɟ'!Ͽ"W_\|E"W_\|E"W_\|E"W_W+rj+r\}E"W_W+rW+rj+r\}E"W_W+r\}E"W_\|5r\}E"W_^`ϟ꫑W꫑W꫑W+r\}E"W_\|E"W_W+r\}E\}E"W_\|E"W_W+r\}E"W_W꫑F."W_WCz?H\}E\}E\}E"W_W+rW+r\}E"W_W꫑W+rW+r\}E"W_W+r\}Ej+r\}E +_\y\}5r\}5r\}5r\}E"W_W꫑W+r\}E"W_W#_W꫑W+r\}E"W_W+r\}5rW+r\}ծ:/_F."W_F."W_F."W_W+r\}5r\}E"W_W+ry%5r\}E\}E"W_W+r\}E"W_W#_\|E"W_ȧjyjS|E_ |W⫁OjS|y^jS|_ \}5)_ |>W+#?yM~^W⫁O8S|E>WC?S|s$+/?S|5⫁OjS|5)_W+djh¿M꫑W꫑W꫑WzE"W_\}5r\}E"W_\}E"W_\|E"W_W+r_\W+r\}E"W_\|5r\W}'@W꫑W꫑W꫑W+r\}E"W_\|E"W_W+r\}E\}E"W_\|E"W_W+r\}E"W_W꫑F."W_W䃮KmCs<}5)"W_ |>W꫁O\}5)b{}?8)_}?8)_>W?y⫡_ |>W⫁O\}5)_}?H_ |>WG|ؿdy_ jS|5)uя\}5Ө8<}?8⫁v;/_F."W_F."W_F."W_\}EW+rW+r"W_W+r\}5r\}EW#_W+r"W__W+r_W#__W'+rW+rW+rW+r\}E"W_F."W_W+r\}E"W_\|E"W_F."W_W+r\}E"W_W+rW#_W+rU W#_W#_W#_W+r\}E\}E"W_W+r\}5r\}E\}E"W_W+r\}E"W_W#_\|E"W_WqEW#_W#_W#_W+r\}E\}E"W_W+r\}5r\}E\}E"W_W+r\}E"W_W#_\|E"W_Wj+rj+rj+r\}E"W_W#_W+r\}E"W_F."W_W#_W+r\}E"W_W+rj⫑W+r*~|E\}E\}E\}E"W_W+rW+r\}E"W_W꫑W+rW+r\}E"W_W+r\}Ej+r\}E +qj+rj+rj+r\}E"W_W#_W+r\}E"W_F."W_W#_W+r\}E"W_W+rj⫑W+r*nr+j+rj+rj+r\}E"W_W#_W+r\}E"W_F."W_W#_W+r\}E"W_W+rj⫑W+r*lkj+rj+rj+r\}E"W_W#_W+r\}E"W_F."W_W#_W+r\}E"W_W+rj⫑W+r*nțj+rj+rj+r\}E"W_W#_W+r\}E"W_F."W_W#_W+r\}E"W_W+rj⫑W+r*|cW#_W#_W#_W+r\}E\}E"W_W+r\}5r\}E\}E"W_W+r\}E"W_W#_\|E"W_WqǼ|E\}E\}E\}E"W_W+rW+r\}E"W_W꫑W+rW+r\}E"W_W+r\}Ej+r\}E>q /_F."W_F."W_F."W_W+r\}5r\}E"W_W+rj+r\}5r\}E"W_W+r\}E"W_F.\}E"W_Yp^"W_\|E"W_\|E"W_\|E"W_W+rj+r\}E"W_W+rW+rj+r\}E"W_W+r\}E"W_\|5r\}E"W_ۮy\}5r\}5r\}5r\}E"W_W꫑W+r\}E"W_W#_W꫑W+r\}E"W_W+r\}5rW+r|w4O8I|3|ogLGyxL{?I>Mla'*}Pm'c_>{ ޞxG}%oOWouzyR+>`՚|2L<َ_sKgyfZ|aua%Lr y^)i\n5! n%Ĺ9y)ywUKG-sk9o;Z<8\'8^os;iPWPWw2ux2~o$^K<6WoԾF^I[',cv֡ƛ#}5Ra觑zu#i78ӼJ?U +CZ7>q.yHs@^2%~B]q'ytg yOJ8/Wgg:ޯӓ{e㯜cyf=6_o{ꂼ]Rm*yU|qzl}6͞w.OzF=Չ~Je^"9͹0\7HL*i~!i\nqs?]!l߬ܿ{PlO{9\\'axKF;񅙧8/gleWg3_?|U_7R?񳻺.gOꁇu>_nW\.8/;U_~5ϝvM[{)wau/y}nۋ}}S yGJm|U0β}=3ͫ<4?^U.ǭA19 59/bjy:y}{:):_ǫ`u5@]%x*U╌|k#>!/ĻoK}^I|yiYIpn_$6(D0\7biO=3ͫyy^qHcc95Vu}ƯC{-?خ}Oy.6u_% žߜԞ{,{8㺧^^*DϯK=uoڇ^`|Ǧ|]fS?t|#ݯD>>'c|ů|g{_rJ^7|k>]tj^ݲU=S}:_58{ jX̷["!"n%Usɻq^Jyi_ZOCw9u^z܅Wxz'VawG3$-x'^&TȗqUەOPJ|}/[?_?=nzxszG9 Ryi^)p__Jc{ev4o͟\!/%oyiПN8`U+;޾K􏚯[ayC{K)OO~7Un7kwZϱmW+8_b'»γ?/oV/j^]gw|W9Of~w+s]Κg ꅲ}=\8KݛǙU<4^7 qhC:Ĺay)ys]K<:_c<췲R\'m= ux-12'd x5/>5x}'.*>+K:gzP}Oশ^ jYC7ߗV#Ύߝo|{^Dz}(1NjuRuvW0_U>&*xCG]%^x"ce*8ϷB]%/:5>|<;3>5xJ緽◶C|=tOewZG9 R04v<8!ni~oJnǻr+r^Y9q>~z{uvd_z :iU>Kw1_??U-~W{XwVj.>|6+7OMn{*Q'9g<78=/%og?k3Jμ>w]F?t>vVWVq7T\_m1NLJqy~W8< qXϸ}ym>"/e8;FKyl?Oѩ91,tN꺎r/ FG]%a<2ue|[7 x&Om|Z}W?mN['5j?ԃ-]tϮnB]};*y=SI=,ۇai^%y5CɻNfDlsBKެ7A+UFqќvC!?ud_ru^jI|'=x|WbjyF{]oO}yp_cgc]_vxJ._SmzW_񷟽%1a3,r5%_>x5פynzC%oG[`%fgWOy!%qcpj5sٟ\!/ߐR!%yrek`?:<7_5>&T?*Oӏ?d5*v quψx&^-_#QW8_+>z>aYOIŤ^ʼd?Ran>ǙwyuC!qKbW~V5RQWWcɻ9~Ŝ Ox4ǓN_qUWn<寏O}w-o?eZzu'W0-ؾYr#xO}ov+^O?}[߿\'|gKެy^WX zu7a:W#_WOϦ8qp,ywqgW 7C"? N."/eZ<ؾfoo(ۇskIst'꤫}@]MGux'i1ăoek+g@<p-'ޞ}~U}~²~7a@9p݈q1Eyi^%y?PzZO}?n_ȫv7Sqݜ͵%v_*ۙVrn>p\ۇ~kc}y DIJV?|Ҭ4^'z/y\m稹k9_kqy4üjġCX`[8/ǹB^Jny>X5[jXB{ W uw|}@]MTPWe<-Ɠx;?Z0_OS{}xJ<۾uUQ}־*k5zai^e?üUgǵ}X¯z瀼 koyz?tn +uQN~U+:eax&sw竸ßt0_༞c|՝s~~l}OZ3NNxJa[z_]}\=9"w/nŝq 4}b)~zgW+ q(y;ġAҼOc[8{2ǹ[W-9/킻{_ ylĜ:7gjJ{US*F`wxg3? +$yȗW|~þljgzh~څ|k_o[~p4' ZǙUj7Cj5?od6qnB]~PWO*Uo?+kKhj_ϲx]O1grn_|~K?Ou"/[78gr=m}6']mzvwl\wm};tUn6^Uil?/`ɻ>5ng>ǙUjWDJ1ǡl'x!nq89;_r^^r\'ݯqB]7~רkcr+F]5-*x=WfjrSN qk?hk_ey&wdwvW'/՛5fDu|_ޚ}.6_ol&w}q1lb3.)9wwp~OWͻw~ y_ ׭ƙU/k^rVVq߹xrRjK<[k';5w;K͚C|i#5_>R?d<ﻕ?`}+m1ϧ'ZY!~o=jeŷx]u['m3?_?uiPWx>[<\81QWzqGuxj#% 7RsȬ'n?s7?bZY C>|ϩWrk.w3+Umykw..yp8m볞g^xr[_Ng8+K곌wre[u%OD\p,yc^%yՈC5959nghsE>롟J8]?8ӼJ YC7W~֨ԮB^B9;r^XxUcIJ{t:/W4Ǜ'?dj.ɿwdQ 於{LV\as„U; N";S{%gai^%>787r*瀼b͝9/85_y/`29}=`pv?^WDw{DWDssJ^5[M㾷KپY>R<?yE?;+Ҽ~[iK,_8KǙUjW8]ei9n\zs<s9|oysq9?}r?;̇Mu5Jux'PWe~ $:3 kEPW7vs_'cZl_?ux<yO_O'vgS0Wü:ġ9 Vw{mvq4^3BK>W'ue[C]%;jZ}O>o[|7/>4~߮rl?~}o|m櫰o~~"u{HUu5PW22 +uxo|FSx%l}+yW|e3_|~[7~PQWi7--ʮ\p,iqy:+.W{OC훕϶q.y}s+kԕ[V=i{Xg ^x>l}6D=Zˏ|ƱcqoOsʶ;Gw/O`?-k[0S_qc%?1ΒwsWɛկUwPCSrĹasX:ߓ"WDc=&B{-I>׋}+mPWKux#/%F]Y?Muj|%-xWcmߐC +u53'y{n觑zu;짹/3ͫa2ϫBJ!n%PWq.y**CǃO*o+8/}է]|[&wkxs>>Qryo#U>̓v?ўt{]{d|U?}׻s7ݍG~c1[Ϸ'ŃZf_c7Ǘ1;|݈qai^%oVǏ q@Jޮ"%8/vu?51޶͛]x\'uO8^A~PU⭌ݣF0Ծs$ެ!O<\pרI|gCc~O*]ר+LJ~s1β}?;żJ,? q(y\7! n%VX|~߯zs_9/ͤC@]~kU(狺JB<W:7g}|:yzzZd_Dkwau;1_Un 'mo͗>y~uh69e<냎,8~~~n3k{_D^nwzk^o_?|x;_כw$"C?-y<(_7b%.L*y{`W@Jq_ݼCܺüNLq{~ r^}>9~,B9 $g:ioKǫu=0JD5}ux-iPW225>$m!Ǎ}k?>_5xoylB=k~M_o/wRp݈qq1%yi^%o~"%q?csv-oޛ|F]5Oԕx+?y ]W}צK'*urig^y}M.܇~9su>y}N}V{6uo>Ss}2!hnΒW >j/+y8y;[?,͛oΒw~:\dnq:~0N̫y^q(y8 n%oOqw8ͥ9/5Xcc]kkZ<\'ws?>^Mc%3 ?ue|?O<1Ļ3'ZY!KsW|Y}}~k롟aV1kUɻJ9^[Iļ~y^s9 VüWCk%9/XueB]%S_$m7M_֋:/Iu۵V?O87~|}6w|Uom/u|_9E^{7v6}WL`\lm:nqi?f^9%~5|U񺯿lO<*/76}( CĹl87Kɜ +y,y|=类}nE-no/g{ZT[q&wou@K55{>/5ߏ^2MONmM/IRNyOj׭6of?TgWپR-Vr|^ŭeZk>^7\9EK<jyT3,#&ZPWw2|^1#ƟynT>^KK~}/|^~_|^vS_T[?~~yy{O|^jGj׭yyW/KyuCySz?~65/y~ZOy9KyRN7gxз}?y'ݸړ&>Ńq}χ~O[ix <̼'Ϸx~v+wuU?3ӝy=]gc ;&}ꖟe8w7xwꌋSl_x;Jonӝ78k̫ly8<~5! n? g>8rxUK\{Ewuc|{1}\'^ 9˼C5jqux+ +22>/>'ySWL[{$4W>!zPWe +`Ogxx@]<ޔiA=3ͫ9`jCkUw8;fs+s^5*||@{G]u\< j;߯L/-6Ĺf}>7Ծ=u ^}w~"Ń:2[%7yy}vO 1=÷۝K1|)'|}nYs(̓w%k|W%.>w~~KyWOy=K/]27|y?C5C^s<]rr??x8gaU'jq:OJ{'LDXψx&kd +~PW%V:Csk{|w?`-F9K=^Wm8Ӽx9<8\f \m9RfVKCJ=O*9N^|]W/ͽvixiw'ޟ.n"G c^~1qO|Nz +a^1[(]KCw9msL.(9>$;o+y;s%u9&|C?04}i>䅒sL,+|ŭEs8~]K L*ylW8:ǡ7kd9y)PW͙5U'*O@]Y?3}s_3sΟݕ8>]5qKo'|.xf] }>7]  `^Oyp_mdO_ܐǒs,!:ޮ8n7\'y~߿`-jql+ZSd-o|x?95>W,xx[|5W:>6zPR}3^z>s;\8~8ӼJ^ w{8Dĭ *BK^~ۯv]jU`ue.ӢY4r;Wj$8Y˝?RQn^D?ٶn!~-ޕ} 9/vIg{ҼGfn)y>O:[sKa?#c폜{_|onqc^%ߝ %o8Ԉ[9n\fy)ywSK<: +y/y\>=NJ^9Wt}Jwwv~Wwgxؗm} 9_uWMYoy\7o}uO7n)y;0p,y53a^A8t[پ[3- Ύ>9ξ~[s^*l_#=ߏ~"csNoG]M I<>ǃ3?he-Ɵxo|u'J"w[긫}kVoF]M⿌st[W~*Ojߠv~Ou{' L*y3̫?Pq+wkT-\Ys%FK<'ηE]Y?ܝ-Nld_qSI|[dwfH<2׏sϱtj8^K ^7p^+~Y>fO#x|E$s;Ǿ=i%wնy"ww8RIpn/!uJo3<-y7\8_<3ͫBJ-P!n%y/_>ǹuʼnnr\jy/:q|͡Nv%jq'xzǸs/|kԕOsgx&_!}o[#WKzӿ{/u˼āROp]~aWpW8]<ǡ_j}CoJ?_#/e?Ր +y,yX3Y$9͎?5~~ˍ,N.i_aiKrߩ/9]=j[8יx/u=jv~{ywfkvqq*_?k;or^۷Ys]nOJÿ6oݢ*jg<ۙooPW}}?nپb%8#UKy^P!^-8_^ yˊڜvu>:A]DSd<8y2y2$8/y2ws缄vdl}y2xv qxLzt'p}ϓy֮{u_7icw<[xu%dy2g;y29x݇|9`3Ń|[x>zn/x>5%q<ᬒ ~|& |kJ g|{xͩ`&N||&'nNgpJgp~gp|O-O<'c3< ._x>wg<8gqyx> gp g8t[پF]ٿOg8 ϔ| 3X|C<gxp}ἳ;\:༳͛qqٍ${Ru.8Pj8lB?/}^4Km⼳:쀧mﶉ4.<8;_ך7p㼳w>#yg8|uqyu__;8qJ6/w]6ۺwἳ[8lqygq^-8l y|pMV'8k7m8|yg?;ߘ8;qٍ~|q睧Ǯ{';?nם睟4;zyg_wήp9{c_?8\HeUݼק0a󃏔Oxp8?=`c=c~Jy:q%Sg~`\Ur-9uq~_8q~A68#? :A3uq8?hy<p~t0w8?hu38?J]?8?x}8?ƃv?q~'|q~'NO]qqlCG|~8$s+.8cy<q8~pI\y8q|}^qzE7v[k,lX_Ľ.`Cc\GKMoro:en=Oc%>v~r>%ȹKv]o64=ۼݽc=[ܰcۭ?^-/ߞשo]'.Pc|a}{/:vW]wo7ޭ ۍcϡowv]ow64/+_ya__+8`{Ϝ@7?\ro8c[nyv>-n%Y_oyc ;R_Nc^8|FͲ/jE]__^E^4 \Eu*~[/狋]Wr~[rJƱ_Ēc_裩=1!~Jy]%~Q/zqyEcE)pe{8cchs-N/jy~<yGWkuFc7WEϝ@_W%nqr[~e볞G|R{r+[اWv_W._euW.e\=`qrWƱW\=cq?3+͛y+_W9~b,+ _y?'4ӮH.Fd@B;tfViCH)US&PɎcLDjN4ʑ]e쐡PhE)i Hѝ{}g{-J? +/Wz g*󄼲/3mg_~D8 ?3\ y]}:oϙg{Şy/܏~&tg0y[Ş7yK:3g8 ™gXq>n KgYy3ky\ktƙg<`N'~3_ġƙgPgY3(n :mgmkp5<Αyy&ggAy<3P|˞y}ag y Wg<' / a?ogO|x2ϠH3 y^y!? +Np ?8Aur^kbc36k{~Ҝ1ټƓڞ5Npa_qE߬q?ujWmOP~Ej@g&oq?8KPB;A#]Z<'o?.{+}֡?h\ 'A?AO/k= œ-}4?Af ?_-9CP8AϷ?hIP--&W]/~_q?8~)υA#GWy ?۵O? z޾Uۣ+n5ޮ8Eo׹KkJ jJ~_]q+J~e8j'ZѯNYq*p+ѯlW/ ՞=y?)JJ8:p+˷>~%{+g+W>ѯ쾠_/+_WC~ѯ~kW:+Q#U|p*_ ggiz+:`}}w/K;)_+6_-{[|rA={>|܇/͍k|{j|;ٷCju\=ul~.|rM\>' +|S5>t^AܸƧO>ï~yP|_0$ndƍσb?fy Wj{y.|x39N_Y{=;7 <h_UϛW//ߵ>tuo|x>Xwɫ&k3g^w;||aygzs]Jp\gA G?K\lK^2q<|#\jC^ſ'=y%OO&o;t><h?KO}+éN4jR2_S_}]%Ç_ہS_ocGG}[[_S5N}O}{SK}ڞ:*񍅣b_p+zdO}uJ}8~8s7wug+?ѭ<+=W:G+W'b]+énxxN3Şm}eW''O}eQ_<|z+֡,W{TP_yQ_)﩯|tO,S_YPG |W|N} E}q8W3AW:+Q#U_>W'䕞c/J)_)WWG8|u^RWo{M+s3Wv.l:|T>Wq>ZqJ _|3=3M]]J}8|}_5_/NW|F|8Wg _Y _+_WWy]>|`Wf_~WW}ևl?ˁWJy_ka_OZ>t+;/Jy_W'|%Wo3|=|e _ <}Wv_+_2>Wg">_JqW:a_W>|e8|yB^+s䭰<˾.  0 PolygonVertexIndexit  # xCfm۶mm۶m۶m۶mMT=&iktL߿,3;ˁXv.aq\ʲc`Gq98Ɏr,7;ˡXvC .a~\}`{q9<+rV刬0ۅˑX#l.Gav\ʊm`[q9:+ɶr Vm嘬4ۄ˱Xcl.az\ʳuU`kq9>rV儬2[ˉXl.'ar\Nʪe`Kq99ɖr +V-唬6[˩XSl.a|\Ny5`sq9=krֈe2Y6lM \l4\l*.F 6m%˶ъMeh&map6ڲ񸜗cp6ڳu`cp FrA։B3˶хeʆmtcp6l=\l0.F/6m7˶ч emslY_\.@mc˶1ezm eq6nlYW\ .Hmc˶1ue:r6emgmq>mLdq!Zr#6匬1k{mc*k˶15mxq6fl3Y\Y1.lmck˶15eۘmgp6l Y\ڸlY-\%&.RVmc˶UeXmdUp6VʸlY%\ְlkY\u<.zV ,.FVmc+fV +-$.f[Y \m8.vV mc+˶e +mfp6l{Y\},?.~m ˋ˶q ˍ˶qe8rme9p1²^8βm`Yqy:;ɲmbqy&;2maq6β lXz\,.cXZ\, .%m2Kˋ,./aXr\,. m&K˶q%e۸ma q6lX|\,.m!˶exbm0lXh\,.b_XH\>̾|}cq(΂vŽemfp6lY \\ ͟eeeeee+,8 m#m#$Pg\'\0G\\p{\;\[\"op>eۈeۈeۈeۈ?eۈ?mOq6bOp6bq6bp6q6p6q6p6wq6wp6q6p67q67p6q6p6RWq6RWp6Rq&~K6".FZ.F:<.Fz.F,.FFvm#;˶eNmde'p6l1\(.FNvm#;˶emep6l>\l/.FAmۍ˶Qe(vme;p6l6\l+.FIcRl3.Fi m ۈ˶Qme(mgp6*Udkp6*ոl*\*l%.FUm[˶Q-eۨmdKp6jŸl"\:l!.Djk|\l.F6m!˶шehfm4a3q6lcq6ilT\l +.FK6m˶њMeh&meq6ڱqlX\:1lh\Nl.Fg6m ˶ѕ eƆmtgCq6z!l=`\^l.Fo6m˶їep6lX\7. mc0˶1eʺm cp6l#X\3.( mc4˶1uerjVý1eۘmLdq6&VlYK\).Tmckm`Mq6f&lXc\٬.bsXC\.˶eXm,bq6ZlKXM\.2Vmc9˶UeXɪmbq6VJlkXE\.:Vmc=+˶emlbq66RlI\.6Vmc;+˶eɊmbq6vB.}m˶exbmlY\и6>Pl_XH\,.7m; ˶eɂmbq6~@lX@\, ..F o9˶˶˶˶˶ ˶˶˶˶ +˶˶˶˶˶˶˶˶ ˶˶˶˶ ˶mğmmmmmmm$m$m$om$om$oM|b7pm$u\5\U\\Te\%\4E\\ty\9\ Y\ .F&vm#3;˶eNmdcq6cl9Q\.F.vm#7;˶emcq6}l^\l.F!m0ۅ˶Qe(vmcq6ml%V\l .`f\l.Fm,ۀ˶Qe(mT`kq9>mTbq6*UlUJ\l.F5m")wl).FMm[˶Q-eۨme p6l<\l..FC6m˶јehfm4e3p6Ǧm4cp6l-\l2.F+6 m5˶цMehmcp6ڳu`cp6:Ѹl(\l$.F6m+˶э eΆm`Cp6zl \l .F6 m/˶mg}q6>lYo\A.`mc˶1ueƺm g]q9)κ^:mbp6FlcX\=.8mcmc?ˇ˶qe8mbq6\lGXN\,.1m8ˆ , .)m4˄˶qee82mcq6γt<]`iq6.4lXj\,.m*K˶q%e۸Βm`Iq6n$lXb\,.m.K˶qe۸m<`qq68lXl\,.m)˶Eex΢6Eexɢmbq6^HlY\O,4.g +m ˶eƂm|gp6~l?Y\>~lY \?, ._ m@ m# 6p6q6p6?q6?p6q6p6B_q6B_p6Bq6Bp6q6p6q6p6"oq6"op6"q6"p6/q6/p6q6p_S\\Xc\#\8C\\x}\7|˶˶˶˶˶˶ ˶˶˶˶ +˶˶˶˶?˶?˶?˶eNmdfp6lY \l8.Fvv m#;˶emfp6򰃸ly\|l?.F~m ۋ˶Qe(vmfp6lE\bl;.Fq mۊ˶Qmی˶Qme(6mep6ʱl:\ +l-.D|kj\l.Fm*[˶Q-eۨΖm`Kq6j%lb\l.Fm.[˶Qeۨm4`sq69ll\l.F6m)˶?6m˶ќMehmdq6ZIlD\6l.F[6m˶ў˶ёeFmtf#q6l]p\nl.Fw6m˶ѓ emfq6l}Y\~m?˶1ezr|V½1ezm eq6nlYW\ .Hmc˶1ue:meq6ƱvlY[\&6lYk\I.dmc +k˶15eۘƚ6l3XS\ .,mc6k˶15eۘmcq6zl X]\."Vmc1˶eXjm,cq6jl+XU\ +.*Vmc5˶UeX*mcq6ֳr܏m`eq662lXi\ͬ.WdXIk \m8.vV mc+˶e +mfp6l{Y\},?.~m ˋ˶q ˍ˶qe8rme9p6lY6\,+.Og'Y\S,3.i m ˈ˶qee8mgpym\dip6.ԸlY*\+,%.UmK˶q%e۸mdIp6nĸlY"\;,!.] m˶qexmm#?ۇ˶Qe(mbq6 +]lEN\l.F1m8ۆ˶Qme(ɶr Vme݄{m ۈ˶Qme(mgp6*l\Jl5.Fe +m +[˶QeۨƖmTgp6jl5\Zl1.Fmm[˶Q-eۨmgp6l \Fl6.Fc6 m ˶єe˶ьMehΦm`Sp6Zɸl$\l".F6m-˶юehmt`cp6:Ѹl(\l$.F6m+˶э eΆm`Cp6zl \l .d k}Y\~m?˶1ezm bp6lCX\;.0 mc8˶1ue:rM6ue:map6ƲlX;\-.gX\5.$ +mc2k˶1eۘʚmLcp_^\).Lmck˶15eۘme p6lY=\..BVmc˶eXjm,e5p6lY5\*.JV{U2.jV mc ˶UҬ+{mc=+Vmc#+˶eJmla%q6lXq\.Vmc'+˶e +(e +mcq6|lX^\,.!m0˅˶qe8rmcq6ll'XV\N,lXf\,.m,ˀ˶qe8иlY(\/,$.Wm ˶emdAp6~lY \?, ._ m m# 6p6q6p6?q6?p6q6p6B_q6B_p6Bq6Bp6q6p6q eۈeۈeۈex^^ۈlQllg ).FL .F,1.Fl.F!.F\.F<>.F|.F..FB.F"6.Fb.F&.FR.F2:.Fr.F +*.FJ +.F*2.Fj.F".FZ.F:<.Fz.F,.FFvm#;˶eNmde'p6l1\(.FNvm#;˶emep6l>\l/.FAmۍ˶Qe(vMDQme(ζm`[q6J-bq6JMleF\l.F9m<[˶QeۨmTbq6*UlUJ\l.F5m:[˶Q-eۨɖmbq6jEluB\l.F=6m>˶рehm4bq6YlML\l.t\fl.Fs6m˶ђMeh&mfq6ڰ lmx\vl.F{6l .FG6m˶љeFmteq92+ʆ^Άm`Cp6zl \l .F6 m/˶mg}q6>lYo\A.`+!.Pmc˶1uemdq6FNlYG\1.Xmck˶1lk˶1eۘZmLf-q6lSYs\i.kË˶15eۘɚmbq6fFlsXC\.˶eXm,bq6Z܉-a5q6lXu\.eXUk+Y\U2.jV mc ˶UeXmgpmldep66ҸlY)\-$.VVm8.vV mc+˶e +mfp6l{Y\},?.~m ˋ˶qe8rmfp6lGY\c,;.q mˊImˌ˶qee82mep6αlY:\.lY\K,5.e +m +K˶q%K˶q%e۸mdIp[^۸ma q6lX|\,.m!˶exbm0lXh\,.m+ ˶e΂m`Aq6~ lX`\,.m/ ˶_P˶ ?l?l߸l_lAlAllol!|Ŀm?m?m?Mbpm{\;\[\\Hk\+\(K\ \hs\3\m#&m#m#6m#m#. m#~m#>~m#~m#!~m#~m#1~ m# ~m#)~m#~m#9~ m#~m#%~m#~m#5~ m# ~m#-~m#~m#=~m#~m##;˶eNmda'q6lq\.Fvm#';˶emaq6l~\}6 +l\Bl7.Fa mۉ˶Qe(ƶmgp6Jl%\J͸l&\2l#.FYm[˶QeۨmTdkp6*ոl*\*l%.FUm[˶Q-eۨmdKp6jŸl"\:l!.F] m˶Qehm4dsp6ٸl,\&l&.FS6ml:.F36 m9˶тMeh&mbp6Zlm\l<.F;6m=aY~6FG6m˶љeFmteq6alP\l.FO6m˶ћ emeq,p6lX\7. mc0˶1eʺm cp6l#X\3.( mc4˶1uemcp6ƳlX\5.$ +mc2k˶1eۘʚmLcp_^\).Lmck˶15eۘme p mgp6l Y\:ڸ6ZlKXM\.2Vmc9˶UeXɪmbq6VJlkXE\.:Vmc=+Vmc#+˶eJmla%q6lXq\.Vmc'+˶e +maq6lX~\,.m ˃˶qe8rma9q6lXv\,. , .)m4˄˶qee82mcq6γt<]`iq6.4lXj\,.w`XJkWY +\k,9.u mK˶q%e۸mfp6lwY\{,>.}m˶ ˶exbmlY\O,4.g +m ˶eƂm|gp6~l?Y\_,0.om ˶e/e\@o\p6?q6?p6q&o6B+.FH .F(3.Fh.F#.FX.F8=.Fx.F-.FD .F$5.Fd.F%.FT.F49.Ft.k˶˶ ˶˶˶˶˶˶ ˶˶˶˶˶˶ ˶˶˶˶ +˶˶˶˶?˶?˶?˶eNmdfp6lY \l8.Fvv m#;6{F.vm#7;˶emcq6}l^\l.F!m0ۅ˶Qe(vmcq6ml%V\l .`f\l.Fm,ۀ˶Qe(mT`kq9>mTbq6*UlUJ\l.F5m:[˶Q-eۨɖmbq6jEluB\l.F=6m>˶рehm4bq6YlML\l.t\fl.Fs6m˶ђM,'{m5˶цMehmcp6ڳl\l4.F'6 +m3˶хeʆmtcp6\`Cp6zl \l .F6 m/˶mg}q6>lYo\A.`mc˶1ueƺm g]q6F.l#Yg\Q.hmc ˶1emgmq6&6lYk\I.dmc +k˶15eۘƚ6܌`Mq6f&lXc\٬.dXCksY\y>.|Vmc˶eXjm,fp6lKY \e:.rV mc˶Ul˶UeX*mep6ֱlY9\ ,.FVmc+˶eJmle%p6lY1\(.NVmc+˶e +mep6lY>\,/.Amˍ˶qe8rme9p6lY6\,+.Og'Y\N̸lY&\3,#.Y[9,=,.m"K˶qe۸Rm\a)q6lXr\,. m&K˶q%e۸*v%e۸mcq6xlX\\,.#m1˶exbm0lXh\,.m+ ˶e΂m`Aq6~ lX`\,.bX@\, .ƿ2˶ 8α?67.F`.F'.FP.F0;.Fp.F+.FH .F(3.Fh.F#.FX.F8=.awll7l׸lWlQlQllg ).FL .F,1.Fl.F!.F\.F<>.F|.F..FB.F"6.Fb.F&.FR.F2:.Fr.F +*.FJ +.F*2.Fj.F".FZ.F:<.Fz.F,.FFvm#;6{ +Fvm#+;˶eΎm`Gq6r#la\.Fvm#/;˶em`{q6 +=ln\l.Fm(ہ˶Qme(ζm`[q6J-bq6JMleF\l.F9m<[˶QeۨmTbq6*UlUJ\l.F5m:[˶Q-eۨɖmbq6jEluB\l.F=6m>˶рehm4bq6YlML\26Ǧm4cp6l-\l2.F+6 m5˶цMehmcp6ڳl\l4.d(\l$.F6m+˶э eΆm`Cp6zl \l .F6 m/˶mg}q6>lYo\A.`mc˶1ueƺm g]q6F.l#Yg\Q.hmc ˶1emgmq6&6lYk\n&VlYK\).T3׆mck˶15eۘmfp6氆lsY\y>.|Vmc˶eXjm,fp[jm,e5p6lY5\*.JVmc˶UeX*mep6ֱlY9\ ,.FVmc+˶eJmle%p6lY1\(.NVmc+˶e +mep6lY>\,/.Amˍ˶qIˉ˶qe8Ʋmgp)Ʋ$˂˶qee82maq6β lXz\,.m"K˶qe۸Rm\a)q6]cq6dl7XR\, .-m6K˶q%e۸mcq6xlX\\,.#m1˶exbmmc?ˇ˶qe8r}6ƽqe8rme9p6lY6\,+.Og'Y\S,3.i m ˈ˶qee8mgpym\dip6.ԸlY*\+,%.UmK˶q%e۸mdIp6nĸlY"\;,!.] m˶qexm.F|.F..FB.F"6.Fb.F&.FR.F2:.v F +_eH_eH_eH_eH_eH_eHeHeȀemdbq62SlYI\.F6vm#;;˶eɎmbq6rClyA\ .F>m#?ۇ˶Qe(mbq6 +]lEN\l.F1m8ۆ˶Qme(ɶr Vme(6maq6ʲ lz\l.Fm"[˶QeۨVmTa+q6lr\l.F m"9w Zl1.Fmm[˶Q-eۨmgp6l \Fl6.Fc6 m ˶єe˶ьMehΦm`Sp6Zɸl$\l".F6m-˶юehmt`cp6:Ѹl(\l$.F6m+˶э eΆm`Cp6zl \l .F6 m/˶mg}q6>lYo\A.`mc˶1ueƺm g]q6F.l#Yg\NjN6FlcX\=.8mc.|Vmc˶eXjm,fp6lKY \e:.rV mc˶UeX*mfp6ְlkY\u<.zVmc+˶eJmlfp6l \m8.vV (.NVmc+˶l+{mc/+! +%bm۶m۶9m۶m۶m۶힤:emgp6lY\C,7.a mˉ˶qe8Ʋmgp6N.}m˶exbm0lXh\,.m+ ˶e΂m`Aq6~ lX`\,.bX@\, ..F 'mmmmmmÿmǿmmĿm?m?m?m?mmmDmDmD_mD_mD_mD_mDßmDǟ6l1'lǸlGlqlqll{l lkx˶˶˶˶ ˶˶˶˶ +˶˶˶˶?˶?˶?˶eNmdfp6lY \l8.Fvv m#;˶emfp6򰃸ly\|l?.F~m ۋ˶Qe(vmfp6lE\bl;.Fq mۊ˶Qmی˶Qme(6mep6ʱl:\ +l-.FEm[6 +Fm*[˶Q-eۨΖm`Kq6j%lb\l.Fm.[˶Qeۨm4`sq69ll\l.F6m)˶?6m˶ќMehmdq6ZIlD\6l.F[6m˶ўemtdq6:QlH\.l.FW6m˶ѝ emdq6zAl@\>l .F_mem `}p6޸lX/\'.'dYkCYw\a.pmc˶1ue:mfq6ưlcY{\q.xmck˶1lk˶1eۘZmLeq6f /. mc&k˶15eۘma q6lX}\.Vmc!˶eXjm,a5q6lXu\. +Vmc%˶UeX*maq6ֲ +lXy\.Vmc#+&Vmc3+˶eJre6ǽemdEp6v¸lY!\= .^V mcˏ˶e8mdyp6ܸlY.\ĎlGY\c,;.q mˊImˌ˶qee82mep6αlY:\ ,-.EmK˶qe۸Rm\e)p6lY2\,).MmK˶q%e۸me p6lY<\,..Cm˶M ˶exƢmPl_XH\,.aXp\,.m' ˶emaq6 lflö˶˶˶˶˶ ˶˶˶˶ +˶˶˶˶˶˶˶˶ ˶˶˶˶ ˶mğmM`pm!.F\.F<>.F|.F..FB.F"6.Fb.F&.FR.F2:.Fr.F +*.FJ +.F*2.Fj.F".FZ.F:<.Fz.F,.FFvm#;˶eNmde'p6l1\(.FNvm#;˶emep6l>\l/.FAmۍ˶Qe(vme;p6l6\l+.FIcRl3.Fi m ۈ6F9m<[˶QeۨmTbq6*UlUJ\l.F5m:[˶Q-eۨɖmbq6jEluB\l.F=6m>˶рehm4bq6YlML\l.t\fl.Fs6m˶ђMeh&mfq6ڰ lmx\vl.F{6m˶ёeFmtf#q6l]p\nl.Fw6m˶ѓ emfq6l}Y\ʲ~6lX\7. mc0˶1eʺm cp6l#X\3.( mc4˵mc,k˶1emL`mp6&ָlX+\ɬ%.mc*k˶15mxq6fl3Y\Y1.lmck˶15eۘmgp6l Y\E6.bV mc ˶eXƪm,gp6Vl+Y\U2.jV {5".ZVmc+˶岬FVmc+˶eJmle%p6lY1\(.NVmc+˶e +mepy mgp6lY\C,7.a mˉ˶qe8Ʋmgp6N.}m˶~l{m1˶exbm0lXh\,.m+ ˶e΂m`Aq6~ lX`\,.m/ ˶_˶ ?l?l߸l_lAlAllol!l!/lϸlOlalallwll7l׸lWlQl kx˶mğmmmmmmm$m$m$om$om$om$om$ïm$ǯmmįm/m/m/m/mmmdmddgp62Ӹl)\,$.FVvm#;˶emdGp6røl!\< .F^v m#ۏ˶e(md{p6 +ݸl.\"l'.FQmێ6 F m$ۂ1X)m4ۄ˶Qme(6mcq6ʳulZ\l .F%m2[˶QeۨVmTcq6el5R\l .F-m6[˶Q-eۨmcq6yl \\l.F#6m1˶фehfmMehƦm4gSq6Z)l-d\Vl.Fk6m ˶іehmgcq6:1lh\Nl.Fg6m ˶ѕ eƆmtgCq9*+Ά^mbp6zl} \?.F?˶џem dq6^lYO\!.Pa.pmc˶1ue:mfq6ưlcY{\q.xmck˶1eۘZmLf-q6lSYs\i.kË˶15eۘɚmbq6fFlsXC\.˶eXm,bq6ZlKXM\.waXu\. +Vmc%YVjV mc ˶UeXmgp66lY\M4.fV +mc +˶eƊmlgpymdEp6v¸lY!\= .^V mcˏ˶e8mdyp6ܸlY.\#,'.Qmˎ˶qee8tvee82mfp6ΰlgY\s,=.ymK˶qe۸Rm\fp6lWY +\k,9.u ,).MmK˶q%lK{m.K˶qe۸m<`qq68lXl\,.m)˶Eex΢m`Qq6^(bq6^HloXD\,.;m= ˶em|bq6>Pl_XH\,.7m; ˶eɂmbq6~@lX@\, .a.F {mmmmmmÿmǿmmĿm? ˶˶˶6qýl7l׸lWlQlQllg ).FL .F,1.Fl.F!.F\.F<>.F|.F..FB.F"6.Fb.F&.FR.F2:.Fr.F +*.FJ +.F*2.Fj.F".FZ.F:<.Fz.F,.FFvm#;˶eNmde'p6l1\(.FNvm#;˶emep6l>\l/.Dxkn\l.Fm(ہ˶Qme(ζm`[q6J-bq6JMleF\l.F9m<[˶QeۨmTbq6*UlUJ\l.F5m:[˶Q-eۨɖmbq6jEluB\l.F=6m>˶рehm4bq6YlML\l.t\fl.Fs6m˶ђMeh&mfq6ڰ lmx\vl.F{6m˶ё {m3˶хeʆmtcp6l=\l0.F/6m7˶ч emslY_\.>lYo\A.`mc˶1ueƺm g]q6F.l#Yg\Q.hmc ˶1emgmq6&6lYk\I.dmc +k˶15eۘƚ6l3XS\ .,mc6k˶15eۘmcq6z܎-`uq6:lXm\Ŭ.dXMkKY \e:.rV mc˶UeX*mfp6ְlkY\u<.zVmc+˶l+˶eJmle%p6lY1\(.NVmc+˶e +mep6lY>\,/.Amˍ˶qe8rme9p6lY6\,+.Og'Y\S,3.i m ˈ˶qee8mgp6.lY\^.ԸlY*\+,%.U;%,9,. m&K˶q%e۸ma q6lX|\,.m!˶exb&exbm˶exmPl_XH\,.7m; ˶eɂmbq6~@lX@\, .agloö˶6q½lAllol!l!/lϸlOlalallwll7l׸lWlQlQllg ).FL .F,1.Fl.F!.F\.F<>.F|.F..FB.F"6.Fb.F&.FR.F2:.Fr.F +*.FJ +.F*2.Fj.F".FZ.F:<.Fz.F,.FFvm#;˶eNMeΎm`Gq6r#la\.Fvm#/;˶em`{q6 +=ln\l.Fm(ہ˶Qme(ζm`[q6J-bq6JMleF\l.F9m<[˶QeۨmTbq6*UlUJ\l.F5m:[˶Q-eۨɖmbq6jEluB\l.F=6m>˶рehm4bq6YlML\l.t\̲i6l-\l2.F+6 m5˶цMehmcp6ڳl\l4.F'6 +m3˅Y6m+˶э eΆm`Cp6zl \l .F6 m/˶mg}q6>lYo\A.`mc˶1ueƺm g]q6F.l#Yg\Q.hmc ˶1emgmq6&6lYk\I.d).TmckrVXSk3Y\Y1.lmck˶15eۘmgp6l Y\E6.bV mc ˶.l˶UeXmdUp6VʸlY%\5".ZVmc+˶emldep66ҸlY)\-$.VVmc+˶emdEp6v¸lY!\= .^V mcˏ˶e8mdyp6ܸlY.\#,'.Qc,;.q mˊI,3,.m,ˀ˶qe8m\`iq6.4lXj\,.m*K˶q%e۸Β2v%e۸ɒmbq6nDlwXB\,.=m>˶exmPl_XH\,.7m; m' ˶e vĽe/e}\@o\/\ O\\`w\7\W\\Pg\Bp6q6p6q6p6"oq6"op6"q6"p6/q6/p6q6p_S\\Xc\#\8C\\x}\=\]\\Dm\-\$M\ \du\5\U\\Te\%\4E\\ty\? emdbq62SlYI\.F6vm#;;˶eɎmbq6rClyA\ .F>m#?ۇ˶Qe(mbq6 +]lEN\l.F1m8ۆ˶Qme(ɶr Vme(6maq6ʲ lz\l.Fm"[˶QeۨVmTa+q6lr\l.F m&[˶Q-eۨma q6l|\l.F6m"=wFl6.Fc6 m ˶єe˶ьMehΦm`Sp6Zɸl$\l".F6m-˶юehmt`cp6:Ѹl(\l$.F6m+˶э eΆm`Cp6zl \l .F6 m/˶mg}q6>lYo\A.`mc˶1ueƺm g]q6F.l#Yg\Q.hmc ˶1emgmq6&6lYk\NV6&lSX \9.4 eۘmdMp6fƸlY#\9!.\ mc˶1vl˶eXjm,fp6lKY \e:.rV mc˶UeX*mfp6ְlkY\u<.zVmc+˶eJmlfp6l \m8.vV mc+˶e +mfp6l{Y\},?.~DZ,/.Amˍ˶qlˉ{m(ˁ˶qee8βm`Yqy:;ɲmbq6NLlgXF\,.9mp6_m# m#m#0 m#m#(m#m#8 m#m#$m#m#4 m# m#,m#m#<m#m#"m#m#2 +m# +m#*m#m#: ?eۈ?eۈ?eۈ?eۈ?eۈ?eۈeۈeHeHeHen^HM\ \du\5\U\\Te\%\4E\\ty\9\ Y\ .F&vm#3;˶eNmdcq6cl9Q\.F.vm#7;˶emcq6}l^\l.F!m0ۅ˶Qe(vmcq6ml%V\l .`f\l.Fm,ۀ˶Qe(mT`kq6*5lj\l.Fm"1wjl9.Fu m[˶Q-eۨmfp6갅lu\zl>.F}6m˶ѐehfm4fp6lM \l4\l*.F 6m%˶ъMeh&map6ڲl8\l,.F6m#˶щeFmta#p6l0\l(.F6m'˶ы emap6l.Fmc ˶1ezm f=q6lCYw\N̪n6l#X\3.( mc4˶1uemcp6ƳlX\5.$ +mc2kˍmc*k˶15mxq6fl3Y\Y1.lmck˶15eۘmgp6l Y\E6.bV mc ˶eXƪm,gp6Vl+Y\U2.jV mc ˶UeXmgp66lY\M4.fV +-$.VVmc+˶l+{mc'+˶e +maq6lX~\,.m ˃˶qe8rma9q6<cq6ll'XV\N,lXf\,.m,ˀ˶qe8m\`iq6.4lXj\,.m*K˶q%e۸Βm`Iq6n$lXb\,.m.K˶qe۸m<`qq68lXl\,.m)[3m9˶Eexɢ0EƽEex"mep6ޱlY8\,,.Gm ˶eBm|e!p6lY0\>~l?Y\_,0.om ˶e/2e}\@o\/\ O\\`w\7\W\\Pg\'\0G\\p{\;\[\\Hk\+\(K\ \hs\3\m#&m#m#6m#m{{m#q6p6wq6wp6q6p67q67p6q6p6RWq6RWp6Rq6Rp6q6p6q6p62gq623li\.Fvm#+;˶eΎm`Gq6r#la\.Fvm#/;˶em`{q6 +=ln\l.Fm(ہ˶Qme(ζm`[q6J-bq6JMleF\l.F9m".w +l-.FEm[˶QeۨVmTe+p6l2\l).FMm[˶Q-eۨme p6l<\l..FC6m˶јehfm4e3p6Ǧm4cp6l-\l2.F+6 m5˶цMehmcp6ڳl\l4.F'6 +m3˶хeʆmtcp6l=\l0.F/6m7˶ч emslY_\ʳ>6޸lX/\'.mc(˶1ueκm`]p6FθlX'\Ѭ#.mc,ku8mcm!˶exb ĽexƢmlY\>>иlY(\/,$.Wm ˶emdAp6~lY \?, ._ m( m# 6p6q6p6?q6?p6q6p6B_q6B_p6Bq6Bp6q6p6q6p6"oq6"op6"q6"p6/q6/p6q&g_?eۈ?eۈ?eۈ?eۈ?eۈ?eۈeۈeHeHeHeHeHeHeH_eH_eH_eH_eH_eH_eH_eH_eHeHeȀemdbq62SlYI\.F6vm#;;˶eɎmbq6rClyA\ .F>m#?ۇ˶Qe(mbq6 +]lEN\l.F1m8ۆ˶Qme݂{cRl3.Fi m ۈ˶Qme(mgp6*l\Jl5.Fe +m +[˶QeۨƖmTgp6jl5\Zl1.Fm-c-fnڶm۶mmm۶m۶mq4ək>:ǝ̴]ͱ6mX r9kcvnQ;'ظcmlʱ66mgX3rkXr-ک9Ɩkcvru;)ئcmlNȱ6kX۷rڱ9Ǝkcvts;*إcmڎȱ6vkXr=ڡ9ƞkcvphKrWs}9~mkcm˱6hX}r9mk㐶gqh#8cmv툶kqd%8cmvʱ6i;XǶr9mkㄶmqb&8mcmܶʱ6Ni[X-r9 78mcm6ͱ6jXgssF9ƹmk㼶Aq~[?ڸcm\ͱ6.jXsKZ9ƥmk㲶Fqy[=ǻ+j9ƕmk㪶Jqu[9KJkۊ9umk|qC[.ڸ-cmԖɱ6nnKXr[ے9mmkxqG[,ڸ-#]mkpqO[(ڸ-cmȱ6oXrۼ9Cmk6wH+x͙cm<ȱ6oXOr|z{͚cmicX1s9mk6Ze5cm|F]6Rm1cm|߆ϱ6~hX?as09mk6Tk2 cmϱ6hXAs 9mk6Po0`cm ycm cm cm cm cm cm cm cm cm cm cm cm p99w9ƈ9{kckckckckcFi1VI1vq1NQ1na1^A1~~1A^1an1QN1qv1IV1if1YF1yz1EZ1ej1UJ1ur1MR1mb1]B1}|1C\1cl1S{&ژ=cmҞʱ6fmOX'r9kch1W{$ژ=cmʱ6mXr9kcvoP'XݝcMԽ+wh3Xݑcm,nϱ6hXK[s-9-nα6i7X˶s 9kcv]b6X]cmܮα6ViWX+s9kcvYf4X]cm.α6iX s9kcv^a;7بcmlα66igX3s9si9kcvJU;9غcmlṈ6m'X۵sq9kcvLS;:عcmҎHmvDjcvx{;,أcmɱ6jX{r}ځ9ƾkc?˱6oX}s>9^α6n{X=sC9amk[qD58cmvα6n;XǴsc9qmk]qB68mcmԶα6Nn[X-sS9im׆cm6˱6lXgMr99mkܶaq^ 8cm\˱6.lxvQ['ڸcm\ʱ6.mkxk[#wqy[=ڸcm\Vͱ6jXWskJ9Ƶmk㺶Bq}[>ڸ-cmؖͱ6njX7s|P-cmږ̱6nkKXs;b9Ɲmk㮶Hqw[8ڸ-cm̱6k Xs|9ƃmk6Op;x͕cm<̱6ksXs'l9>=fͱ6jXOsgL9Ƴmk6C|>xMcmئͱ6^jX/s|Q{Mcmڦ̱6^kSXskMxMcm&ɱ6nXﴉrwۄ9{mk6~A/cm|ɱ6>ncXrOۘ9}ȱ6>oX_r/ۨ9Wmk6rM)cm|Fȱ6oX?r۰9Omk6tK* cmֆȱ6~oXr?۠9_mk6pO( cm 0z˱66ɱ6α6ʱ6̱6ȱ6+mkckckckSjc~c1\C1|}1B]1bm1RM1ru1JU1je1ZE1zy1FYk#4+$;8'(70/ ??ژ /ژ07ژ('ژ8;ژ$+ژ43ژ,#ژ<=ژ"-ژ25ژ*%ژ:9ژ&)ژ61ژ.!ژ>>ژ!.ژ16ژ=cmܞα6fiOX's9kcX1g{4ژ=cmα6iXsa6oX r۽9BkcvwH+Xݙcm,ȱ6oXKr%ۭ9Rٖn7X˴reۍ9rkcv}B.X]cmԮɱ6VnWXrUە9jkcvyF,X]cm.ɱ6nX봋ruۅ9zkcv~A;/ذcmlɱ66ngXrMۙ9fk9kcvje;%تcmlNʱ6i'X۶r9׎]mЎͱ6vlX;sQ9.kcvD[;<ؽcmͱ6lX{sA9>/mXsY/8cmɱ6j{XrCڞ9ơmk㰶{qx-8cmvɱ6j;XGrcڎ9Ʊmk㸶}q|.8mcmضɱ6Nj[X'rSږ9Ʃmk㴶ykͱ6hXgMs&9moiX s9m׶o6.lXur9%mkҶfqY[#ڸcm\V˱6lXWUr95mkڶbm׵r9 mkƶlqS[&ڸ-cmҖʱ6nmKX%r9mkζhqW[$ڸ-cmʱ6m Xr9mk6oP'x͝cm<ʱ6msX9r9mޞlXOYr93mk6ciϵr9 mk6moirW/sWT9ƫmk6EzkcXs/h9Ɨmk6Ju9cm|F̱6k#X߷sp9Əmk6Ls: cmچ̱6~kCXs?`9Ɵmk6Hw8 cm̱6X~6PO1pw1HW1hg5R#w1x?="-25*%:9&)61.!>>!.16)&9:%*52-"=<#,cmcmcmcmcmcmcmLcmLcmLcmLcmLcmLcmLcmLcmLcmLcmLcmLcmLcmLcmLcmL?cm̐?cm̘?cmԞɱ6fnOXrYۓ9lkcx51XƜkcH1w{8ژ=cm̱6kXs}9ƂkcvOp;Xݕcm,̱6kwXs%m9ƒkcvKlKseM9ƲkcvC|>X]cmخͱ6VjX+sUU9ƪkcvEz8mcmжͱ6NlX'sV9)mkԶE7ks_nqF,8m9ږmmk㜶Qqn08mcmϱ6.hXus:9mk㒶Vqi[3ڸcm\V튶Zqe[5ڸcm\Vα6i+X׶s +9mkㆶ\qc[6ڸ-cmܖα6niKX%s9mk㎶Xqg[4ڸ-cmα6i Xs9mk6_`7x͓cm<α6isX9s9m֞hd5x͒cmmcX1r9mk6jU%cm|Fʱ6m#Xߵr9mk6lS& cm҆ʱ6~mCX!r9mk6hhAr9?mk6`jϴrW_Icm cm cm cm cm cm cm cm cm cm cm cm p99w9ƈ9H799(W9ƨ9h99g9kckckckckckckckckckckckckckckckckckckckckckckckcFL>@W3sYS9ƬkcD1{{<ژ=cmͱ6jXssyC9Ƽkc@1?Xݗcm,ͱ6jX sE]9ƢkcvGx=Xݖcm,nͱ6jx̶t9Xݔcm,ṉ6k7X˷su9ƊkcvMr:X]cmڮ̱6VkWXs5e9ƚkcvIv8X]cm.̱6kXs y9ƆkcvNq;;YMۙ9fk9kcvje;%تcmlNʱ6i'X۶r9kcvlh;cr9kcvdk;"حcm˱6hX{Cr9kcv`o; دcmr~9mkOqP;8cm̱6m{Xsn9mkȶKqT98cmv̱6m;Xǵsv9ޠжͱ6NlX'sV9mҶ]mڶȱ6Nk6k㌶Yqf48mcm6α6iX s9mkザ^qa[7;:9mk㒶Vqi[3ڸcm\Vϱ6hXWUs*9mk㚶Rqm[1ڸcm\ߖϱ6nhX7es29mk㖶Tqk[2ڸ-cmϱ6hXwEs"9mk㞶Pqo[0ڸ-cmϱ6hXys|B{͓cm<α6isX9sI;͑x͞cmlXqr9'mk6fY#cm|F˱6lX_Qr97mk6b]! cmІ˱6~lX?ar9~҆ʱ6~mCX!r9>=]mͱ6jXs@9ƿmkcZ1`}1PO1pw1HW1hg1XG1x{_iCXC6TK1ts1LS1lc1\C1|}1B]1bm1RM1ru1JU1je1ZE1zy1FYk#4+$;8'(70/ ??ژ /ژ07ژ('ژ8;ژ$+ژ43ژ,#ژ<=ژ"-ژ25ژ*%ژ:9ǚژcmLcmL?cm̐?cm̘?cmԞɱ6fnOXrYۓ9lkcx1G{,ژ=cmɱ6nXryۃ9|kcv@/Xݛcm,ɱ6nwXrE۝9bkcv{D-Xݚcm,nmvsL)Xݘcm,nȱ6oX+r۵9JkcvuJ*X]cm֮ȱ6VoXkr5ۥ9ZkcvqN(X]cMLӽ w~;?ؠcmlͱ66jXsMY9ƦkcvFkcvZE;5زcmlNα6n'X۴sm 9vkcv\C;6رcmԎα6vnGX#s]9nkcvXG;4سcmα6nXs}9~mkcm˱6hX}r9mk㐶gqh#8cmv˱6hXG]r9mk㘶cql!Ӵv9 mkĶMqR:8mcmҶ̱6Nm[Xs_nqF,8mcm6ɱ6nxvN(8mcm6ȱ6oXr ۺ9EmkvqI[+ڸcm\ȱ6.oXWr+۪9UmkrqM[)ڸcm\Vȱ6oX7r۲9MmktqK[*ڸ-cm֖ȱ6noXwr;ۢ9]mkpjr{ۂ9}mk6kǵrWys<9mk6Wh3x͑cmhXqs89mk6Vi3cm|Fm6Ze5cm|Fα6i#X߶s|Ocm|߆ϱ6~hX?as|\{ cm҆ʱ6~mCX!r9mk6hW$ cmʱ6mXr?\('8;$+43,#<="-25*%:9&)61.!>>!.16)&9:%*52-"=<#,cmcmcmcmcmcmcmLcmLcmLcmLcmLcmLcM]mL_ϱ6_˱6_ͱ6_ɱ6_α6_ʱ6_̱6_ȱ6ϟϱ6fȟ˱6f̟ͱ6fjX3sYS9ƬkcD1{{<ژ=cmͱ6jXssyC9Ƽkc@1?Xݗcm,ͱ6jX sE]9ƢkcvGx=Xݖcm,nͱ6jx̶t9Xݔcm,ṉ6k7X˷su9ƊkcvMr:X]cmڮ̱6VkWXsɺ6lXkKr9:kcva^ Xcml˱66lXsr9&kcvfY;#vzy;-آcmlNɱ6j'Xmډ9ƶkcv|};.ءcm؎ɱ6vjGX;r]ڑ9Ʈkcvx{;,أcmɱ6jX{r}ځ9ƾkc?˱6oX}s>9AmkWqH38cmvϱ6oxF5wqd%8cmvʱ6i;XǶr9mkㄶmqb&8mcmܶʱ6Ni[X-rY;mps3f9ƙmk㬶Iqv88mcm6̱6kXs z9ƅmk㢶Nqq[;ڸcm\̱6.kkXs+j9ƕmk㪶Jqu[9ڸcm\V̱6k+X׷sr9ƍmk㦶Lqs[:ڸ-cmږ!Dq{[<ڸ-cm툶HjpqO[(ڸ-cmȱ6oXrۼ9Cmk6wH+x͙cm<ȱ6oD-ǧ'۬9Smk6sL)x͘cmoE-cm|Fɱ6n#vW)wm1cm|߆ϱ6~hX?as09mk6Tk2 cmϱ6hXAsD cmα6iXsi9ƀ?@?99 _9Ơ9`99o9Ɛ9P/990O9ư9p99w9ƈ9H799(W9ƨ9h99g9kckckckckckck^jc~n1QN1qv1IV1if1YF1yz1EZ1ej1UJ1ur1MR1mb1]B1}|1C\1cl1S{&ژ=cmҞʱ6fmOX'r9kch1W{$ژ=cmʱ6mXr9kcvoP'Xݝcm,ʱ6mwX;r9kcvkT%c92kcvc\!X]cmЮ˱6VlXt]mܮα6ViWX+s9kcvYf4X]cm.α6iX s9kcv^a;7بcmlα66igX3s9si9kcvJU;9غcmlṈ6m'X۵sq9kcvLS;:عcmҎ̱6vmGXsa9kcvHW;8ػcm̱6mXsY/8cmmwjWqH38cmvϱ6oXG]s#.9QmkSqL18cm׶ϱ6oxvB68mcmԶα6Nn[X-sS9im׆cm6˱6lXgMr99mkܶaq^ 8cm\˱6.lXur9%mkҶfqY[#ڸmkʶjqU[%ڸcm\Vʱ6m+X׵r9_-cmؖͱ6njX7sR;-ڸ-cm֖ȱ6noXwr;ۢ9]mkpqO[(ڸ-cmȱ6oXrۼ9>=ɱ6nsXrGۜ9cmk6{D-ǧ'۬9Smk6sL)x͘cmncXrOۘ9>]m|Fϱ6hX_Qs(9mk6Rm1cm|߆ϱ6~hX?as09m?~iCX!s9mk6Xg4 cmα6iXsm9ƀ?@?99 _9Ơ9`99o9Ɛ9P/990O9ư9p99w9ƈ9H799(W9ƨ9h99g9kI>`q=Ǿs/ < u9]'r3aʌ9w,Xb=<'8r̅+ϼʍOa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^ "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7oOa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^'H0Ĉ I4SH2ԨӠI63`Ȉ1̘sǂ%+ܳa;ybρ#'\ 3 "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7R?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xF- "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7a &Bq$I&Cy +)QBu4iѦC} 1f”sXdŚ{6ly`#O9pę WyV?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xFO'H0Ĉ I4SH2ԨӠI63`Ȉ1̘sǂ%+ܳa;ybρ#'\ U?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xF !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#'H0Ĉ I4SH2ԨӠI63`Ȉ1̘sǂ%+ܳa;ybρ#'\ i &Bq$I&Cy +)QBu4iѦC} 1f”sXdŚ{6ly`#O9pę Wy'H0Ĉ I4SH2ԨӠI63`Ȉ1̘sǂ%+ܳa;ybρ#'\ D$DQbI$E Yr)PD +UjiФE]z0dĘ Sf̹ckٰ<g.\yWny &Bq$I&Cy +)QBu4iѦC} 1f”sXdŚ{6ly`#O9pę Wy? !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#v &Bq$I&Cy +)QBu4iѦC} 1f”sXdŚ{6ly`#O9pę Wy~!J8 H!K<(SJ: hӡK>3aʌ9w,Xb=<'8r̅+ϼʍ !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#g$DQbI$E Yr)PD +UjiФE]z0dĘ Sf̹ckٰ<g.\yWnޡ !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#Oa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^s "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7^?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xF "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7  &Bq$I&Cy +)QBu4iѦC} 1f”sXdŚ{6ly`#O9pę WyQ?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xF/'H0Ĉ I4SH2ԨӠI63`Ȉ1̘sǂ%+ܳa;ybρ#'\ K?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xF !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#$DQbI$E Yr)PD +UjiФE]z0dĘ Sf̹ckٰ<g.\yWn~!J8 H!K<(SJ: hӡK>3aʌ9w,Xb=<'8r̅+ϼʍ$DQbI$E Yr)PD +UjiФE]z0dĘ Sf̹ckٰ<g.\yWnR "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7~!J8 H!K<(SJ: hӡK>3aʌ9w,Xb=<'8r̅+ϼʍ_Oa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^x~!J8 H!K<(SJ: hӡK>3aʌ9w,Xb=<'8r̅+ϼʍ@Z?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xF_Oa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^+ "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7Oa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^'H0Ĉ I4SH2ԨӠI63`Ȉ1̘sǂ%+ܳa;ybρ#'\ + "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7U?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xF} "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7Y &Bq$I&Cy +)QBu4iѦC} 1f”sXdŚ{6ly`#O9pę WyU?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xF_Oa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^x~!J8 H!K<(SJ: hӡK>3aʌ9w,Xb=<'8r̅+ϼʍ@N?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xF_Oa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^k "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7Oa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^'H0Ĉ I4SH2ԨӠI63`Ȉ1̘sǂ%+ܳa;ybρ#'\ u &Bq$I&Cy +)QBu4iѦC} 1f”sXdŚ{6ly`#O9pę Wy !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#A &Bq$I&Cy +)QBu4iѦC} 1f”sXdŚ{6ly`#O9pę Wy~!J8 H!K<(SJ: hӡK>3aʌ9w,Xb=<'8r̅+ϼʍ !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#7$DQbI$E Yr)PD +UjiФE]z0dĘ Sf̹ckٰ<g.\yWn> !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#POa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^7$DQbI$E Yr)PD +UjiФE]z0dĘ Sf̹ckٰ<g.\yWn~!J8 H!K<(SJ: hӡK>3aʌ9w,Xb=<'8r̅+ϼʍ$DQbI$E Yr)PD +UjiФE]z0dĘ Sf̹ckٰ<g.\yWnJ "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7~!J8 H!K<(SJ: hӡK>3aʌ9w,Xb=<'8r̅+ϼʍOa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^~!J8 H!K<(SJ: hӡK>3aʌ9w,Xb=<'8r̅+ϼʍ@Y?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xFOa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^; "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7Oa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^'H0Ĉ I4SH2ԨӠI63`Ȉ1̘sǂ%+ܳa;ybρ#'\ ; "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7W?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xFc "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7U &Bq$I&Cy +)QBu4iѦC} 1f”sXdŚ{6ly`#O9pę Wy !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#$DQbI$E Yr)PD +UjiФE]z0dĘ Sf̹ckٰ<g.\yWn> !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#POa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^w$DQbI$E Yr)PD +UjiФE]z0dĘ Sf̹ckٰ<g.\yWn~!J8 H!K<(SJ: hӡK>3aʌ9w,Xb=<'8r̅+ϼʍ'$DQbI$E Yr)PD +UjiФE]z0dĘ Sf̹ckٰ<g.\yWn "L(1$H"M,9(RL*54hҢM.= 2b̄)3ܱ`Ɋ5lGsȉ3<+7P?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xF'H0Ĉ I4SH2ԨӠI63`Ȉ1̘sǂ%+ܳa;ybρ#'\ |R?AB%FIRɐ%GEJPFMZХGCF0eƜ;,Y [{9q•g^xF !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#'H0Ĉ I4SH2ԨӠI63`Ȉ1̘sǂ%+ܳa;ybρ#'\ c &Bq$I&Cy +)QBu4iѦC} 1f”sXdŚ{6ly`#O9pę WyO'H0Ĉ I4SH2ԨӠI63`Ȉ1̘sǂ%+ܳa;ybρ#'\ 4$DQbI$E Yr)PD +UjiФE]z0dĘ Sf̹ckٰ<g.\yWn} &Bq$I&Cy +)QBu4iѦC} 1f”sXdŚ{6ly`#O9pę Wy !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#i &Bq$I&Cy +)QBu4iѦC} 1f”sXdŚ{6ly`#O9pę Wy~!J8 H!K<(SJ: hӡK>3aʌ9w,Xb=<'8r̅+ϼʍ !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#O$DQbI$E Yr)PD +UjiФE]z0dĘ Sf̹ckٰ<g.\yWn> !D#N$)dȒ#O"%TRN&-tңπ!#L2c Xsφ-x=8s3/r#Oa"D'Ai2dɑ@e*TQAm:tgc&L1KVgÖv<ĞGNp^$DQbI$E Yr)PD +UjiФE]z0dĘ Sf7 oxo-v;y=~>#|q|S op$X|ȗ2_| ɷ6|o~ď ?g_K~ů w7Q?oͼ6;x'ݼ> |1>'$|9>"_+|u7;|}~?'s~/7{ϛx3o᭼ɻx7ὼ>ȇ01>'$|9>"_|57&|=!?3~/%;~m?MVƟwn{y|a>G|Oi>g |/eW_|omwc~O?_~=oyo-v;y=~>#|q>'3|y_+|u7+|~ȏ1? ~ɯ5?ϛx3o᭼ɻx7ὼ>ȇ0| >ɧ4?s|/Eė +_k|oMŷ{|C~ď ?g_K~ů w77x;w|!>G(|O)>g,|/%W*_|o-w.#~O)?_+~o- 7f[yown{y|a>G|Oi>g |/eW_|omw~9_~=oc֟7f[yown{y|a>G|Oi>g |/e:|o>?~9_~=o|~ěy omwNŻy}A>ćcC>'3|y_+|u7;|}~?'s~/7{ϛx3o᭼"ݼ> |1>'$|9>"_|57&|=!?3~/%7{&[x+ow.{x/|!>G(|O)>g,|/  |e$u]޲;oYvvy:[^.oYg@֗!$@ !F,lI0e!Ka K† YR0`Ȉ1̘`Ɋ_cÖ{9͙ WnyśV?AB%FIRɐ%GEJPFMZgc&L1gk6lٱߜpƝO^'H0Ĉ I4)QBu4iѦC/z0dĘ SfYdŚ [v9p7g.\qo>~~ a"D'Ai2dɑ@e*TQAm:tGCF0eƜKVٰeǞGNg.\qo>: &Bq$I&Cy +)QBu4iѦC/z0dĘ ̌9 Xaˎ=̅+73aʌ9 XٱߜpƝO^A &Bq$I&Cy +)QBu4iѦC/z3aʌ9 Xaˎ=̅+73aʌ9 Xaˎ=̅+73aʌ9 ~k6lٱߜpƝO^[$DQbI$E Yr)PD +UjiФE= 2b̄)3,Xb͆-;8r3ܸɋ7~!J8 H!ˏ@e*TQAm:tGCF0eƜKVٰeǞGN|s•w "L(1$H"M,9(RL*5 MZ} 1f”s,YfÖ{9͙ WnyśK?AB%FI~4SH2ԨӠI6|ѣπ!#L2c΂%+lزcρ#'9sʍ;o>~D?AB%FIRɐ%GEJPFMZ} 1f”s,Yfïcρ#'9sʍ;x!G$DQbI$E Yr)PD +UjiФE] 2b̄)3,Xb͆-;8r3ܸɋ7) &Bq$I&Cy +ITRN&-tE>3aʌ9 Xaˎ=̅+7 "L(1$H"͏%GEJPFMZ} 1f”s,YfÖ{9͙ Wnyś &Bq$I&Cy +)QBu4iѦC/z0dĘ SfYdŚ [v̅+7^ &Bq$I&Cy +)Q槨RN&-tE>3aʌ9 Xaˎ=̅+7> &Bq$I&Cy +)QBu4iѦC/z0dĘ SfYXaˎ=̅+73aʌ9 Xaˎ=̅+73aʌ9 Xaˎ=~ߜpƝO^S'H0Ĉ I4SH2ԨӠI6|ѣπ!#~ SfYdŚ [v9p7g.\qo>~L?AB%FIRɐ%GEJP姩ӠI6|ѣπ!#L2c΂%+lزcρ#'9sʍ;x!'H0Ĉ#$I&Cy +)QBu4iѦC/z0dĘ SfYdŚ [v9p7g.\qwy͇@N?AB%FIRɐ%GEJPFMZ} 1f”s,Yklزcρ#'9sʍ;x!'H0Ĉ I4SH2ԨӠI6<= 2b̄)3,Xb͆-;8r3ܸɋ7~!J8 H!K~\?AB%FI~4SH2ԨӠI6|ѣπ!#L2c΂%+lزcρ#'9sʍ;o> &Bq$I&Cy +)QBu4iѦC/z0dĘ SfYdŚ Ύ=̅+7%&L1gk6lٱߜpƝO^$DQbI$E Yr)PD +U~: hӡ= 2b̄)3,Xb͆-;8r3ܸɋ7 &Bq~$)dȒ#O"%TRN&-tE>3aʌ9 Xaˎ=̅+7.O^$DQbI$E Yr)PD +UjiФE]gc&L1gƆ-;8r3ܸɋ7~!J8 H!K<(SJ: hӡӣπ!#L2c΂%+lزcρ#'9sʍ;x!$DQbI$E Yr (SJ: hӡ= 2b̄)3,Xb͆-;8r3ܸɋ7UAD#N$)dȒ#O"%TRN&-tE>3aʌ9 Xaˎ=-\r΃'/| "L(1$H"M,9(RL*54hҢM._3`Ȉ1~s,YfÖ{9͙ WnyśOa"D'Ai2dɑ@e*TQghҢM._3`Ȉ1̘`Ɋ5sȉo\r΃'/|s "L(1$Hɐ%GEJPFMZ} 1f”s,YfÖ{9͙ Wnyx!POa"D'Ai2dɑ@e*TQAm:tGCF0eƜKVsȉo\r΃'/| &Bq$I&Cy +)QBu4iѦC/z3aʌ9 Xaˎ=̅+73aʌ_ak6lٱߜpƝO^$DQbI$E Yr)PD +Ujigiӡ= 2b̄)3,Xb͆-;8r3ܸɋ7? !D#N$)Yr)PD +UjiФE]gc&L1gk6lٱߜpƝO^}Q??@a"D'Ai2dɑ@e*TQAm:tGCF0eƜKVٰeopȉo\r΃'/|4$DQbI$E Yr)PD +UjiФE]g/2b̄)3,Xb͆-;8r3ܸɋ7~!J8 H!K<(STQAm:tGCF0eƜKVٰeǞGN|s•w3aʌ9 ~k6lٱߜpƝO^h'H0Ĉ I4SH2ԨӠI6?G/z0dĘ SfYdŚ [v9p7g.\qo>~!J8 H!ˏ@e*TQAm:tGCF0eƜKVٰeǞGN|s•w3aʌ9 56lٱߜpƝO^+ "L(1$H"M,9(RL*54hҢM.?O>3aʌ9 Xaˎ=̅+7,{osr3N[~.?g|e QW<301xV^>y>a90?1WqT~[ǃ_O=ϫ~ڧNo}~:TO[9{ygo,1 ^5>u.>?1\USC>8 ?{3gVq/G]1V^AuEcOoK*r=A[w;wr*vx OpG_ ?# w?$<+>Ӭw󏼊<^wun<%>~zUѧƄ| y9?o~A||= +Sc^A}u y yN7?9u JqW/?o9ww_xozG>yÞ{S^(/<9{Gg'_y<7\{G|Uc>8հ'Z *|[L΀n *gZQu_7*ѵnoUyg o&oUߎkև>?fOyUًY +>{yG_g٫8>ϖ>Uw>1;/٫8[k {ynr9_yx⤼7sțߋngNug7oDOUA4Mq20˯և8a|y͕o[g}WrDOU_ywr·z*ί~Z ||N|*Tdu>y1 yM+(oC2V]>_?$XgK^̓9>=U}|V^y60Obp_s/wa +{~٫8> +fVk}ث8ȹ/?]f٫8ȹ/?_37ɡ +j<+oNx/?0~C$z*p%3|υW]+q~a/g/*N/SuWq"F"2^S͝wϿwfjg/A>w8s7qֽ~ 3#W}~qD5|0#\yu8p/n?g5UZHu+~y@:*ꩶ^w*EO 3ZVyGER^)DOn79UWt+9/͹+/N8֢jv9؛d/ʷ[qX7Wr슫9{}.8TO9~m'{9EXc׵*ry>>Wqs/͙>~sU9EN!U=M*~7\U_m?Uӊ^A=֡a|}s/v@xD^Aȫ~f٫8>{yF}}[q?]9ꋚ-_WqM>y9EnvcQR=Wꇬ7Q=UqL}@_p_+sv!WJp/'X?+9ߑ+/Nz]_+vW^Q}Qk2_SCO ||N9{3'^޿y߼8^ Tg9«8qAqS^A}u?_:%\WqH6|||\E;NOy>Eȋ^4߿^W| {3碧_)'.qDb>Mq +1V}W^ 0o˿0W+ƾN˱ߟ:A^QO]Ap񋜽)q| +zZipo{u+8/ʮq>|\7ϣ毼3<Ϙgo^e#ˉ!_y1"̳a->{9ErKG^A}]x`=U_T,0J&9j1M7psQ}QX|U]0O,@+8-=gK'p_u;9_SO~r||@_Ep_<"Gy/E-e}{88jի8ԇώ\E͚W)dtN}z +C^zrOc;DZ7Y7*/^YpʛPO~!8>}Q{}WpT_Tp1"W eWqT_Ԝzim9؎fugolgaWqTOͼ9_jk}ث8M<#hsٛp_vkʫ8S_ً\qrc/w"pWpT_T2|橼x#gV}1eN#z*pu)[~/ñ>ޟ8ʋ{W/VQ?\ x{*˵5́"Q5*NN=^\7ɡ*rzf=+&9SaofSyezMgWN/*oW]a}z -KEeǣiʫ8/ʾ9|QS5-t>˽/EȫUߕWqT_h>k{9EϽicEGE{;q&US>BxGT[-r@ nUSUWrDO찐˽ߝ}㬙9د?Mq v ogoOc_?09*.3m8y>񇽊\E>όܯC{YWUa}o > 9{|6^U}ꩪ17ןpOuwX褁olUG-nIy}|{*ˉg́"vKgo}/ʫ8詪*l?AyuS}$z*Cs`CW^;*i->{1Q}Q7Wqzs2KT d{S<: y&j){n`OX}+Eg3uomWq/zJy񪧪Z-Wq/N^?z'a=[_9૾Z^Uwn┢US?yfuW^7;pٿ)/spU_TO{p)p_NҖf?^̓9U_ݨHy"xۥVF^?^]a|驗\ywxSKvW^ő}҂/3zf3{~J#&ֽo3_x"-6_yֻ!{~*N)֘:+/sDO?'[gP6nN^/|2iW>RdO}]G|ʫ8jnO(꩖r/j79p}0^ +x|o˝/*}8_؋y2 JzUE=8ӿ6T_#[| W}QJ|}>{Sr~?8EߺpG^ +/slx٫8^Y >{~ ۗ\T +ɛ⨾"WYjx*T^SW}Qo'8+:Q=UVƓqwӼi9{SZEɓ_yG?U6= o<"Ͽb/3{*ŊGʋ\qT_T?qC(䈞8:S^S!~~Fb'_8_g*꩐״O^W[g>uK]/j/"WE9mvQ\ySucԟ;_gً9𪞪8 NN^9T4nj US߶}*rwމz*̳q룼)Ed'L6oً(ʳG7E;nG_EM5OUlh٫8>y[ɋwa=[꩐?Hp_N?aV)2Z̓GN=> /vwƫ(~}/5{Ǎ6+wQOu\k'Nȹ//ree >{SՃ?_^GT=[絭+ʫ8/*]ws&C=3ʫz'#O>?"W''{q/Eϯ?%?򆼊/E׿g٫8UOU.U^qM=W[׏'sOsMws9૾ͤ;`ox P}+}ƫ;*k٫8U_)E o1GxGE8?6«8-$ؾ~}9E_co_*N=bu^苚v?7ũi:+8^tu#sT{}N=; W^DOk?Mq~a;xS<:}Z].E}`y199Sam>{Ǐ +y%7%S!ov/D^g깃G9˞/do}ƻy0?E8SξR^`ߐWqpT_T6 |*j8/8ҺR^ɡiO@U}ѭ=9_p_cµu}X?2h{GE[]?+ W}Q'}F@.=8BwV ^wqOUη){19y︤z"C/{+9jf? y1Op/G{U䥸~+[C$z*}[|;_ Sa;VRwR}QO%waa|g ͙?9{9Eozi٫8ȹ7Q}Q&oSEŐ y*w o*OzCH̕'rJn >s3j{'|ꋐn?xwq__V4#g/rũ*i}g W=U1g28S;әC 8E.9<蛬^Wꋊ,*E~y_y"/pʋ9U_T-Pk*E Y|USe:\eև/a~7{yMQ˿8?xka/A)/sy8/&Nd{=p_<:bp_9f^𙃼=ytKy/E9-w7)W?ܯw8[p«8KzNԟ(`<~ۙ={˕9)oy;.Eg}^:Sy(/sW=U>_|})NI>'/r!>ֳ}^zvU) Βw_̇>5>+ȾhsͿ/`/֍9_/jx<~*s_:}Q^48OQO)NKW /rbpa/3۝"?~ 9{S0|/-^ũnsay'gEg_AySa>Տw7Q}Q~tW^mEOlo_!o~/&kW{۝s}w\W{*vj"ɋ9r_<{n{19=S(p_Ne/8șsSKu}RoA/Wo׷{1^qT_T~vK9sSaG/*:z\#UG(^R}Q3+p +8苲ϯ]_^}msșoeo}ƷϊseES2 ꋐg_x珏ȕWq/jzy?|/B}!~~2}Q޻~q><*S!o'nX S_lb٫8>|ӥ/ٛp_⫝̸9<)َRON~}y&_zj:?̚K^AlUۅz*?Rث8rO~~ӈ +rE^Ł"pw^_F^A}8swL/{' +be٫8k9{Ms\ +|%Y{9T7l>{9Ec}nn~Y)di2^[2z"p5x}٫89O<6o&Ώiɫ8rOߋnٛAq/Hx}}8*SwSC\EKkd?Tvg}Q;/-ua W}QW+og'/֓9𪞪2JkWq|N=Ӽ1<^AP_un+U +y6h)/s垪A?Wq}Q)U詂l+皯B9EyS]xeƫ(#B~~]ǂltZ"vt~D^A.ΏgU:SoN2$o=Sy*qPOuȯ_!|p{'y)⨞x.s +,7L^Ł"?rCeN詚/ʫ8X5i痲Wq +,?79{^i8|}/E߼6|}ITuc|R^ E؋(EߺWy3}g'`ǷC}7'm} 'ǯQEȫY6_yʕWWyqYW9En\g?nZü>Q^vw/ _ȕWq~UmW=U5 gWqT_{T0wz29T5ܾϧz,>{tU䪧*6q}٫8'Ew{Gy%GT͑p_;>GWT[OٛpOyCNbK8/=0^y%z*sG^󩨧BF7puGׁ|u4G4o_)?Fxu` _?hy>)T?i«8y}FυWqd_4Y_xp_aֹ^r<#/r`>a|w 珜"pu7s|`o=u8+kxU_Tty"oϿً9~DOlg8詊^<9~#|<{ꋊ-o^U >{SS>«8aٖ$/ri!"g7}}AONs_7󸪼/os散?*(:qk}WqT_Ԟ~Lew/*& d͟)ʗ.x/:d̸/)EMqTOU{ܝ_yyr_y*p_~;yxknm_e?{*̿fs#zA[|啽m_yw:hq*Nt^`s_U]=<ߒWqs_»t9~ϼ|. {3ͫ3g~9z~{1^q/꽅w֟8a|o-*ꋲ;N6"My"Sɋj?Q^q~ueQ^5؎_F~˲[;`--46<~* {B٫7G_U䍘e.|*rk |*"!/Fr*r>{9EXr^{*pGn:ھUM[/#go}8>`9rOU}?|kWqs_?}쮐\EO?;+z*pIKDɫ8U_u'o#Ѣ#/㎟Q_yo,?)?9?lq`n_UVE8f<\E%">My{*p/la>~Wqj+/s>9 |bE/r*rn>.g /h4mp}jUgA=r5)}Kx/HQxͷ2|0f{go}凷F2^~R7mpS!#zl丹 +śFZg Fb{yĤ[{S5ʫ8_N^"z" 'KD*r*r>9{ꋪkzE٫8 sq.r*/jY|}"3>9{ꋪ_]?Wq7SSzWq +߉?٫8 |+ꋖϣ=֡ѻXӐ%GEOkn_ KTfãϏ<ٛ⨾lxԟ{2^^9Tg8>Wqs_ϰWq({Kɛp_OSyo_p6wIUmbUSnl٫8rO~Ԁ: go~oW^燻7_EWqs_n֟\E +!4 +?z˾xu{H*/;~#'JkU/*}8z}^ũ{=US. 珜`\ ~N^A}8هG{jZ^A<^Ab`ꋪw+/sj?SaȮ)CO񇼘s0+>8/rױI𙃜"j󘏼^4G_zwxsN^-8aʷ^7+"pn?WAg}Q޻ld]?+/s0O|>s]ʫ8aQoM^W/(/s0"YMʫ8m!9{+WjWrDOבW^ܼ:Q}Qv(OQ^)/GE̍"O|4W]a>EϏ\y%GEf}8zR}«8Ew=:~"W^S/ʫ8_yyY<<2Um8}<^ p_ʷVyGE8}*N#zfǂ}8*p_~;>>(4l:fu|S^ő=U9bg=OFxu˻re?v\r8a|~??"e_y4#^}8#Q0=z"/pp_~}|`/3^08x7}QU|߅r߅y|>ϻ~qD>Oq敏"'8*WpUx1'5yT2Oϧo&=WKץ9/SSY%z}8޿1U_pI~;,މ]gW~E/ʮY,z`ҫ.i~z>~>Ez'//#+/sp_4?X)z}|8Sfβοxlmś"6ߎ\yꩲ]GEqgh{WכgZ|Uo\p\«8/*`gO"oƬb_;^渟wrWq/}|~|؋9Oy[[(~]gur57>wpGi9n\}8->{9Ek"lD >{9E'WUn;OUޘa W}Q[,oF^AzPU_“~Lx>EO_MqTOU :~|W^䊣zb=_swɚ?{1x/T?!U/*OO^A}o}hWqrpoxcOX]uNGi?={567Ng;/z_Vzheև,="p W}Q9}Ǒ 󬾲{9Eg|?z8苪Ed>u?q^z| X|8(U0b9{+EYoڙ^8ʫ8/*}}H^GqT_T z~R߅zK\ES >{Se3fZ|U5,fWqT_T}WqT_Tͯ*T^ 2~+oqอzߒ7ř{=c=Kݔ:y"gjySůM+/s4ucrxU!w>7s毼OyGT_j͟'s]dOZ7[|*Ufɫ8rO[->{Smt́"? -~I^*E_T]&_U/g_Wq({|yAGEX~}Sx%m8u?cq~WK|~yo>Ug'yGrR^N&ֽ +n~3gw; +E./s{*gmQy~m9r o:r-gC->{z!E߈yA}.W를_EaWq00'GUy'EO}N^zTsQs*r)f>yE^A}jŪpg/+Ed/13ꋊ:͚􊾋{*̿ڳ|̇ș"˗oa'm9{9E_2z r*NTT+i~~{Wy'yz*?vnn~=ꩲ8+?țp_N}+[ן9ȹ/l=B>reʮgoЭ{G4>x<_xO fퟕ2EO_fW~7{8a/rW=UB8a??b//*Ge}2/B=yb/Ʒ}Wz[ً\q/W|es_#U0rs_/m9s_iU^Wt}{3OWqd_~Dp_~=IE#~/^=/E~>vn}}N$"p/g^*{QSA=R瞪}V{}~qǷ#z'0WSQO~ʐ}bً\qrܝWχGz!7=z~2/w߄9yo^WMq/c߈ȕ9X7S_oߒ^x>ESC*ϩ/Btԏ)/s"pu=-<a<{3"qeo#g7 >{S-t%/x/B^;dxɡ뙦j/8ȹ/ +'Uϯ}ȋ=WgGy!/{pXOyw/R^|/϶8~/!ȋ\qT_Xt} N$u ꋚ3ߡi9q|A.¤E}8J7^>0ӫ8ȹ/B^>=:(/3M30>uK)Tgߟ5_Q^r|9%\USw~ਾ{9E8a|w^A}o<ٜ*TG}>reb|*O=WpTONGb>㋳WھMqZ.^4_^oOarگI24$zs"WySp9}ֿ*{/l_㙃 o׍1Sy~ ׷yV"'_bl3ʋ9U_T-<65R^`7 +|o2^'_~>,x4"느s8u֡X̾~P^`>|=1OU#.]q9FOCGݯF2^SǽWqZ< +y5Y y1{'aG0șz*O8}m"w7Q}Q=,KEQ~A|ŷ.s=7Q}Qu?+ꋲΈ^u3"WϿ؋+!E2/mھʫ8/j6~lW^`/j[|{S>|\yGEuau)s_DO_cUEഏg^A愸Q:ܠN<{B/~֙_-_Q=UqSʫ8ul2 +yY{*gG/a/rᾨ='/"/丹'?VyxQ}Qu$/A}o{ړc/B:':(/+f>a39>yYs0LxU})ǚg/3Q}Q69{ꋊ dob'X2χz*';r%|N>>' W}Q3vWq*-gٛ⸟sox*zً!S!/cT}a/+Ed#8E8S?(o#=2z|Eׇ~,~-}5}9TO72|wiCG^Aν|s_=ubp_~(>srp|9{zWq0i?#+GSOycK}EIys_t$[qא~{#z|l}~)8ʫz' w/?xyE^}Yʫ8R_U^A=Պ2E_Tw٫8U_[)E?E.ʫ8S:k/v{dB"oyܼW^`>/O\)UG?n~wR=U3kZx򊾋"}z*7覼GEEd'r W}Qy#Ǘ2ITՄWq0)nr'oQO~(Ԣj8츸R^s_|Ty Tț6ZϽS-zËa`ꋊq~/e֙"xvC7qUt<˜Μcb#UB^];ܔ|\pd_4̾~`/ +ԓ`>2}cY|*rʫ8ȹ/{?X7wa|%ʫ8/j6ns^Nꩪo8:A=պ`?{19!/ b⨞2z>Ne_Э{ݮR}Q~ws}Q{^_Sm9r_~ure!_.:^gN[0\|xt~A^|J).zk٫8𪾨pSc ൢWqsON5%UxBx|<؋qO=k+a)ƫމܟf/A}_)/sW}QQ|U^|TOU,{Sy? S싰n'#|R/qexw:09ss_83Dw/P >{ꋲ[M ʫ8TTw+C>*S!o|%zbecW{*pʣ+⨞(ϔWrD_T]4u˽S<}tMq/zWq/\'w W^E\yGE x +⨾kvS+/]xܩ>dkMr|}WqTOռNġGEĵw*EW6OWq/{5U}Tmogk?}a˽s_~~g +2|?Yp}g/3ye/}ɕ!}3_yӈ*qcʫ8=x}R^șsgo~ηCiK~kr"Cr[rF̓9ȹ/?bWq<z'7[.zυ9ʞjQUkfUl0fx g=8}y:USvA!gy8SS m"疿ݚ?{9T|\^A=WWqs_~[U_? 9{;ssONyR[|*r<qQ?s*reK/g$ +W(z\ENKD?Uݹ}Wq +bҥ7X{܀nLggN˹\B+QqG=J6{*3oU/*w\"zHy'PON/*_Wqs_Nև"Y*ߎ\Fk٫8ȹ/fʹU}|*ϩ/|ǑWqs_Nq߷^A}67_USO~Ӓoٛp_~+䨞j'ǗIE)'Z7#/և9ȹ/:d^C{*p +wsreN;墧[&z?MqT_]R}K/]~\j>^y=+/]nuO +r.\qTHWjes_mR^&[^W7?@yΈ?9s_<8*׊P_ǯ|y|P^ᾨ'~ +Kes_ވWq/zyh#s"Wo민zff߇NyC ވd9EWU\O/?{1 y{ʫ8_n<8z_*eʋ9U_?|*68Zb3b9r_ؾʫ8yκ#E!'\s5+.ϯً(ʭ38ʫ8/*.LkQ^l|U`u ʕWWy5#+5^;qPHU㑫vJԯb|Y r ًŜFEM7?WqU}Q=du:7sߧ^䊣zbs}ȋ(Eo|/{1 +j_y>T->{S|JxS!/kx;z MEMq]O{*r> ٫8Eߜt|>Wqs_~}ȝ/*ϩ/jz_o>ʛpO~}`9{3^0vbD8pث8ȹ/;r*z*p=."g W}Q3kٛp_N}~g/}:e 7s]^NxU_TowE}S5x| b\y/Eg##/9s_ go=ͶS ً9r_uhfg gǫ) _ *rU0Z85nʸ{3"c+#g=jKL>{19r_y]~y^f=+/sW}Qqug~q_|ُZsܺU}>,}ogzًu`r\3??AySowU/d"̿A >s_>ۇRʫ8/y1ɡ;aT=RE^5{B^jT;5|a+PON=s[W}Qam_*rmȫ8>FlK^As7Q}QQ^}}sO}VU"gr59)>IyчZ?{9T_ͽD7=_y39Eț+?3)䷽ǝ2"_ {_+ ~;*SE9S^[hx3*E_Tn۰R"C1qWy%GEn^My}N9hKk}p_ٶ E!'R^`E7+h{Q}QqO^-~ +E}>șpOo`SS!g]?#;}0:|b<{3ybTp^s_uQVSOU]_!goC=8g«z'PO^̟9ȹ<۽n͟\Eb٫8 ꋐgmg/+ꋚ3' t8EΜ7S9^Zn!9{^)|r*rcV]y魏/>8Saͭ{2/B^ kT^v3C>r"gNSTsf0{Sz*0k2{EOk? ySu_ϼeo}2(/s +y(/3e_D|p9sO''>rA}ټMqTOunҸ)/r+擽V9{S|: +)gJ>٫8K=8٨[|&9S_m_yR}Qʾ`c) svu`o}8'WaR_{ =5\Wq(pM>yS"3ǘ{B~;9s+G' +z?A.R}Q~t=ΐ7Q}Q5Y|U|;,q_y%GT= ۝"pM1?Wq]/ ,>{^S7*=Sp"W^+{_*q~@^Wq|N}8cc 9Hʛ}8A|;쯐=c=U;WO~Q/w}Qͣ_)U}EgGEUM!"grW0饾 U_T~xkzk>*E=䈞YIyɟ?)|fUpϨ?/?:o}WqT_h}0OS#7?Ěrp_ukR}?=:?r"g}מ~@Mp^ߒWqs_xNu@yU䪧*??+O8Wk''>^ãy?9Wq/w!_p.pjꋐ7O^G^(ͳ0 {/BތrtJTOϏC䲧簩 R^Q}QSW|o y+EyS2㹧:׆Oy>E>O_b/.U<ș"m}Bԟcݔ9/E?Oy~+N'XyA"_t>Mp^*/Nq/0=JW^xS?p}Kw}z*#5 ./>_4~ kT1k鲧,~VuϝOuOzy9⌐)q +!_4sr׋<-{cm!_?KEJ瞫~hGT?~N~/:s{?:GToU@s\T3gOq_~/KS?ϣ߯N|K]s}c׼yY%"xvSϋr~T3w޿@Ιਗ਼ HQ{*y=6?9y\y/g_K_ DkEꟿ|Q{k^t^tح=7ﻺsTo%ޡV'"G-3rȯ=8/Pgę/xGU__eUE퓖8)}q|;σq~TZu3Gǭ{*\r8|Wc)9?੦g?ᕵPh䩦?(8>nqRsԏpfy~X%"qx&U9.X/RrH7y\䘧8חǧ;ׁC(\tq(8 NSu>_Q.y'Eg{YKEUs?.E!k=CϽkykkKH,ߟ~|w_$p뺟\̹FHk/{*q+~}żqv7{k/:G47%O?z\w<_|pw +4~W[x)9z]ӽykTA;ur;ir性nj*}4T3q~Qrq_zg|~S/kUݽT_]/R|uJ7,U\J񻞽{.q:x~s~E?oP.q3*rH~瑵3"|Q罥Ƨ\]4W~!_4 0"<=}]{%"ݨ\/G(8t^J#\h5G%-8U?q|=A.rSsuq/n_=/6"5%"qS~\x&_>岗?rS3o6KEA׏Sk}ќ,떫:q5+ǯz !_O[%z}Z މ|g?P..T5\NzuTxb^_UsGi.Yq={Chx'_{Ѽ/ +/[Ώ8K{?} \N{חr8ᯫߟzsT'_4s'"P}*%uU4oG}kd/jS3<6~83?/T/g5~?K!_^zŸk'x^]/cg^_%pc/A"_4ys"Zr8䋺xj/Q.q E!O ?Uŧ\!!;{*^_D_uO5~-zsqw +Ex>GuE7=qS5yM멋w)8/ǯNETrkǏqiG~3j|u:GF_]/nL%"Oz|Q;VuO!_>T9"1|^TlTs8䋚{yN\(|Qyx%_|䛞s^lC5hT 5gš\/g^㏐E'v\/<95>}s%{*[{Ι_GT]xs"qO~Q|tO]w"S"?j?6q_y)m{y_?!_5ǟYNE˾Q5>=S_V;Psޜx%-8䋆>\8nsw/<4*?@s}.\u4S}=WuNڇ-~8T᭏euKމ|Q{۪~sw/:o }G쒯::GH]{.qT'_~<|})wgS_U8ߟsrCj~q_4sN۫^Qsz/oUokE˿_6?/%"g>6~uHw뜙jz܇^_{|QwWU84~rhϩwU9/S-B_tmjQ=y#_R?Oq_p#J|5ߥ~NVs;/w<'Ury9<8^|T\h~ y-o{.qTw_$3Y?{.qy*q8?ę_(8/4o8n1K)sS]pǧGFs"+>p^W}\j{ɹ5GuEgkS.qTw_$N{YK?׽ؤgp4߫\Hߵ~Ts)?iZ|+GuE_K:vG(8S/j||})wH :K\՝"U\h?[=8s|8+_)8/g:[%\7O%~ǖǏKMz|kEb*ޝy(9fλr)wGh srzoh̷\uEL?%r:{O+r8=|Z9~qTnKgS}7-8{U,8/zfęi-WQ{*sNr3/ +;%r"yZ<[%NvBO?~Zsw_$Nc~%Ψ<̿ 5-8/R}o,[~EtK8KEwTU\ՉHx¯Nh\Zz.qTSx X|IQ}81_%y߿= r~Tw_::g/?P_s1OsKꞻ1OqNq}RοiqS)8/_5~%̏GuT/oGuEC\|%䋚S|s";\ tO%c)!_>L/y)Y=Oqw^9'y=Z~C#>Q#V_\{+-.ħ:R_h/G[97%֫.N?<WOu]X|?ZuqK%=AL:'|e(GN4o_\\L_w]wW)8opvc 񦗽kS.qxo:ǽ Kx3Ӳީę5oQ.q~,:?4Xևo?oP.q›~%?)yJ~{s G7:u?GN%N?KN?7|\_um9;h~>~lz8XNpN;\w^lsKy|^i.p;NS<~,8c<gz~*8!F}\_ u%N[9$~Z甹Sg먃iW[=:uQdP\ℯ_sIK!vG|S.w߹\gjPoubq}W:먒3uTwZ/J\*9z_Ps3|:9wyy,+߶r*9w[J}KޮkPr?}hpǭ^R~rϜ)c\_''d*yOZGy}x߭U?z$̹ϧrAs9 vSQr|շrM|GSܭީ75x(7XdErC=R?O/Vq5վ,%No)T1:K ~&O9x#v!_4j+%`T(8]QsrlYVqz䐿Ҿ,%N<>Jÿe/9s.p;y}Hƙs_|)[9<7?("~;SJ뫃I׃mS.q;oSQr|շrS/rC||(%1sǔ+\/:R?1+d?\N]|-ƙ=Ux.EIy E=(%NK]1iuꬮT>%"QK_Q.q5vYW v)18:DT(Q}+|)*[9䋨NO(sx}[9h?"m性"D?O MΏ_GM_+<7sSRyWy'EX\'_>.?CK䩨Ch0ۋ'E"r/7qqC^gE֟c}V{\t䩼.E/NcY]>Q.qR9ZKNy-?H={*7>=~=CT^o_͹x9Tk?Z8m\W#R.qҾ,̹!OEuϜ މ|U_͹I+_4g(F%6J.!'y&yEt7Lu%N,`t\9vﲧ +T7r}+VeA.qeZȁ3H>\'_D>j+SWBq;Wc\/%>/@;SQrG>FY}+<>rӁ/jeEI/<5Var3ϵ/_uH/{y*wWuNr_x\.|׵9~qSS9GIrfOeu\㧇UsI߿ +ݿ'j>KH!OEuʥ~TT́}V(Q}+|)ѾEՇ(|y|E#ˢ\]&QKEڋ'g%Ng)E՛rC.{-%No׏TT\'_Dή勼>(f/h@՜ ;=䋼>~qڸ)E^O]G/N_y]3<0;|u8g[}^ s_<}iOZ} \~z J/N신"Wix^Zӓ/)8=y*OKE6sr_`ϭJ!_4lW!_Duʥ~ETSY=~\/kUy\/4^=:'rމE>1%_1S.qM(8䩨N߁/K3jL^r>IC(8:g :ru<`6s_<+]B%N*8i]Tγ|CW)]+"?wr<~qSy]9s+/l{Vy?pNv[(8i=S^E[W%{'"S.;O^|Ѱ_|Qg6)9䋬fEQ\N`'wV"Q'?lB\_'K=j0rz}Gub)8䋨Nԟ3qi3%_wJ.~|}|\ mQK1Ӻ(/_\/l?UZ_%>"<՛)7R]]SQ5r|×x "W!?H]:g}" G/N:R.q:<䋼o%N| %_銋jy*#a.x'g"{n#_Z v5V_)8䋨Nԟ3)̟76s(7 |E-+%NKGm搧:nNV"S."C)8䋨NGwҿ3J2w^rCK|^S*}^[9y"S.?ɞ*XYW/Q rG_dIrCR?"o/jNu{IA_rӒ/zXWȱ&>GHeCn)9T-)8= u%Nokr3gȞ[9=ZW-?(>)__QCo䩼.~qSy}H69o,쿚6+֏0;婂EYQr3TiS݊ + v[WKE!_Duʥ~EiSο_mlWTT"_DuWOh诈3᠇~j_Q.qQr?Sy=oO}[9M\G|SQ%_zg0@jK`dEV_)9qUΏ|Qo>ZܴZs<$JOE/N\Q.q|䋼GA jy*Q+|geJ޿杆zՐO)ww"EOh048:Q?\/N[y$ʥ~E_|շrqTruJ[yKET\'_ԙJJu(TiT'i}_ܭ +sw/߳\ jA%"Z=|\쩬uQz!N,y*Q."7{*o䩬Vr]KH/h@K]\._(}~]!N!%G r_x~Yjy*xY|Uiz_a.pz|}_P!OEu(ymWN?<:|QZ/ע\/"EA_rCohQ!_ԚJy0(8Zۗ~4)8&ZrC||({䋨Ri^H<[ET.q\y9?T^}|[9y"S.UWSQ=x?實|r:<}<ʥ~ET/:|xwBe* ࣶr곿\䀧junܴ/_Q.qyR7Q{M:竺s\jϿN!_4R|Q rCh픋R@E-#ҿ߯w*{r}+'J;Vy)_N}TVKѼ|{\1"_Y=+/:R<_uϺqQ9s_SM/Y_AvuV\'W룾7r_N.Vq3Z;GQ.r_\?mz_+CoNKE摴?rCh45+|hy_\-ocKEwL|J|%0_)8]hߔǍ%&~(SPwrӁJ^\䘿=yAs8C<*m\GRY~8%N _r_7#Y]\ĩX+"7ujx? rK߿R.q:;N䋼98䋼.E/~}?\/j(8lTO)8o:mWx0tvy +s/ jNoIꔋv>Yc._6VT\|`\/TW O5]Q.qMߺEKEM\_Ǐ|Qwm(8ZW Zɯ/=+E]V w~qQr瓃M7L}[9i]TS.q:E<_6rE%GG/N<-E^o_͹:Ϟr_y /y]:G/ϳ|QkـR.q:lssIh}PR.qZT^\Jr~|>jG!_ԃ\uQ9~y*^<8)!_>wa?"%N3%_*7zK *b 5^|ny$&O՘_y8i}Uγ|՝3'K<׻JE^oari]T͞*@9%NcA}S.qTTwr|7sSQ=Kތa"NK䋨CKG+/>l}x2;͞QK.J9z| c%_j⯼_Z08䋂I 8]gu:@ruUkٽ 8i=?v~gEuʥޯ;WVIrE^o_)I%_ZQ'%_S\_l<~qzSyyjy*#a+{E^6+q:;~98i=_ο|h(1Qr|WiXWAO>rU~=%No_]~_{=z/Nk}JIu\W=w"kmubS V\/_Duʥ)ST^}ʼnυpkGPgy*ca+`_-Z8'[՜ /S4w$_> ~jTΟӇx7rz|x=,!_Du̹M5)8#Q.r;5T\G_di5␧s\N:WE!OEuʥ~NXUg^m?}>sCQ E x-%N:=)8i]T婨>K신yĉ_y](IrT^W~qZ7"k9G/NZϔ/s\:R{'"o/r5+8|ڋ!z14SQ|rӺr3>+S.q^?ҿrx>)9TT\/2mp=Ҽ/ r_,gꯔK\jT:z|oET\oy}Q6~WtvW+qM8䩨NO[9f_diu7CxiN(7ї(ww"C뺏rޯީs\GrzSY}֯ZHK!_ԙ +E!]i>G>?P.qz^d?OO^rC*~y0Ey y-(8W#~rq_)8[+y*O&%"cZ51}.{jN0*_Duv|壶r{oWE'*^ i +s|)TTi9?lG>RI<=䋰~JѼ}SEkJ`>ju+_Duʥ|շr<18䋨NOC=ET\'_DET\Dr zi/(8䋼>~k";GO[9䋨NO [9<ɧQ?"Gmt䋬u|Wg׉EX\'_Dޮ勼.E/`@Q.7O䋨鼨<)Sż/_wwJ+`K_Cj>a `ǿ||Y\( _ּS7W`i=SW:p"xK!>C9~y*8䋨NO[9䋨N:>߇E<)y}zl/dQr|շrm+䀧"P.p¿A탢r%OuY_Q.qy]0׮7Qrn"Gm +|շr;Qr +s|Q^CE|ӺkwC7]:Oq}QC#ҿ\␧zw'k9G>5~~j﷋C.l勼_]Ujεm]յ/+ݜkz]wʥ3)|՝\'_DTT.ᐽ|QR.qQry$fxM>nN/r''_46rZWm>x=s~qxKETwΜ .*䯺|_!"<՛|s>qw+'}WuwA1#_Dǣ\C"y_#QV"3+OEu"GQyem~E^P}їS>M뫿3h!G%"OKGm/:R?y*o>+S./}Pௐމ3']<ׇ%"J/߹j9;Ov:9`"|Q =}We}+y*Hm3؎Wx;;(s\՝N<zl:'j__SCiᵺ~&%"k_z|Wk&OEu(J+y Y>*IJ_Dr||_V"9{EȉxK'[@>c./"EAOrC [9"?]]5<0X=sq5iݕktzi>Kh+%"k?z|WZϔꯔK||Qzp+'y]^r_-<NjxXtr_EN^GrΜkJ|勼>(h+oꩼ>>S9~+#_G{z8=_WS^:GIr[՜ ETP OEE^ע\r?"9qr#w_C7KC!O5ךע\/GQ.qQr}O r?:8k5K*^or9`/Nk׏i=;X}\uQ!OEr߯ϪVNZ_㿪!"7h_nuQp`gN%"G9G/Ei}z_isKET(|SQ.r w쎗tG}kJ륔%t\tੂյr3uVjwC.rzMz=/zZ/S˃~J\ _uNsKy;=䩂;\uEɗ/|z8q܇密%y*;g=L$_0_?߫,NZϔjNZϗ|"Gx_NTwr<F%NZ,'_Rr|`뫃M!':b?x*Q9#͞ET\G_>j3YG |)y}\W/}ޛ!OާsK!J|08i=SCT^_)gN|)E<_փ+(I뢒#_Du({̾F5s쩨!WSQ}+\y+K.]p䩬}Yk]i=S;WmƙsC|G!_Duʥ~E_ɛWT|}J1%_SET\m|EJ(8䋨NO[9p_}(y$̅~E&J!N _Duʥޮw}/~Ѯ+U&(9q=S˞<RoETIrE)8I~dEI끒#_Du~WEzT^G\Wy/^.8+q:;N_)8i=_E;\wzr~ސ@JUUZ:|) ++Z{!__):-<9%NcIj ._}(8苮ww/=TMBz'y|Z8zE:EK}]i}go zuוZ8f_d)rCꐛ>_ _5jJ񀿚sUɑJ뜲>s_WEg{Y\hPAM9ē(wQPEDE18 AgdpڻPL9"ƱFhTW_=k}עsO{`,ooW^xy*?HTnE赨8a_ss"Q-%yʾW(D!_D9xE}W)/OՀ^/vKzCW1?O^%y<|Q9|u^/j_5P/qR28^//OU[WasKp>EwߏQ3o _Z.'gY^9xy/TaQ>gX_y޿h۩NjT_>9E<䵠NjSqҀ*_8'y~^/#գ^}Q|QmP/qyލ^N੪_S8>'tß8a?s~| +z}8(wzi<"ʗvjS/O92h*L3Q//_|ԲE=W%N8'󗧲s%NkA_ +NjE<_NjE1_\^9%p%_y믨NjS'9ngUa,<Ռ"D}+4%_TX^zCoNKT/Q/qT-Q/q^w oU7+%N,pl SYKa"ZE^_]_8(_Cȯ8Y]a9(^]%"N zxE^<`>)SA%޼< +Uiy_-%9(^O|Ҝ%ojy-f>^vx]E7)_y^RW |QcJQ/qzT5|zӂ,oF?FA_zC6~o! +{Cr_1ղNEez;/j_Q/qz{"OZ>7\8%xjxq}N|\A|QzU3o^vw"}?|"_TNKr^/j_uq௨8WKES//W/JʼtݔtzcJza|`T}a@>S/x'_7y*ZʽWNʎy*ʱ8(^3q"OU[^+v 獰oU[9Sx>w|Q_|+%"ʩƓj#-!_D>z<KjE% j$_Tßi>iAN!_Dy4OEEx-%z'HԋT">~e9y"kvxq*T庞9%N3u/ +8K)+"u]xqj|ZQY~]>^ڎU j{'"|>}Qr^/"QN4>g/'_> +CT*_Ó {;/*_KTS/G_dJjY"G-Ad +9jK]/ϪGxMzE1gES/qE%y5\'xyμ|QK,ԋaS(s +Nj3,i<>^E*'dz_i<"_?XNʎW >"~{SW*;W%y*ϛ_Q*)OzC0|K~"Oey7㯈CzizCrZHp,!_D9xT xe9"ȩ8(_qMr#mYNI,%NGOEyE xSu738 +~JĩIjINelj|-tp/*,_8jW$E6^&_dR/qU*8-x>WKN~~zC4R/qz'+Er(_CrE~;q5pOZ.E y+x~^ 瓘/O^?Hyތz}|Wx]/_yJ>^/E7^/N|09%NcgTWtKaJ_zzSx"壜^/|͒_S#_y_Mq$_PuKT_Q/q¾kR/qT诨8~)>Λz%"|xE䣖/zier]OE_'uA/2?vuzcuScjƋә7/]O +%J_W|P?_MS|^3w"Oy _^^G}?Ռ"NmI +RJ냽6^k/*z*%"WKvxnTK=Ϋ,35y*>'Q/q;y^W/9y" 8IUJOa?'pU=W9pH$J8񵍗\>jY|ԋ믚%Ɠ/r+/OE9_UEy4"_>8'wR<߿^<*v]E!_Ԛz<'w"_ԙ^B%"ʩW>Ee9ߩ KewYNzCrxn_'-z~ϊzN]?qޥӰ <¾.z;/^_e9=r=^zKE!8xB Ep>A(컲9bG"ʗׅ/_y7i?y> pz}8y'yj_sKfG#_Kq9C/q)#Q/qj=zw:TKڎUJ!_yJ>^|Q3'VsKEa烁O!_D9xT}QiYy|T5~;&O9 OEEn~"|Q^Għ^]HG!_T(^_r=/<lg-SpCPN4|QeWiA{: rsũSA'gDRg8T%_yp\|^\ {_Mmka/p;~*壨83zӃ|YNiy*ʱ8vK+/jHO!_7A%"ʩƓ/"4|Qey_ey$k-OUXoCSuE +{;bߐzCe9|7j˛%8Sy.E>^ɽ<ݒ_3}Q |P>^+y*SjG>^/OU[벜^m}Z;WS/\>6z}"ʝ^<ҲE]ՎO8vT3+Ex*Qaω{熋?C/qSu毊_Q/qZ{._9GE3yގ +{S/^/N_y^Rg8%OyY5| |%\s_UvEΰ9Eg8.%_D9)O幮Z&_D9x;~W=~S|Qaϋnp8Q/qvU3^E!_Ԛj8ZWޟB/r}Nx.EvzCO{a<"W~|Qc+ pU9,z/Et?98%ήjy>KEfWKC?w"_D9xN/!_D>zCީZzCxN7KE+0<Q/;Ue9:Z_ U[Wa=9>)^kq(_D +jY[3Q6m'43$N5b,8*=zәg-p?ƋS-x=K/JƏr]N|rSy>y$'_乮r]%U^|ܟS/q +;'OzCr?"_乮^/EgJ!_].O +%"ʩƓ/멖/"}|y-W!_D9 ǝn rtqo=^OEG1GQk)}Sx<{3~)c/oSWWԋu$q˱>}ߍ9o~x}:KS/pSy.z)'_멨8'1^/ES/'_DN/Wqۍ^Tvއsʡ8b9<^7EiY"ʩƓ|Y"ʩƓ/*:e9(^_-鯈 ϣ)<<rJNvZkiUoa%Nr%x-|u-a칮ˢ^/NiB\tzcE|ZW:3,E_׉{+_y`?xq|Yz6^ˎ~T͘ߍ^/"ʩƓw|Y%q}Nrಜnx]Gs]OE>^^E;G׃x[gyωo7䏣8?|.zSq.9|Qe+ /vX|I9<z}|'2O{>9 xım8y6;T͘So8k^ ~w~3_^/*U|u{ԋT +}zNc{xWOasnu\~)WQީw1z;/1GzWԋTxްYj+^`uPQ/qZE]>^jx/O^\^9%NcEvz}8RjE]w%~O8_r񥭳?PG|S3zz. {m|Ϊ^ܜzCKY<7%NĜ~8oNoy=kA_9^y{zm p8o/ruVW3~{ zUyRީztKϟ՘S/q5|QoW^䀧GZKމ|Qk>A]䩊a<_^䀧j*?w"_SC!_?H!OE9xEaXí~e9p@q}w|zӘw*Xky_-!_} xvx?Ÿ;ȩ8u9gy?+%N5Ob|QoĹ|gX_y^\t_Qsc7vFk[GO}特zfNU|{,g0g|}R>nϏfvGykz;I/q[n|E.^<2}?:+^wاϳ?`cQ>xd#~oGu(s!9sv+Nw{|f{ܽ74;6ǟ{/qHw}>k?D{|Qk8:^p?VΟKv\TTG=xK/G{*Á{_mqz{/qb3 t`y'qũL_h}8J,b%%z5K_S/q/XS/q/ϓm{/q/\g7ǿr%rET_|wr%rE8i]7K& ?N̔[/q:Iz3)^(wOW~K^(w_$N#Kqv>2>~8MO/^Ly^|n%rEonz 1z|V^.zy1!z|z;G"mK<%:G|EOn{0h>QN<Ƿq.;G|E<įQHj&sgS5:~޽Q{3:=:2KK4[O:!>8ʇש>uM|P/q/θ{}W{}ֹc>G9ym益8l?^}֡ʏg9/:4?~,wx/q/Xo_Kĩ|Y9G{*wz/q/f8w\\IQ5G&WnQNr23Kw%rEշ{j^('OU58E&x$/zFvٶyNo$N}y*w|g5OՏy$J|/*ܵCʝӎtO%~^4#=8囿)^⨗|Qqm[/q/*KM=y}{|Q|%N7%rE{V|ǏG9e%N|Qq{}Qua it*9KNcJ,z@ <7&IG9k;{|88E|yGĩ6͹{/qJ OwH1kްjCt[99䩊VgKv/6~{/q:橦9G9mG"q原z}+KSQJ7\_qS 8/ğOi0O%~}"8_䋚Kzݯ0z}Ŀ)^h)/Nķ^wkI#)^>1_4'$S]zMrG"qo8J~˽zH+zCyzC^ϭ"WVΟKTOoH^zH//+%"v?KTewAcy'}b'?"ޫ8䋪?3^␧*KE/Ͼ?^/Ӽ1̝9z\57윘?KEW]5UNE|eOq_u(*|M^]䋚ל| _O^q_y6۬K |Q6ևzC;|*wցWCmOR/qSy|>'}zd?^/<ݙ}P/.EwzEy?QNYsTGRN4|Qi{]2_T~}ęcJ?}|~PN']mW$~?{'./⹷dkK|Q'^/rW"z;iS[i;qO%N8?C/qi>Gz%W7k>*wwEʛ|GOEmʉH\Wspۊ`|^oK9oK=/8s۷/ޫy:G9;&= }8͝5U_u+Tʫjs4}]KP/q՟19>Xrh>[<^wz=W%n?{5OL9x&߹^N䋆GW$r<5PsKsq_$y{A+]q|qe?rozGg[x$4:d׬]7_EoJ>^(w_Ly/q4EWz#>}/8GS)o/*Ͻ2?}8N<7^{;G9/zQ&i>ޫ9݌6}/oUyzȉC8?SstSU(/C/qS>5k>ޫ9zM/j.k |Q{W/P/qV??E^h"z?;~|zJosJ=S9}xWisK}sEw^_Gq_y~5{SH];wC="^q!O՝yNr~{HovE^~/*9wcJo~Y?DשsOվ;!_3P/quOzSʫssE~?kuz z3wC(prϯzCމ<?~ _/_a]:GGW㝣y/ɹzC©M|%y&*wHy?Ix;GS)/d&}Q׵}?ޫ8G9{bl._Tǟژ?z8䋪KEg߯zC zC?;֟zC~̶믨9zSu?f?{8 +x}^wxxo_;!_<1ϧ^/Ԭ_^ XE1S/qSS^{5OL9xx0Hr?wO!;r_gxʽwC/Nʝ9>hsElxUn}8 |z=ed/>r_$NqƗևz{\S/rSU=+%Ho߼'7%y+\/qS^>O|_Y3 M9:gOEÇ|HęrTWNߦ9&MUE{Cޣ8.}}% ;>9J?_=5~[e{^둞G!IW#}s4E/U8?;W|%rEķ^(w_$N5ʝZ%rECԫxEw.u䋪:%^{37OՍao^L|TK.2>>8b'\9"ͳ֟zS<4Wsr|R/qtSM7SnQNM3wCnM~IUNE;]x`/.E?I^]苶볟R/qM-}&׷:G TI\/qSޫy}Q7ۿš^jw&R,<ֹSn/^)^}8wG)#wO<8ߕO}Ɨkz}8(}ΙrT퉇{|y*Ϳyo*'D9(}~ʉCfBq_4OuƻOG+^OnC^h"7|zHK*wN) yx/qn"q[/K)7O%~%_(^(wO5q˿x/q/?sz}8Ͱ8Twc;i䑨NjHz}Wtܺ9G)ozqރA/qSM?j>QNi3SuZ'~Kw_ikzCب^_佚q_5UnSկyI/%"͟z㾨K͚gj>rO%~ {ӏ_/R}ޫ)g|qW9q5۾(y:֫8苎š^/lޏQ/x'EqKEz"z3'xnzxzh}Qn>y*ݯnӒϧzӁ}v/@Gq_$Nn{8iRofuSN!_z*w>5OUNEպ%z}4~{]jQN%yr{5Oh7I/G)_>woK_I&}z;?x'>:G)p}r}\/q}K?*wrE'O|_|<|QK䋚=[/q/R^'x;G T\xPs4{^&y}os4Eʽ8Ÿνy*qrlr%rES~žp[4|y};qwH,^/u|K}є;徨7[x\̟8֫;Gi|.]3 m9geG"ͳkr|i|^:?/ӣS|Qz3_y֗\xPs4|Q6g^/@ ;8zSU'}5VC9Rϻ>1{:g|Si>f$wrO5q^p^9Hy?Oi86|Ks{5(w_[R/.EW:{5O/j^^/*ֹ%{}jQN!YLq_Ox{r/&0O%~Yz~Vʝ3<~^'E;;w^}阯Ss4}Q9M|$:G|Eʫ 7`̧^'i!wz59/}Uwg/?'gb>š^⸧xa^h䋺}8ڷS{}őu#G{*qϥ7KW/J_^wֳ4?ZqW㝣.|z/qI HKru_9">NiKC"OU>cquܛ:xr␧jKr?|QSsny =Ix=ֳYU|K/ϗwC|o~}W^O|l}}iz}9o+9z\MZ4|"/S:/T,+w_}dn|}~sU'"_ɹjstMr%(~1OǫϿz8G>zCzXGE)CS51_sEZ~=ׇ{}W?^␧*Gq_4KT=?Wssƃ/jnH{#>zاǿ;qx$>8E}qS[?^t੊-_}sE_|ʝ}֧|w^Hr;/S/q<>/f0H7;y*ͳvkw"_Txc>OE4< KUNEsG>U/O^[%z)o>ߒzCߟ^!OU|z3x{'V^(w_$N{M[/q/=W{8:6|p|Ɠ/s_r:az'wK/j.?FQHlA%Wѯ}~y;G}~t }8巯>5>Sr(w_$~{~=Rsw_$~廬{x}8w=3ǧ^稗|Q:_Q|Q§?^3^u_ߣ^wz@qwC^s|Qأ8g':G߾2Eqo_ͪn5{84~SsKƣ^(w_=]̟z59ݸ곞w]{8wEO|i>]sbru7Ouw1'z/q)^Ly*>3^K_S]{/q:橔7Vޫq4OTW]{zx%Ǘzij]{8ĩOʝӍtO%~yr/IkK}ӟ^fnYr >į[sǧGį^r{/q/{}M{=8g&*^qqO1=?OE#/{a*^| +T[/^_Ko^QHyyr|ze߹^]z\{=oxʽWs4E˒Vr_^78kTՋN<<>wJ[c8ޫ9[/q|ꇥz83>ޫ8gy* ROBI"q__8SnJ8#~S$y$/*zqw)#{*qCM>R^[}8w^Kq_}/E˓_?wH'ǧrUNE_oR'Sq_m{*]aʽ8w?*J|xh"[e_%9='w~^9O8)oo\'c{;G"qYK<_~z;HΟʽwJruz}?^('_4Fàq4|Q_u8ӍGEmsh7|A䋪\Kxn{|Q۟8u[iQh'{/qt?*wN7>G$GG9>#^(w_ԏwo6;1Ou(KE8_>֛&?{3拔=|z524TS~X(N㍣橔瞿js4E(sTSsu3O_8{'wD4^9re_3^n_~u\ʽ8Slr%N7' T8u_$~x{/q;y{3>KP}81ʱ|ƻ/R^8>)^~/wLr;!_}k㫳^/ٟg)uy%/Q/q|Ĺcs//z£^KE'loOq_$~}ӔSsn}{}Y|KE/%C/qiƏ~EO=QsLn4(;Ͽ;%Ts/uz_zSrǧqrr|Ճj7ʯjqOW7?6oʩ8i_Q/q_]wB%"=IB>R}8Ige2u [9{*qv}rOQ"?{}PsEͅ]O!_TWϯzH/߾{}?>$y{8ĩPs:yBTK~/_X}֧KEԋTNn_I z&|&3ž=Iy 4}Q׮x5n՟urESxr̡^(w_Wy~{w}Q77kOxuƻ TN}ֹ>/Qh?r%rEoQ_~QhgG%<ͷ'^('_oqa?{}֡xa'm%rEoiw1s%rEⷧ.?ʽ8s^(w_$Nᓓr%rE+^L"qK)Oy1{/q{8䋺O~ޚ&*wrE'ݜg^O/K4O^\;K.$|d[/q/\'OoQH7%ϣ{}8W$XK䋪{8i=v^}K˾SswO%~>;y/q/*;A_f_{wrEL׺S\gK)_ğsEwEa;O_G9^Y'SUqrE_oO(w${$KSUϿ[=ٮzRN/|O}={|z/q/<}تz^X/q:TT=?,+%rEד!qSMݿy6_6;7>KEga^ㅞ'7$/xwH<<'w֫q_է.8t?os1OuGNq4EʻxWh!{}ǿ~d@sHyO.Oq_$~WHgߕݟP/q=)}%"qOW9qzǿrURT|K6:^L|E_^'EzʮuO@sw_xh>ԫq_凎{g<ޫ95OyM^}m8bYH=랒[u}֡~cKw_4w<*y7KEW9w}Ɨ|[ѺN1;!_T_~Q/qS=5T7{;Gxs%^/ ߨO%y O~rz;i)/_u_Ew9+}uPo_Ep~g/q;I9xE8/%z[~&۹^L\i8oŹ:G'OUtazg9?5K}݃NM>_ISmޫus龨k>e:G=N^wh_|fxxr(wO%~y\^z7O%NwLJʽwJ~'8493Sr('_T_:G{E:W^//h/OOU=$}}z;>yU]|u֟|Q;~8'7q8Q'+X?~Ow=|>ޫ9x*CY[~lCt[Y/j?KE-:G9 5ߥu#OUq=5*'{*'ݣXf^Nt>19üVT=91S|Q}}ԫ9%Oտa3r|%ΔߴoKw/Nw/jɿ~Q/rS7͓z/qR={ǏGdi׽S9>/S~ٽJ>/~xyP/qio+/z6Hg8zݫOcʝS|Yksz3M-:Gڇ\_7kkoJyq|8O5|QSg4UREg{=8-'~zg9orrǿj~f{w/(彚'qSMoSn<ގխ2[e L +J,&QH”0cc."fPa P EEEJEDT{Y۽W~\^9]ڵk׮u~M9tΑ=q=8uW9'bA{S/]sAC?rrNN;fb~|9/Ut8S;aT^ԼpM@(ԹZþ"ݖ#_Łm8hy}b |>E_?(89/隸o#ew+_Qy$CesN6~f˜yQ}f|UN-3S |ʋwǯG;AWyQ=chϾs*YA'_i39U$ }_H|U^T)?p/qy೯ΩTWeNUy,o!8*/9jB_D_O!_.ʩ/qʩP4ʗ9U9UuԃgGE-Wq8/B=͇Қ?pN~uk:s*/~cGE3}W΋M7BWAq^X}^q8Bϊ/t]TVr:9/ݬ_*Ewc/& ]q*ʩo2ǧU΋POJBgtu~f>| + AS9*'.7:8 +z}2ECyd{i*75y}IHҗrC9UO'zwF+WTH^ "S _yq'l~H*TY/=s_A_'_W΋о}s3b>t8aݼÒ38WqT^Th:ss^λvnOԯ|>E/+Ež3:EQAM򫜯pN*o?jԵ:BW.=Qy8^׏~`_CyroЉtʩo;y}%Al꡼oCrE-r5uvzD^L74rtvΊ'88U^TtW]E_|Ͼ9ESG >s[pw6Y_wq^~(PBW΋о[M#)_́oWr(Lu⨼zꥃp^UONj|+̋hAWGE$OY/tQyQwݗYo.*j%~^29꟯U?=sPʋ?|9ǝt2Ag_Łybm{}ȾhɩWN?8}+_ᜪ#})wB8!韜/sr'pT|=8n4A=ݳR΋ih */jm>e4sG˜(J'О8hywwܿCw—9ૼլ|ў9Su?-p7\9fW iENt &_A=S^@WyQu8*Η?tUr^qGhϜPȩG7QqZé8_E/:WqP'TлO^?G2968kQrfթ;| ]qT^LQ9d ʋ)Ƹor*KϏ7 "/jٰ8UyQo(_ +rt}z:ss^4?es^[誸O_ɡ +?ɾ@y3/ry8k +z-|GEnUcº7—9-"g8RN;W//i98W_Kyïe|9/XN8AyQoyv?p^;3ʗ9/5w|,p^NL{Ue|9/rq=}ƾ"o? :*t΋)^xA?A'_Ł9U1$Uo98%)_́/EorK||@WyQ#Ͼ9Er*Ӡ/tWEݯ^!s*pozW lֹlB|R]Eŧ'ׯ|:EmkN9EkU΋/_Jȩ>;N΋?ʗ9s^lsAqWyQO"W'@uv|UyfIXe|9/BWzWSAww뫜⨼p^:oz?җ.̩<2㨼7X;E(Eh_3fW~q^~^f}'I91_*jt?P^ۋo5r'΋= *_ +zI,􍰹uM2?:E4ljξs*p:tUY7uV ;8 9AzY3np/]a\QNNQگ/NΝsUkt?yO?sgz芣 a:sr*Uo㨼>C+EeګŝGoΗ9s^NWqg_Łyt + /3 w΋оlg_Ł9U;KW.8AξzTNU\d|Ͼ9EhܸQ'Bgt΋/tnKy8Q_Tr%Rʋn'㨜M>|es*ɾhTs>?Q⨼uzG*T`~+}[eQeCxoga?Wq"K8"/q_EvW*/*Cr}DUS1kq}+Tο^63c:s9ϟ1_p^zvmYRʩʋcG{8*/r}+EV́/Eлg%WΗ9nS/|U^l/sWyQu[o9j.q/tPrk 9U^T} _9UXl8AA8^=})o4,w7$t_})8|SSWqr: | |jʋї̱՝˥ /ED[ _ ;d_2ի_?|+8**/t@WyQKM2|΋ͳ9*_{s⨜9s~WЙfrjn/pWq=>*|K9U7دǚCUy&߃|>EԨ#:*N/Sum㨼|ya_ԯ8*/*y87ߞ/so*/iT9T8z menʋo¿pT^|Y߯9S׮}s΋o͑6_*ʩOI^2'3g_q) +iVQsjqT^T7f;_/sܠ8/yeWq~QN~u_|su[|FΗ9/΋)/r(8WNS?ƛ[˹8SA/?̗홃~ +z /3eN|p/sz}{홃z8/BⰽAWqy@T~{೯Ao&E?oE{8/^QA{r_En {WqPO'r' _(_y"o홃z8/B{o@9ʋ*WAA:/sB{~'#/Q9/ +??[;xEz :E׫_*tpg*Թ[|ʜ#JWWqs^8Ū$_Ły '$^@)/ +Fգ}#l*8SSﺓ/syżZ|UwY|U*/<>?~@ +'tUSNՄylV@o)B>;$q8^GE{"/Oe}:Tu[N̗|J[~d99U;|"pne3yEK2~i}#lw|s*p˾3:EWć|>EoߠoC98w7$O]"pO}Q?ss^~V@缨\_ *t΋PgO|~)_Ł-á@uV8 ˾]E͕{h*N)/B?Ǫ}s΋zqЕ/syQ3̓3X|UL`U^{2+s*Sc:Bg_芣ny'p⨼=sR*/jiDWq8/jx]Ǖ/s{9C<@w+N7臊X~=s[6)U;S|U{ԣ5t+t/g_Ły8೯@(}e$ξ" kΏ|E{QyQW4|@WyQ9Bʗ9ૼk|sS}3ʋ +뎘|>E'&$ʃ}3ʋ;~<—9M'Ӝ +<9~WqP?EsOu|Wq`͔@W9{'oS8~y6b_d=|UNd9Sŗ:qyF\ߙ9^J/t9UqS]pT^ԾE 9+ʩPO)Əe_˾]EϾ]E䭓׿_-*tu߹)y}|Uvp} +fQI~}Tu8yڻ}ў9-Svయ⠽ʋyZ||>E4_o\?tU*/_VϾ _Tgd*N >T.4}5qdNE#*|9/ޜo?J(p^YPs|/aN;?~|#_Ły7vǾtWtQyQis: +ir*pT|=856J 2 ]q8/Bn7ZUFTX|"_(ytBTu6}s΋BH^|GTk$ ~q^NY{X}s΋ou5?+_QyQc(_}I?8*9N0:EA%SKEޕ|S+_怯r|UmS*̋VeWr|_2?U_b =q8ρ^qH:t8tI+_i^ߕ/t +u6ćξЙ_΋о+7+_)UNuu_/}PWZ8Wc}P|",]"\ϟЕp^N_2"݇د@r)ߠo#sCOWA{΋wLN8_\[}^q8/Bڏe"}^q8B5|WU/sE=hoWqT^T//QΩ;X }yFW:*t΋wkm؜Gcᰜ%m8#K2/g9~'ʑ:ګx}l"o{|~PyQu拳c~WrDNoGEtP_y Sy>~r*)_ ]r̋>|ϳo#w2R/r^ݗ$/7/2I+.΋ojr}3'ȩ8ow΋7ޚQes^oWqT^Txt ]qT^Թݾ(_Qy֛ߔ⨼-n~qϗ9'**a,GHNr'΋ͳ3fկ|GEg8*/k|"fe)E^~sy8-GÉyQ;xݶ[Y_wqNN/dtΩD8U^TeoWqs^~(V~⠽zԧoΗ9re_Ły^V89/ +/~U*k}??ś/E7~ ݑ@Wd4E*Eu 9U^Tm/syoyQ;/o/s&8(_+XqFr:9/B=_=)+_WN#Ͼp{SN{q;Wϋs*𫏯|~yE]VM/tÉ&8͖+O6ǿOLp^|U΋/>k,+EwkSr }̋ ||U&o4/Wȼ ߰Wq8/B/^fZ*ʋ&O2ɾ9E#||ENU~u?k~f_ŁyN[*t΋->*t3/X?yYE'þ3:Em~GL6+?'?_|ƞ|@6}'Sqvo9e|9/}>7 +vܪI> ]2TW7r(BArEЫSۋ rrw}s΋qwgu}T́/Ek<|q8z~d|ENծ6{?p^zhcWq8/`կ|fp|mߑ|>({T_~Ꜹ~89Uw*scUSS^}:*t΋<+_A{Ω/Z͢Q́o|\(ߑrо\:{sWp^`~x?hϾЙ]E_GUΝȑWyslC/Ǖ@_z񟳓;"k7|@z=}q|?/ܠQ "yk%9/^}bE{j3y7>8>Х/NhyV#9/YЕ/srv06\{೯@ g۔7|:Tzjx|*_Ł"I]Ee'}:E臦_UCU7=U@;|:ETϾ]ERi(_ŁyQ7"RyQ8 9ABW*w\5>u2:Qgy|:E>?Cg_Ł9@g_Ły|U?s*IA'_ŁyQַOtʩw~Ǘ|}Twϝ6⳯"𫛾Wqs^ o"3p:ss^~s;Sʗ9sNNWqQ9U{;L>*N;sNzoWq*/j|SwUՖ!ǔoSxW%oMXg\\o_oc?8l:=BgNr*~7ˡ +w}~Is' npJS}w&Hr! )Bu3g7~*+8y^^)—9_TV$U7 +jg +blz+_`8/:*t΋)zyʾsOoOq8/x[S +_GX+_洃STMѪ}< +w+^m?q8|yWq8/f|%r*oPrT8^?}a<~О}3_:aUDq?E^T\}| U*/*O78_WqsNU ^g"Oz̾QOg)D^4t6Ur^pg͜Q"+E{}-rvf|pPNNo+8*/2''_~_+82Z/ 9A}1~+NhOyڻwmO"s״@*t΋Ϯ|?E{8/ +/Z*ytq8/fT)_ʻzw̏|U΋ws~Aq^~{&}:T괝*t΋oj8A +vt}}PeN9>8*/j'| 8 ]q8/Bq/$es^~yߴgU^n#8~ws*/v\/sW;hWqsek Sޅ)(/^=ChϜNEh߼*t΋/68 Ͼ9EheNhobmY_zګ`]q`7"jc\8hyQǯOb>tU^^{:qTNUNsþOyQyQjzþǫ +bg{}Ⱦ9Exi/˜wG>Cg_~qNy:8]2**γW8`g_ŁNO9EuBrBgtS't'Z+_nuyڗ{?yE'_"px*ʋ_3@? ^PM([o$_BgtS}ͭeߝzCTC)|ʋJZ'`7Q9Ub_ u"Gb\{Ωtwg_\W%X:sIʩPOe| Q9U5a_ԣ8㿽*~/BǓx{~ȼeNyQ3{_@a\-wK2?*NhO9墉;C//qWyQ >*KEv]*tS~X\⠽ʋM6veګ\$_B=Wq8/ +`T> +}ΜvN+z3's*78OϾЙ"yʩq(_qq>ǺxdCD :79hyʏz^r:o--8t΋О9tU*/rק89/g_ŁS't.d=1Nyt΋Ww}F8NU΋BRG|SN~)u}s5koY2Aow7/3'ʩr'uo>0A;Eԕ.]}ϜVTɾa_Ł/o+q*_PM8SS_BWWGEyɆ::s"JzIqSzK`>88*/7_rr$ԯ|TTNNևйr΋)$ߏU΋q61/t@/)/ގy\(_QyQ  ]qT^~wV>|_΋Wۼ\_p\/s֥_*tk5>*GE6bN)/~P 9j%ߞes^?9_#|LBgQN0nl89B=?O)3R ΩPO1֞?Wq9b[Ͼh8S?8 9臚r*;Cg_Ły3Q)ǛDNՉ#r*Y/Wqy[h_"7F99/j?r+o-sX>Qy~wO"L_Ł98v]E?þ: Uv s* ]qT^̹ s}x.9"^*ʝT^TtϾ8.́yKžhΩWȼ?Ryӯ'? }3%"q~o93CZ?X:syq8B65/3U{~f_Ł[|/W94.ueH_O8o8~U#|_΋s{o=sо9T(; u.9S_c>|N=}y!,rP{6K?tyWh//q_*/*7Q9U&|GT屿GEWϵ'RyʋNGTϻŬ_2T37"Nq*ʩiFOm-_Sg}}a> +4_5ު}ssΗ9g΋)O8U^Tq{qD'oe_1?6s* ě.)?׬北 r^=Nj~pR΋xָbО./΋B{q`h}x[MnoiEN~uJΦ +t|U߾7@z6}d홃z8/BwA_T4?Ͼ9Eh'/"WN+V)s'_0mŜ׵Sʗף'Gq8^W }f{XS.!߉uoop^Sԩ|:e^'!˜zŔI~GhϹ't7p^o~SSr緲+9"*k-G$neƧR6_ +E8~~:Wq8=wدb?5*t]m>8O2+}E~' +|}:Tæta_Ł(Bk'|suWi?Wq~39^*_`x_׭U*/jz5}:T$߆ξܹVPN~m +_Νr+N_o98ZG2*_%DWqTy +oe]7uZ_Wq8/+AW[Ǐ] q"rQ/7ื"/*?$} s*p:_97j=+_Rw9U<㎌ыfYCA|6L//+ʋU'8C9TUrCsW~U?kʩwyK8 *t΋n>qLk|@wۏ;2>Wq˼&?|q8/B?wwA\?8Bgt΋SqNKEnqWBgt~%ԯ|GEԼh7).u<5:+.5ﺍRyxx-e"a쿯*|>EWϾ]EnKoq8/]-ϜS^}cʗs'p8/:BW+.΋q3Wqd^4I/sPl?@o/{AoesD^T?!t΋B?|̋8*"L?[8*/j.|K2*/H?—9s^ٻ|ګKEzϘXI܉s*[|*/*fJ*T?վ'_A/?e_(_o2r* 򕹓ȋܛ|u|7;u~%ty8ʋr|.5KGGE|s'C#j]E{$O@\BqT^]w82Y|8*/*&_2"g]qNyZ)yQ;ތ|3r:`tt*_Ł"C㨼9hw??/tΩws?/3UNU918SQ5ty8}ʋ7QyQ2s}+E}5G*TZ:|t8}Ǵ~Wq*ʩVeSE{_8"px?8r*;?-GkrWyQ[|qTNU}?FTkiయG 9U돏o+_}C9q|WqZʋ[:WA{?ʗ9s*G*ʋ$_RN{߻Ⱦ/@9z-| +F"Ag_w*jLRoyi]fN8 ]qz{6_]`/a7yWT:?~gs^7B:>sA{ΩN9RΗs'ԯzg>[]y8*/[.k|*_iE6|B*NI)8~8J/=0+_qKoWq08B4ߒ8um9=@gljWrDNUь틎޼|`8/^e_W΋|:?a_]E;ηGs*_j:GEnbsҗ.ԩr3X|EmnWqt ~5~Me_Ły8Ͼ>E}s΋P+9Z?`U-jk*_QyQu|>|"p܆ut5Voy庵o-|"ۍ+}EyQ_5?_N΋CzeS }ʋߋ8e^⳯@u[<|:94['tUS >*N)XUg_nZ$}ףRN#8r߬'N"pM|sG9Vʗ9n*ޗ^oy8n|e"<@oE^ԭ]#Wq7SΚ18doO6_6,89/. 5U,}:E4+Y}ʋܶuU9ʋʭq+_rj/s_g96taǿ̋׿}}W΋PGVm7syl>*tUrފHǷ|Ωc(_ʩw_H)y_; Gɽ%/tq~G +NM NsW?Еp_pE-|cΏ;tUu蟫.IWq.r1+GE:گ;/́^8kVWqJS/}+ʩߟ|U[o^b_Łdz6U7tBW|怯˾]EtZlWq(E;89/ގ"SPN{~Е/s/D^q}'"/>*t58**8 +|wbo9_Q9U#EQN:ݺ WyQ{ҘS|~C9o~}ʋ^68U^2~Ur*O->*tΩoV}%~T89/ŷ-w]`_Ł"7gaF b>8 9ΩK9_ʼn_pXG=%BW9/]7]_A_R|9/^ߓg_WU|՞u )Gyz;tÉڏk~`NkyQk~"kz8/B=%@? DUooā/EFz89߯7xCWy8խmyEt82 |8ӌ{8ߝ8|U΋/zx;kH_wq^4??|"#8ʩ?t"Oz*'/Ss+!7WGtUSS~7C/Wq7㔔SӊW|~|"pjϷ+9"V+_λqr$Ut#w?' 9{/.<]*/O@́"9>sWyH_E#+Tv:}Q⨜헎s ]q8/B=}ў9~?ȩꧮ ^þ +O%ξ߂"p~]|~"WqSCr೮8)GBrt|*,C|t@?-o__jC^$qwKi~\pH8 +VWq9US^~K'tUɳƾMG i7OPW<Oߨ7z?v9_ůi88n<"+t΋N@|w=9s^~M'O;gpTN?_rC9N=_88g8q8Ɇz;ϵ_Xz~Ǐ~83 /+J|/#78|:^qq FÎú@#3xq6}F)ms7[04<s- B?߷_1{7a~k_#O,~;>ks|>/Л牯8`ٌ6OK|a8C˰_q08g/-NO!ΐޭV~ҋ%AbYjti =2KGz;c54KXjݯ~.P{pxq{q|=ߒ^tnYBjt4~|RWztiG#/nNKon=8}pj?TgT@>nz=85 _5~=8y?9T:aۣ(G~G=1n~q{p:z59_?q=89c ;P{z=QgnzPq=8A׽=Zj#Y'}8}ܰ]h8P9y    LayerElementUVI f   VersionIe   NameS map1   MappingInformationTypeS ByPolygonVertex   ReferenceInformationTypeS IndexToDirect{M  ~ UVdf;  q xTyܕ^IiUh}ILd + B"-E)ڴJJJ&ZKY|~_;sfsscr*1& Ƕ 凁~&ln,l__q^}PIl a_-'}[91 / +e{ n vG}_]7.9kC8|-`]X&}&!kѮ5>f=\UYo\!zFz{2>(|]E)ǠΟ//\zg?_9s..Пyja_Ih}Zؠ0χc/<Χ ^|~ e>YbYϒ##/m]> /+.' +F! l^z/:. + ۏ r1/;j.W(No"l++>n >u/8!xn9N8k! sf/-/ںKw^)a=?r|'k~|~e>YdYoװ!K ۑS7@7O 6 +=nW?K8>U8O;QZ,O˿S/C8׫O6*Sh_דAԯ$ou8:{]O8Eyz{1uANYi= ]_tWlX_:s݅9Ya?3 ֫8;a?ϣ>*l~v-a?Z\Cz~xV?|G0?\|O9/Yoz1%{|yᝑ ːGk\| ^)'"a{ց?~K~S=u@oj >a<>p4P8=ZG;X8rm_awJWp_?za3pW0;wpufMc_%t6rzOkqU# ]b!򫯷w:~Z|C9||p=̏͗d5AFW|'_R.]$_#s?f.g_>\ayYǒ|AGh{¶_Oyyiп|J֣z/ɚ?73Zei=.<#S$naר_p^}ppS{an߭u'Xp[\oY /a[w^[.>;LhM؏{?a~TGzk6^᮵AO[)i2`ۣ䝯K/:8Yחjt\ܟ](#KZ +'fouKΏ|7:_|8]O8]/e_2z.<JUX3xp>|]Tfxī=~P8?TN:}/ 6s7v/e?w[ +H8 .a.|xf'NpYK{zYЮ.< n"/;Kŏg|+_3|Փ:ݟoy'NZsV#_T<7L%lZj|{=_g`|zJ5ad=_+j,kֻp=|eI*9m=׏mK^;n%+jih7Uv{{x=𬰭w3{x _EL?I^3ϐv +g]kuMFu?`ohp zA {tpzO Q9^W^w|Us/GAg%\ ݿQάGol> +fpCvz~y:|^c=zW$_FgKZ/j=]b.aj?\/~C\p{//J㈕aϹ1hwG*k67$E8$h'j vy$ר$ly=z|g~q'ɿ9V8|՝O cf {]oq)'tMZSؕCҡ {g(pzsvyEǏ->$? ?t}~˕-=<[<"K GoڸS|?y~Q|9??h~7i'i|j=ߠz2ZBB7ai!g_ ~|7]y^qW݄m%Tp a[ +m޸=F->h$JFE0TF;&S' vVK^'_=~է oԫ +W*yW^Mz&?F R~=(>h?+/?!Ä7 gݿ=m v_#w^$lƠЮC%:|̇0?y;|JO5QQ_֋zZ_GTatԓ'Wxx{O'~1 A76'~<}p9`7Y8݌;I9^Nj]BKfHݟXOx7XkvY~ u鹭o yzm3uQ8#F^?Jx^>p>:>l/"t$Ic>\8k«O#Z\mas o–r<^#zJuߨ 7_zͷz2N]|s1w%~xpd]}|| >W!Ϫ[/v]E8k8c|ףޠJ/~Kzh~+j3Bw!g{|o ~wvO(~x}܈ϯ˾⵭יxyhmL#UĞXSl@ԟSo!*܌: G%]}\/tyP'!ҍ tEW[cP8~+X<Z g}^ϰo>9=[|D]t%0i_m9ͯz1.3iֻ9׏GLjq`|?*"kWO>a{TxNkD8N,>6aPwsߒ羏}AI|4b|?>{pb nZ8h/aƋ] +ۄuXO8_x5Mbלk=̵wSJ?MWNZďQYOk\/o4BNO󫯈Q5'ݿ_1G8k}!eP???&D8y~V{qN;ΧpzKhL/A^Fm>.|~<ӏK.~p +ϻOw_9OX,xć4`u;ܧg#l>؞{]w)a[>U|JpP| vOJu?|2 +U(3v+ouzv#uz] !`^y]_8iߟ +;Xii<=}؟?rY7!Zp[Z?'wZ__7C99|yOt=FcuW0V|P/;j=?z>?|&_±x}cOFasHyI8t<~"o}N©ry#\u?]^ apދ%k-ͱVR~L  W'??axδcgoXOn~pڍ +ñxgw&Fu +upzJewjCV0=a𼡯w#t|O ֗O?=mjݿ;ypMp=x?Y?|AϏo񒞿p=ϞXoI~~ +I"|j=_oz2ZQ|Y<ݫ}̌2ho<9 ߝNEvUq}q[sVH[E-f<.ש ~J|]Lx0y1tmey>o| x/#{S[/4C/繒7C3"QuV9{qޒ|~?e>=uZ<vZOk cIqV#>P]8oo·v"]c!ﯿ2X/Ha35w,:QÇ5q`\,ɿΘQt)Z.rk1GR+N|X!,zx?x7|!|YwدY P3k{zg,ǣޅsaw\UUsS|vMΟZ7/PW|H~s쾸>ܪEY&7]Qwa _#?iX7]χJ|uot>1^+Eݯ|zY/wz:.|~.y/$Mo-*o?r<ᮚ)k/JO?©]->-Y->π_?W±fKyaoxaW-i[^f^9]VSؖATeja<3؆žGz5`7==1mq[~܅E=᳐^@[ۅֻ|vǓN^_on #E?_uaM6C%Qo@ر>/_9|9].ǁ' G=\r~ڟ8T# zeY؏ݯ|:G=P/3.|~|߫: ?/VX}>C8kU!"B1[ +vza_VGGnw]yCMa3X[;8_\7 ^F-:[0{V!w~j!k +GlGoPTz7 yozW +ըgL]x>zQ>aVŏi#7|t}񱸟[H??ta#$A㦽)~35nZ[=rctz-K~uVXͯz[i5F]\mǯ}̝_[r<_eą][OMǂ}cgvGepc;<~m],aJwWO>^8U)?CVNv2۞=3y`Za>S ֓_%7^Uc{|?Ƌ_vKa$/Y+'lE ρL?؞>sGקqC]ހ:8#~8]7Ao=4 ݿ>h}RwKǡCo~S8{=ߠ%=eGDO|;3_j="4.ܡH釽jn9!_fMn{Ѭ9׾+>5*>o4{U8ލq7jwy~^䕧‡˴&±DA~j_\?B2?Vap|yZct4֓{C]7>w +|ىز^Գ=G=rkKKWgnN8G oW%\_MK_#~d?๾o=^M|x^⃝qp1;| |`}:uECf5?©c<_t |ck=p=ߖ)= ._<Ou rW_u te*x]kvplXonvxqFK7 ?\ƨWo iXE (i*>m17z]x`cK5ɿ'_ >h}ݚO :^:|]z5_/iXoPZ<O޶T~H8}n{b"^#>2n.SdH9%9x ZV?R)|.>s>B[2'J1V85NV9\Cpu.Ƴ#G1_XVXw_v Wnaw#gJ~YauP9lU<~ʼ)]_j3T~75ҩq?zݳ~_Z_YY'k~2~(ィWbi sɯ,lV>1xJ}G)~tO1q>_F]!NV?Gn@aױ\/l3G=qtV\/ G>_;<$?|თŏL^s0E|`=n`[\/`>.~\ ~#~^؏A򧝄,*Իv^σ~ì:;ޯ~yH~ɏGj?p>y⃩sHכC<+|Iiku<u>z||5~3g߷W|T.|~.-.[?D&M;fKoE[[`<?? w|=i) {Nɿ^ׇ oďD>)z/;ŏηk+vam1Oa<4^ɷ=ovMQpv=OԻ|XǨ~mO> ~Ͽ9Əo8e\?"7 !q彛z7 7Ɠq7 [?Vχx~/;/k>B'j~hiv߻:ߴ ?t}nS+Fiuݳ~e +'|تb?V'|IϏjh~kj/[y^5i=##Ω+.,~^~G?חK-;L| 7\ +?#Srus2C|/\' jqZ\G] >0>>mRq>sGC4a"G5G@8m㙮|`!zo{ k_T8<ߊsnQ ++-Qxp;Ի|.xGO3u~3 +OJX#}_0?zabn +k}C3s+Kwj?V''=?xi>[XOI~>z~?M 24߁dޅ~l.b~1o&-~{* +ۃZ[$ȖpϯxzSߚ.׋4+Xu+4oaSm_?*~e}K{㹑ď S'޿5z/?a? {u7*%}^؍F=ͬMԻ|^G_?CǷ6AO?u獤3MINNf?w>湟|\~b_w C;G9nx%?\|x]X]/et?Vj>#j~|kQO7ZcZBk|mqb Nm$%~yí{>? ˈvM{-Gy%5:W|oC_+g^i,~CO? ? +&>/*|Z5}=0jbr¾'ꑺO7^_u;pnP8i8M0[ϽSm_ŏ닷+~pQ;^xݟ}u~T_!i}IA_g}?aCNz~^]8ߠ9=4F5?E2~O0̯hiը>y_?!g[?zb<?6TOq"SJF?0Y:_͇}!nyE|;yUspju$ _{{d-xU3~]1]T71`fV&دUKQ>{jz6za.z^CyG NW ?>?r~wP#KďOV~j'uݜ֯ +Go8' gpɽYk[2_˚)ɏ7a?F^~j=װ^ozj;Oy?_7^n?+WV0ÿV?G/ ?ZۻZ WMcCXYG*!NJt:_s?L  >1ߚ_\/lmuLCލ;a{ Ýy2g wޅsݖY!~X}Y8DB[# zA ~$ݟpyH]#ϢAgT8h}Ji ?(|YϏ/3]pWKh~ͺ^͗0F5V둘_|P }]88Fp݇ +!…@#= {Ι%ym?;%y_Aiw1=V*O6{prSk)C-!4Y?N| a3}Xpl??7C0OaUW*ΣK^LC~޿|}ɒgWV84|  _ቿqB]\?+ׇr6̡M;.Smϊaq0'xn$.<ݿS|Hqi7> ~n?"+\Vi$(=2FضE=ӜԻp[ʏnv񃯏#ďOA3~?O5؟;}g$>$Og"ַfo7vz>u:^|O>M׫2W #0w^Lj=?MA s]n?bEh_SM0Ga7?~kf1f}Gxo~,:)SznGWćtȻ8ekYYŏSo]/,G\->zG^ӹ=q?b^m#z2yzﻃ?z|.v=_ŏ,~Xac~C֗:߭$~_'| +Vh}WGt&b㔳_IxV|Nu=At^et?y&tAG=r+7Bk=#ȿz.ې?'y[|踏).4!>6\jk?_)&?UIV<03Xyjz]:¶?&E }Q p /w{Ǡޅ- +g{=v̟Řߞ7]p5>7u_s{nUn"y/'gqz>y\8߳ =ߟ 3Vד5?v짐 j=4y-e5e3}玨w 2^W"']us%[Vޕ~ W4Y\B;o]9|81Iki_'+\g.{A|H?3~g9pT}{s(8?zq3tϋnc^aŏxz|P؃DL VVޅp`{nXA}C_u8,{b~3bcď{OBɛۛk}M^d_Lǣi +ɬ' 'z/nz}|nXtV 9o`>C=hKwz.|~<-GY>VS#FÏFV:Kď@ra74y՜>;G%;b{v!ݽ>b.#w ?8p+(Gٮʘ/'~MXk9N|oc,>؏9p:|C=x2zM|Py)?!~D}}|D#錓; 볿|!~[~W5I[|p<09#v>h |_^Ϸ{O?|ߟ|D]O~OB|*Oş_t;QuZZϨePni?NU_~.~~ޘc.c>}oOxya&?TX7x?j!;Z^aӻ\y+k+j;^&߁SGO]G_G^&~{0_Õ{WGaA|V~C8zg^{kޅs=/?__aKm%~x]_y$tB#L(y3cs$Y*y½OOD{iC +!f8?zINjz^̇j~Xoft?I_ͧ;G ;^P .|~.>D~: +K׹4?L+m@?*?vWG_V/')ߛN4[&JLFJAÇWZdNs%}-Nq)8}~%Z;\?>|+c=qO|zݢCX;7Çد +]>Q^g@?v?©byU=Y\=?^sckÂD~XO\~oqc)>?_ϑڨ_:yr׵Nv%.lSŏ#~]^c/sw)ZY$A$l:w=8?<_//i>ǴG~/~h=7^z%w0 .|~^ʏi?¾Kۛ ??'k?[î"y*ÔyQ|yp?a7qJ\/ >v!2ޫS*^?Nz[89~xѡ)3T?#XSCTa~ȧć8uG#ֻy VǢ/^F –~h{,mϊI{/?~U⇫m3*˿ׁ'Xi+l@}s߲iINϧ{?vί{@fη>2^/|~GD]oft?I~5|;[wyG1>,+~.C⇙~pxx][M8%ϽqO[؇'J~'W_Q|˼0U[n=Ի|^ʏ܍rpzqt|cEy?7[=`m+IW+~JoG} +%~߫¿k}+. vz>d{6/WDku|_NS+Y/et?QtVvN^>F=ie~7yO8]ď)&??E&K~oӆK^+rz{Z~E·tуG}X |ݻ 'q.OMxi ޞ ?{A$ O f_VI_p7#G=JnV^igpz K>? #p#N?\w~$]kajcGŃJL߹ +OMvo6o?i"OT +?I{M{xUpi?0?|yOfد|GW|/P~C ~zҥ9Iw8!>Wm?|b|b.9DطA ;,G<sGo ?t}<í]w|4=4MHÉAS}8s~N\}u5|`S|-Ϗ| '0#zp^p{ItzoXz9[i4N]>/b·bN?bJyb(3[&ȣ7W*šRl79^0ח[WooS8Y _\;J4>t)™4)9Wbs8_i o"}~^ov7/MjQØ;JX/՞t|wGRl<9^0T{صߓoe{8RåPRʮ+Ņ(Ņq%^R 9/d ϟB/dB/dB6 y_L_ȅ|dB/ydB/dB/% PL_L_L_L_2}!2}!2}!/ K /dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/d#2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2})aL_L_L_L_L_L_L_L_L_L_L_L_L_B/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/% K/yL_L_L_L_L_L_L_L_L_L_L_L_2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}I 2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!ӗV_L_L_L_L_L_L_L_L_L_L_L_L_%L_L_L_L_L_L_L_L_L_L_L_L_2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}1/ K /dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dbߺD> K /dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/d6, K /dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/d+x}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2})aL_L_L_L_L_L_L_L_L_L_L_L_L_ {,L_L_L_L_L_L_L_L_L_L_L_L_2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}ϖ92}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!ӗV_L_L_L_L_L_L_L_L_L_L_L_L_%]2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!ӗV_L_L_L_L_L_L_L_L_L_L_L_L_%t|/2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!ӗV_L_L_L_L_L_L_L_L_L_L_L_L_9/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/% mp/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/% 鋻nB)_L_L_L_L_L_L_L_L_L_L_L_L_JX}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!?]!/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/dB/% KR)_L_L_L_L_L_L_L_L_L_L_L_L_JX}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!ӗsU;t^_L_L_L_L_L_L_L_L_L_L_L_L_JX}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!ӗTcX)_L_L_L_L_L_L_L_L_L_L_L_L_JX}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!2}!ӗ|QE^_L_L_L_L_L_L_L_L_L_L_L_L_JX}:lb}ۃ݁uI5&XX t،UlQQn[ǭbbw~ᆵsu\sϚ:] /hxA ^4 /hxA ^4 /hxA ^4 /w /hxA ^4 /hxA ^4 /hxA ^4 /hxA ^4 /hxA ^4 /hxA ^4 /iw /hxA ^4 /hxA ^4 /hxA ^4 /hxA ^4 /hxA ^4 /hxA ^4r-/-/C-[_ׇnya~e--/̯k}%߷D0~߲[~}[^4z%[^X~z%~ }K{}-/-[^[ⷼP߷oy^oB~z%~ {[wH >- =XƷ|x^/-_z% >P߷d|{o/"B=P߃m/` =XB~P߃o/` =XB~P߃o/`rCyny|x|//_^ >s|x/^ >Ez/-/ B=P/s^B=Pzx B=z/ _깿P/sa<~̋t > > > > > > > > > > > >Ezxny^zx^zx^zx^zx^zx^//a{JI^^^^^^^^^^^^"B=HP/ B=P/ B=P/ B=P/ B=P/ B=P/tE^^^^^^^^^^^^"B=HP/ B=P/ B=P/ B=P/ B=P/ B=P/.wuE^^^^^^^^^^^^"B=HP/ B=P/ B=P/ B=P/ B=P/ B=P/vE^^^^^^^^^^^^"B=HP/ B=P/ B=P/ B=P/ B=P/ B=P/+ۿx"////////////hxny^[^zx^zx^zx^zx^zx^˳vE^^^^^^^^^^^^"B=HP/ B=P/ B=P/ B=P/ B=P/ B=P/őt > > > > > > > > > > > >Ezxny^zx^zx^zx^zx^zx^/M̋t > > > > > > > > > > > >Ezxny^zx^zx^zx^zx^zx^/t6E^^^^^^^^^^^^"B=HP/ B=P/ B=P/ B=P/ B=P/ B=P/̋t > > > > > > > > > > > >Ezxny^zx^zx^zx^zx^zx^/^ՙ|x|x|x|x|x|x|x|x|x|x|x|xAËt "B=P/ B=P/ B=P/ B=P/ B=P/ B=0^v}3/-////////////Ezx^zx^zx^zx^zx^zxa<|'[^^^^^^^^^^^^ /-/Ët B=P/ B=P/ B=P/ B=P/ B=P/ xxKg^[^^^^^^^^^^^^ /-/Ët B=P/ B=P/ B=P/ B=P/ B=P/ xxY|Tg^[^^^^^^^^^^^^ /-/Ët B=P/ B=P/ B=P/ B=P/ B=P/ xxμH > > > > > > > > > > > ^[^zx^zx^zx^zx^zx^ܟtz"////////////hxny^[^zx^zx^zx^zx^zx^[wE^^^^^^^^^^^^"B=HP/ B=P/ B=P/ B=P/ B=P/ B=P/̋t > > > > > > > > > > > >Ezxny^zx^zx^zx^zx^zx^/ݞ̋t > > > > > > > > > > > >Ezxny^zx^zx^zx^zx^zx^/w8|x|x|x|x|x|x|x|x|x|x|x|xAËt "B=P/ B=P/ B=P/ B=P/ B=P/ B=POX3r/g0]㿮7'.zޮ\͙t=X~~tKn޹տg2_9y=,;g_e5>~;Pzawuu'hUz}7Og7ݰ鸛#=y$mM7gʼ C}|_ڼZ_p?|ַǷf̓??65???eL鰵7c2u>J׎FWZ메͗CJo~E;o T?xuc|v=3C\Z=rkm4u.^ʻ?7]_}}<֦}r־z΋[ #կ<ɦk3~^:_y5OMr>t·֗tX_`</r↑| j/utM+d:嫏\|t5ηfn~eZ]|h=ӮWOCJ,x?QV?+~AS,ߕH@zdSҘύ5Kc|4ZOx|0]k?u7;hԏGW\ +~r3>}PzР|ӌ1>KzyveޟM'w 3ߠ~~V_n&N=7y{`|Anzxwi:ukQr>5ZBӘRGĕiwǍB?.ȵz}bO{?㜇^ߏGOe|4Ok`7c7v>zM']xH_*qGwD{Q6Gp>u>j_Q|Q_znGd=*_Y_~#T?WZTC,?m7?he?tM۟q>gu?_I7noz-k|0_=9֯[ZOX_o^|+h?q̹G|x~4aVsgQĉ^h|UNw!k;]v 4t\,ng9/՟,ﱷ/q7<|.:,]W?WtQ׫S+?QmdbgW~+7|/P㣼~*ӗ;;'}}Z la:ՠ-;Ƶ5իJԇjA!jp㕮up·e:kai-aZ_پgtտ*s_suFuJHy}Qc +wYȿ GYtLCz_i? S59t>b Ga:_yv~{PzLy>M^LE7u^xl?_I!E;Ecv2>lXS4>yoGb:<.0Yx}މGϟֹv5j/|ku^ˡW;Oc_j~Poo-C/͖u>谩η|Ο5Gz*+k?Y3igoMJlFv>!wjQGL7|=y Y*f7#,jþA]l|>YpƦW/8We FU2>j]/?:(ZO|?_ibӌF~Er^.?G/9tu?PLg1z_4Oyߟ.-T΃_1~~YkΗtY y>֓~hՏ_FwիW'>B:xj~~7/W|V=ޟء~`6ÌBz\f|DIכtHp΋zxx?kJWs.g$y'>973Lo<4da_?^ _Xmk'}嵧fF㡨:52_ ~|h=zW~_~Yկr~=lwݭ3Sqnn|ԯ}`:Ttcw5]xCϰ6~{w_eG< t9d],ǗGdWӡot=4^?x?_IQk|^tfpQzhp!k +S?`eՏyUM7g\΋4H7m姣~Tc __xW|_R]ԟt|8Xߝj|>c|G^|KɇSȏKȋOMgVP~U)ߍRmJTowwh:l٘C7Om:Nq2e6IoX;|꾿-կt=n~+6jOcOwo:+O+0y?4q5_tsb||=eMZo񑴟rG~8{5>to<w#/qPTtC~G1]Konc|2_t|>^~}&~-<+)eKg9_{G\I<90ghL]Wp>t?\|xW)\J3y/_yyqy{ML3,t8Bh|zz#18yz8/GzC~2Boo3~?Q? X+;}y'>1͟d<]5w__=q㡺Lm:Nu=_v_yQ5s^U0|·>|tΏη|YuFZOP~/E7O#)UϠ]3-G]63]y}o[矏 ^7ǎw.<<+,m忉^=wuw^=t>N\t:-[m?_IW3\/c|W ~Ⱥ^:k' {7rF~iMW:y^tVpg3Fa wN|dC/M7C1b^z_{t?=_Iy8}7t4u>c|FW^FIZ/OP*Q>Q)U)Q T^wYѿOXxo~Bˇg<1~? m|\_b#LWGnL/O|gNtI͛p>K^.:?G/A:]!?|i?i T?ԯZJGh󜇷uV\ywCa{]5]}91n[j: ?f{?۷n>k5M7O|{?_IWƯ7HwU70>a|7񐴟f=R?'C鼨q9\!wkMÜ7o:j-F/nh}9?|<҈LF[g.rŏ8nyoX!cMYK˻ަ}^w=,\zXZLwpv9w+~2|\z:ֳGz4Oif1ݨ[=L'95>W{2 Q~\`!|ețG!yk\0y WnMg78oc'EϷgΏW?߬?s=#j=z|i?߬|6G WPJx=؉f͜EGF=MV2EY彙 c-t`Zˉ .s1n~_ݳ<~1Ӛn:}r9f:?gt?Q1CJ C'>ˇÂΚ??GZ_>[Zz#d_ihagM'' tt>8y=C}:*:rQសV*(/W$gg|wEMn˦qY!8.CGF_ŽÚ/:+{,_}B>~<|Ѧm1e bJ{?40͌JFY} qGӑ/j#}iWGa6EjNWy?כ.wn'>4nOduxÙ;CIϬjyc}qw_ӟu?w{gg7P=LW:t5p=G>Zo/RJo~%廢~wމ?F\n<[rڮ?]w/$!|L'od:>\,ߌ˝uyǷlg~כ7.2]r^k=L_>u>v@ף&;C||8}>E^k^9ﯾ4}f3^j~Qk??,Y LG#lZ +7my?mר~w>w~aݟ45XʿuCaYދWt[UoOꟷ_|{,票yAgk/q\/)(?Y%_"/,y?Un|G3N|P?|?eCiL7}>.W{=[x&{˜s? laS0j) +!/V466~:3]5Q=tQ҆s4w絝H/T_߷_|h}M?=8[>\?gFKo3y)uW:t1>|kW(?ȗ' Qȷ(~Ig>*5C3ϋ8/iy1x}ʿ\?7keO>ny1ݬpͿo6M<|LGtʦvk +~>Ya5EI}~X}?_i=~ntϓ[~û_xՏf^R_ͽl}GwtWl{8oy}n35J Ž&8/Z\O_q]Ͽ_vk'=|鰢7c[E雏^:οVO>ɏKOTo@T?*~%廡?-r=t:^%r}O7v=n4t屙7^c:a>P,q<۞|0J_c?_I=p&kWIK1Szk ~bM[}qWl~CLSO2fL=o_ʠmF k|l:ZW\͗lzZGu~}!]g~V;^w?]/Q#R]Ϫ6e2?jy-a3=}=/0]O׻Vwnt>4>|/]"ZOU(A%~( RYQ;Q ~8!ݡO8zϿbڴj<>N=y{ǚæ7\ta¦Gzo<~7V=?L3>_^Q+V7!Im.]tT3QC7>jYt]JplpWh;56 ?.~?C5O幺yWJ`:\ps\iKMW:ti||5_Ϻ^R>*$͗Cھߠ|fVW|T݌݉㱦㳷[Nk41yUMW/_.eNy{('-y9/;zeMǍOvKe|WJ ݷw^KC_0]jȏ64ԏV˚g^`ϫokoTt/]I돋haq}[{.bOXV⭵a棜??tFjOkoο#Q~J*_V[)I IjZ ~wBxަ{ރM !4͛ǜyeGLv3]]sRފoz,qXfz~^:t::ᢥM+t~?4>9Ț/NZOz[!ka>ZM=~ L/gh]㣨AF~^KM'_?CׯZèLg[ILgasLZտR| Q5_ZZ/b?hԯ|'Rw?z͝X~k`;>4]o7Nk:v}|5n5]}{0_ts:ûs.u䇻^r>v8tZ_'q wZ]d|$]/M3yz=6]kC~B>W{tCe:퇺V;^{=_/oaUiS4~u–Jk`:\s^hOfݿ3՟^,_ڭot>i||.?JC!?֛/S+IϠ~d~EϝGzleI푦8B߿[ڧ-OLWq=DAˬ[Od:'61g_qd챤Or>6xx5_u댇.=|'F+#RV?qטnO6\gfËi4V3q~t1{L_sw{A'Ώ:_K:W)I멕~ȟK>[_w{W>d߱~<߸i|O~'<yL[Fz(Yf~TS>7{C_}c?#C~֛/φ~(Q*w{Y+AnFwG=J#~-t՟66]ߒͯwtZUwWNp~Rٹa6޲kÜK^槹g6?,]/;~µƗ}EC_zawJ)i:ja|~?91?kM'?UWZgT;kFq~؇L\ƟM |}ž>ZQ[a~RҦ/ [R6_x:ߑhף^W_~߬~UwOQ;^wt93?y_̧;mw}]{oOa:ww>09Lgnۋ֯>o=tk,a:?o!njJ:ܻ?4>P4_5ioӑ=?i= Mg7?:ϿOZ +%W;^ ~y];?UO5ƘO}W3.>Ӎt~Yk/q~ZԏүDϤ=zOY{;q9̯[,ay(RY^϶1][Krg?[ǚ_92] <&.;NY-P6jYLsz宦7 ΋֛V]k?yM}7=x?¢7k)k`ӕuѵ,I#LW?_}~`}oayͬ0o}=xw׫q8O_^As~|o|$֫|%')A@?ү|7g.'Z^_=qxԳ?yڋL7 ;|L Ms[no:9t9N'鶏?yө¦ӍL]uOwƗ} :y+V2z*[+7Yɯm|hac{~&[޳rnxӍ1>5矹zW~~OJ +wV?K7_=GY~M-g^b}508쵕9//o\ߛ7~?IǼcnoU9'y`}LW M4AoOc|Ul[Y_ZoxfrO0߰U _qF;Q˯venh3LW~׳֗}ֿ~oVc~fF WayO_:/w|KMW:FuuJ!?KC/KwP?O;>?<͑74t:mM.&}\j%~Oy_?O,#O??ϺtsPH>äLE4]M^ԋt\0Eq]MG \/ߟjK_k?͸Ϟz5Ej*GY!~s;>4WWso}Wk?7R+Oun{{caᦛE|еΏoΟ<(?7)__K~_=s/WBҼZC|/^'hm~gP?/*Kz'wgΣZiKeɖFuou^Y<\׏#g:y1x<ۏ7]JA7>t|˽'A:9ŵt>N菝]piStzą\S?3]eɋ='x6Ǚ2@T r.=YotO9tK=Ұ+7yxp<'?_aw;e]vI·c]s|z~~I?/=:UMoy^t5.s]rbL|{O<\_彙xz/L4_8-9?ayLeGm:k|^r#ך5c:j=y]kw~ҷsn|B?'Lg:+M{N|7ii^5M]BӍ/` +_V~?)_sW>Z3y>ϿW-PcO8.i~AG+/qI#ޤ|Fl&+)'s;^޵7RR'ٴѦy~Ϗ:wyoFnj~ύKt;{ ަz޹mn)G]?64㫟3h5_d =O3zMG'~P~]G>}Ͽ٬i'N~jIo[?ߤoY_XEOd~o?>>՟f}IT˳:oܟµzn|М9_`=Jj_Ym~V?+~w|~ޙ?{!_|_1.y|j[N5iVG5?쯿#~WXqm_  jmLg_W1Ϙtg.$? lL3~foW}nH1[GgmU\bnZ^0OϾetyך/LZt3k=q-Q 1f}Boy.ޏp^Ͽot~/y/X}+//yb:~Rk>k/vx4)Gdbnf;~}|u~otIq\V>SKOV(~(|H=:XOS,ߍt]Wd:j<ڟi/s}R=짙~\<r8Wɑ Ex4ϻpK7#_jVG]?ߴZ+b=6?j$%i՗W?տC5?lNtQZ|6_OVoV>GүFNg]瑞Gg~yWM+7]뙮0]rݿej!߄0?}5jt?oa:kF/߶1^L?=}v|i`\iz fWie?q]k'M'ybWx:g8rw9XO֫|߬|&ү|7'o=4G|>usM磞6?>t|nj~zyIm~^͉A9?a(_l~o cga _yC2]4}k{`v3h=euMG;geģg4]k-Yk+9t~5_t_iqϛKO?Yk0L7)]_|>'пjg_߄{oGk|^|Dd7/5/C_QI{/>G,_< ×\/cl~ܟ{W^<Fmb~z_tٚo4s&'N3c_}33 }^jwZogSOxUIo^4~tۯYf2V~.:0\_W/f󢫘n׷?x泿c<ԟ#5/>t׫̓'xTpӜ1|!s6Ga/iEE_IgY[Ud5Ϙy\m/v]MW [>~Hޏt?;ruY}sUy`~4u<*}=|+o4#]k=Q~a~mx7tۏ64]ԯL^~w>7yYިHqRsC׬oU}?wMdz!|ͧ{.o5j?A=9Y|zm>6?Zo"_O!oQ>GR~+(?4zg㾞4şޱeq|y_?ă7rVyUO~tz'~ Ukq1>Ѭԯցt͇w筬MnY_}%ަ_Yq?MӟMM,0?HWƷ*?#C~Xo|_~U~*m':Gy,o%=<$끥_[㧞σO?4_y5|C|^6]2R޸O kLk~3e#|ˋz[1?jzkufg]k=wjY)k&׻~E^t~ǘwi?{̓~?a꭮stF\|^ǫ?ʦ_sUmݭO9?|/)(?͗?S |OO;>?|qe_yO z>/ |C|cvWoo)&f|F7~Hoy.#]g 㛕5|u|ǦYOzopdZUՏ8PU_0?UI~OhWF}yi?/\?j9=Ze/ߥy7gN:t4eZ^O`=zk?K>GM~կ~ߣΣ㿞^ߠC;Wbs"w  UVIndexit  ۅ x4Cim۶m۶m۶m۶m[3mSDT> 0  ͜T(w:n8vc2ݜq얌gf>$-8|xvg#2ݝq잌Ggf>&/8'>q'ed>9{4)cO8IvZƹgOfO}=]ʞggsu:|~b {)/^8|qjK2_q썌×gof[uvaqXf{u~a|qXfuQ3ߔ}qӌ÷de5&k:eZ\m<=T#uXam/{k:uXamZZuXoamYVuXam[^uXam|XQuXam|ZYuX_amkuX_am|Uu7uX6:|BOemRkouXamQg_uXamSo am 7_ +sX9A~94am 6sXC9!Pakc01L6am 6sX#9Hakc01J5am6FsXc91Xakc01N7am6sX9 Dakc01I:4Z\mL,ژ"amL6 +sXS9iƴakc01}ژ!amf83`:5f83`:383`:783`:X083`:X483`:X283`:X683`:X1J'V8;{k:6^xk:6^xk:6ިxk:6ީxk:6>k:6>k:6O#oƗuX_a|]ʴ66k:6~k:6~k:TWuXg6kc9akc01h,am 6sXC9akc01l.am 6FsX#9akc01j-am6sXc9akc01n/a -p6& OamL6&sX9Idakc01Eژ2amL6sXӄ9itakc01Cژ1a̔qX3g,u0ka̖qXgu0ga̕qXsg<u0oa̗qXgu`a,qX g"uha,qXguda,qXKg2ula,qXg +ubԹf+g+']OZ'VÓfɲ5ٚuxl:uXaWuuXaTqp j쐲68k:#68k:c68k:IuX'amR7N8k:36ά8k:s6έ8k: 6.ڸk:K6.ڸk:+6ڸk:k6ڸk:6nd7am\qKuxL ۳ڸk:6ڸk:6xk:6'eam5{k:'6xk:g6xk:6^xk:W6^xk:76ުxk:w6ޫxk:6>ߔ}RiguXC2-p6}Q6k:o6k:6~k:HKƯuXdz6k:6kcA6̛(am 6 sX9akc01d*am 6 sXÆ9akc01b)am6F sX9akc0u0f&;uX2-p6+k:68k:C68k:#68Sqlqux:6Nd'am\qJƩuXam^qFƙuXgam]qNƹuXam_qAƅuXam\\qIƥuXam\^qEƕuXWam\]ʮڸk:28W7f7qSuXamZq[uXwamYqWuXam[ڸk:||`CuXameZ\m|}T'uXam|VyuXoƗuX_am|]MƷu:6~f?amTs/uXamV{uXamUw?uXam 0ƀysX9 akc01Xƈakc0u0r&5am6f sX3eu0Ka̚qXeu0Ga̙qXseu0Oa̛qXeu@a,qX euHa,q߄8WguDuXKa,]uLuXa,_uBuxl:k:O6>k:/6S[eWu:o6k:@CƏuX?am\KƯuXam^GƟuXam]OƿuX ?1`@akc01H4am 6sXC9!~#*am 6 sXÆ9 -p6am6F sX#9(akc01Z=am6 sXc98akc01^?amL6& sX9$akc01Yژam6f sX3eu0Ka̚qXeu0Ga̙qXseu0Oa̛qXeMhsu`@Y a,\uHuXa,^uDuXKa,]uLuXa,_uBuX+a\uJuXa^uFuXka]uNuXa_uAuXal\uIuXal^uEuX[al]uMuXal_uCuxL إkc:6vأkc:6اkc:6eamXqP^1;k:C68k:#68k:c68k:6N8k:S6N8k:36Ϊ8k:s6Ϋ8o]PqaEuX2-p6..)k:6ڸk:6ڸk:6nڸTqs-u:6nڸk:6ڸk:6xk:6xk:6xk:6xk:6xk:|ARuXaZwʴx={76ެxk:w6ޭxk:6>k:|SIƧuX6k:o6k:@CƏuX?am\KƯuXam^GƟuXam]OƿuX ?1`@akc0_ sX9akB !CdXC90akc01\>am6F sX#9(akc01Z=am6 sXc98akc01^?amL6& sX9$akc01Yژam6f sxܙ2`:%f82`:#̸oB :`::X`::X`::X`::X`::X`:V:X`:V:X`:֮:X`:֯:ؠ`:6:ؤ`:6:آ`:CdZ\mlmSvuXamPcNuX;amRknuXamQg^"۫kc:}پuXam_q@ƁuXam\qHơuXam^qDƑuXGam]qLƱuXam_qBƉuX'am\qJƩuXam^qFƙux:6Ω:8ϕisq~v^Yam\XqQuXam\ZqYuXWam\YqUux:k6famPqcMuX7amRqkmuXamQqg]uXwamSqo}uXamuXaWuuXaTupp!uXaVupxuXGaUupt1uXaWup| uX'2-p6NN*k:S6N8k:36Ϊ8k:s6Ϋ8o]PqaEux:K6.ڸk:+6ڸk:k6ڸk:6nڸk:[6nڸk:;6ڸk:{6ڸk:|\@ƃuXa<\7ȴ==Z~,:xG~"?UOgg C@a  a `a a Pa 0a pa aHa(ahaaXaqo6n_f9U6~_g9M6af9]6qg9C6i?f9S6y?gS9K6eӄ6OamL6 sXӅ9 akc01S:9f8Y3`:=893`:;8y3`:?83`:X88E3`:X<8%3`:X:8e3`:X>V83`d+g0[%D٪'V8k:O6>k:amk:6k:6k:6~ӄ6~~)k:6k:6kc6̛(am 6 sX9akc01d*am 6 sXÆ9akc01b)am6F sX9akc01f+am6 sX9akc01aژ(amL6& sX9akc0 mL2ژ:amL6 sXӅ9 akc01S:9f8Y3`:=893`:;8y3`:?83`:X88E3`:X<8%3`:X:8e3`:X>V83`d+g0[%D٪'V8uXaWuuXaTupp!uXaVupxuXGaUupt1uXiBgǕqBƉuX'am\qJƩuXam^qFƙuXgam]qNƹuXam_qAƅuXam\\qIƥuXam\^qEƕuXWam\]qMƵuXam\_qCƍuX7am\qKƭuXam^qGƝuXwam]qOƽuXam_@&P`Yamam6F sX#9(akc01Z=am6 sXc98akc01^?amL6& sX9$akc01Yӄ6OamL6 +sXS9iƴakc01}ژ!am6f +sX3g,u0ka̖qXgu0ga̕qXsg<u0oa̗qXgu`a,qX g"uha,qXguda,qXKg2ula,qXg +ubaqxlfd([5j'V8k:O6>k:/6S:/6k:o6k:MhDz6~k:6~k:6k:0okc01p$am 6 sX9!Ɛakc01t&am 6 sXÇ9ƈakc01r%am6F sX91Ƙakc01v'am6 sX9 Ƅakc01qژ$amL4ÓeXS9)Takc01Mژ6amL6sX39La`:%f82`:#82`:'82`:X 82`:X$82`:X"82`:X&82`:X!V82Oqxlef8[-$'ȸɲɳ5S]֩Seᩳ4uxl:<]a>ۨϐm\g63eᙳ,uxl:<[e=۪`:m:خ`:v:ة`:]v:ح`:=:ث`:}:د`::8:C:8:#:8k:Mh옲68k:6N8k:S6N8kc=nVom۶m۶m۶m۶m۶=G}4i>IWmlgmƶqv9ml綱mƶq~mlm\ƶqq%mlm\ƶqymlWm\ƶqu5ml׶m\ƶq} ml7mƶqs-mlmƶq{mlwmƶqw=mlلmܟ6lcxm6G6mcxm6'6lcxm6g6mcxm66^lcxm6W6^mcxm676lcxm6w6mcxm66>lcm6O6>mcm6/6lcm6o6mcm6l6~Xmlmƶ[mlmƶWmlmƶ_ _c0@ƶ1pm kl5AcmcXc<65!cmcXc:65acmcXc>6F5cmcXc96F5QcmcXc=6ƈ51cmcXc;6Ɖ5qcmcXc?6&5 cmcXcۘ8l6&'ɱmLklƶ1emLklS4ƶ1mmLkl ƶ1c̔fil4Ysl9`v0GNc;3̕il4ys|9`v@Nc;X0,il4Esb9`vDNc;X2,il4esr9`vBNc;X1rO[9UrO[5Ĺr$IskV'˻fO[ȭSirԹxmlcm6O6>mcm6/6lcm6o6mcm6s?ԶSmlmƶ[mlmƶWmlmƶ_ _c0@ƶ1pm kl5AcmcXc<65!cmcXc:65acmcXc>6F5cmcXc96F5QcmcXc=6ƈ51cmcXc;6Ɖ5qcmcXc?6&5 cmcX ۘ$8Ƕ1imLklƶ1emLklS4ƶ1mmLkl ƶ1c̔fil4Ysl9`v0GNc;3̕il4ys|9`v@Nc;X0,il4Esb9`vDNc;X2,il4esr9`vBNc;X1rO[9UrO[5M$znzҼkd5xZmjcm6O6>kcm6/6jcm6o6k !}m?mƶs/mlmƶ{mlmƶw?mlmƶ16̷ƶ1Pm klbmcXc,65!bmcXc*65abmcXc.65bmcXc)6F5QbmcXc-6F51bmcXc+6Ǝ5qbmcXc/6Ə5 bmcX ۘ8(Ƕ1ImLklƶ1EmLklSԱƶ1MmLklƶ1Cmkl34s,9`֜v0[Nc;=̑ils4s<9`ޜv0_Nc;?,il 4s"9`ќvXNc;X<,ilK4s29`ٜv\Nc;X>Vi<~nVihcm66>icm66hcm66ic&lwmƶcOml?mƶkomlmƶg_mlmƶomlmc|klƶ1Hm/65bmcXc"65bmcXc&65bmcXc!6F5bmcXc%6F5bmcXc#6ƌ5bmcXc'6ƍ5bmcXcۘ l6&'̱mLklƤƶ1YmLklSƔƶ1UmLklƴƶ1]mLkl3ƌv0SNc;9̒fil4s9`Μv0WNc;;̓il4s9`vPNc;X8,il4s9`ɜvTNc;X:,il4s +9`ŜVincm66>ocm66nc&lܷm|ƶCƏml?mƶKƯmlmƶGƟmlmƶOƿmlm 05m kl ƶXc465cmcXc265cmcXc665cmcXc16F5cmcXc56F5cmcXc36Ɗ5cmcXc76Ƌ5c&lcxDƶ1qmLkldƶ1ymLklSTƶ1umLkltƶ1}mkl3L9`v0KNc;5̖fils49s\9`v0ONc;7̗il 4sB9`vHNc;X4,ilK4%sR9`vLNc;X6,il+4s[)M0JnzĹxmncm66>ocm66ng?ZnrXyi1sKxܒmmdn6^"W/۳ƋvoEr¹]x.m`n6^ Sϟ۱mc66kcضmc66jcزmc666kcشmc66jc;ذ`6kc;X`6jc;X`6Vkc;X`6xJm<~n6/Bmlyݘ/ ml׷m\ƶqm5mlWm\ƶqemlm\ƶqiw];.jsv 6oc8m6s6nc8m636Noc8m6SxmA6^?wb;m66mc8m66lc8m66mr񊹃xAml7M1qm|ƶAmlﵱmƶNmlomƶFm|I68j_{/̽^jcxm66kcxm66jcxm66ksIGm|B66hc۸m6{6ic۸m6;6hc۸nmrm|6IܨwC?ʍkl#Hƶ1bmklpƶ1lm klCPƶ1dm kl`/5 ƶ1pm kl ƶ_ƿmlmƶWƟmlmƏ~ksC_6~ncm66ocm6o6ncm6/6>ocmchly`,vh"ml ,v`mlv0o6wGic۸m6;6hc۸m6[6nic۸m6x mo6'w]mly ?j~7pƶ1lm klCPƶ1dm kl`ƶ1hm/65cmcXc0 ƶ_ƿmlmƶWƟmlmƶ[ƯmlmƶSƏm|_67}ߓm6o6ncm6/6>ocm6O6>ncm66F̟6a -Tmlv0o5x{m6G6ncxm66oc۸m6{6nc۸ƇhCs!6nmc۸m66nlc۸m66mc۸m6#wUw]ƶfmsC 9~-7Dm klƠƶXc$65bmcXc 6kcm66jsmƶ{omlmƶsOml?mƶ}wml߶m|wn;r_/mlm|ƶi'mlm|ƶamlﷱmƶn;mlomƶ1t&lAܹyj;`69foc;`6Yfnc;mc66Ϸƶ1]mLkWnX?sSTƶ1emLkldƶ1imLklDƶ1amLklxƶ1nmklcXƶ1fmklhƶ1jmkl#Hƶ1bmklpƶ1l kl [мmn6icغmc6-6hcؼmc6M66icظ`6 6hc;X`6uic;X`65hc;X`6UVic;X`6Vhc;X`6eic;X`6%hc;X`6Eic;X`6xm1p{=hc۸m6{6ic۸m6;6hc۸m6[6nis7x܍m_66kc۸m66jc۸m66.kc۸w];.nrm6R wC_ klƀƶ1@mƶo?mlmƶgmlmƶk/m`66~lcm66mcm66lcm6ܧm|S61qߐm66ocxm6w6ncxm676^ocxm6W6ۄ-h^;57[mv0Sƌml3mLomcXcۘ665cmcXcۘ265cMksnXcۘ$6&5bmcXcۘ 6Ə5bmcXc'6Ǝ5bmcXc#6F5bmcXc%6F5bmcXc!65bmcXc&65bmcXc"65b`7a 66mQfmlmlƶqFmllv~zml붱vvZmlkvzjmlvrJml+v|rml˶,vtRmlK,vxbml,vpBml ,v0|mlv0wƃhc;زmb63sg՛=m66Nmc8m66Nlc8m66mrǴ񚹣xQmz6^-wDmlmƶqHmlmƶq@mlmƶO/ۻƋlr{mƶ[ƮmlmƶSƎml;mlƶ]ƶm7_T6ncm6?6~ocm6_6~ncm6/Cߛ}wmrߴm|ƶUƗml_m|ƶYƧmlm|ƶQƇml{m|u6*NmlomƶFmlmƶJml/m^hssϷ96msϐrƴƶ1MmLklSƔƶ1EmLklƤƶ1ImLklƄƶ1AcmcXc76Ɖ5cmcXc36ƈ5cmcXc56F5cmcXc1憏5~'7\m klбƶ1Tm klCƶ1Xm kl5AbmcXc(65sۄ-h^;0Qmv^ml봱vVmlkvZmlvRml+,v\ml˴,vTmlK,vXml,vPml v0_mlv0Wmlsv0[m,wGnmrmƶqSƍml7m\ƶq]Ƶml״m\ƶqUƕmlWxems6)wImlm\ƶqAml統mƶqNmlgmƛhMs&6ocxh#ykcm66~jcm66kcm6Wm|{6-Eߚo}ƶi'mlm|ƶamlﷱmƶn;mlomƗlrokmlmƶrKml/mƶ|sml϶m<ƶt{O=Ƨhcm6)"6&5bmcXcۘ$6&5bmcXcۘ 6Ə5bmcXc'6Ǝ5b?ύklcƶ1Zmklȱƶ1Rmkl#ƶ1\m klбo䆊5~=7dk!bmcXc,65 ƶ1pm kl ƶ_ƿmlmƶW{kly`:vfmlvj*ml+vb +ml˷,vl2mlK,vdml,vh"ml ,v`mlv0o&}mlmƶqw]mlwmƶq{mmlmƶqsnh}s׷>6mc۸m66lc۸m66.mc۸m6x܅m]66w~o;m6s6nc8m636Noc8m6S6Nn r'x mlMhcxm6w6icxm676hcxm6W6^i s/܋m|^66kcxm66jcxm66kcxO='nrm6ScwCMklƶ1~mkl8ƶ1vmklcƶ1zmkl(F5bmcXc!65bmcXc&65bmcXc"65bmcXr5~17H cmcXc0656mcm66lcm66~mcmckly`jvrJml+v|rml˶,vtRmlK,vxbml,vpBml ,v0|mlv0w\mlsv0{lmlv0sLml3mƶ1}5bmcXcۘ&65bmcXcۘ"6&5b`6a 6Qamlmƶqp;hes2xܾmTn6^2w/۫ƋhEs"6vmcإmc66vlcءmc66mcئmc66lcآmc666mcؤmc66lc;ؠ`6mc;X`6"VO['˭vpdmsw{GmlmƶqKml7mƶqCml׵m\{i=sWxܕm[66.kc۸m66.jc۸m66kc8m62wvo;7ϝƛhc8m6S6Nic8m66Nhc8m6cx1mf6^#wTmlwy}#Wml_m|ƶygmlm|ƶqGmlm|ƶ~_{νWi+so6lcxm66^mcxm66^lcxm6ܳm|V6>3t{m6'6ocxm6G6ncxm66ocrѹ{=ml߶M|:7ݐrرƶ1Vmklcƶ1Zmklȱƶ1Rmkl#ƶ1\۹acmcXc:65!cmcXc<65Acmƶ1Hm klƀƶ1@3ܿmT66jcm66~kcm66~jcm66kc?n4 [мv|nkc;X`6jc;X`6kc;X`6jc;X`6kc;`6jc;`6fkc;`6fjcۘmc6mLkl4ƶ1umLklSƶ1ymLkl$ƶ1qmLklvbNcX!y;^.mln6^&_/۷Kn%r{=xmhn6^$[/۵ vnr;6vhcؾmc6m6icغmc6-6hcؼmc6M66icظ`6 6hc;X`6uic;X`65hc;X`6Ux*m Mml7mƶq}uml׶m\ƶquUmlWm\ƶqyw];.is6.lc۸m66mc8m66lc8m6xܩmQ60wro;m66oc8m6c6nc8m6#6oUrʹCx!mlM9im|ƶQƇmlmƶ^ƻmlﴱmƶVƛm|Y64z_{/ν^icxm66^hcxm6g6icxm6'6hSs)ܣm|R66jcxm66kc۸m66jc۸ƇnoCrm|6YwC?ɍkl(ƶ1rmkl#ƶ1|m kl0ƶ1tm klCƯ5bmcXc_m kl@ƶ1`m klmƶOmlmƏhGs#6~mcm66~lcm66mcm66lcmc&lAj;X`6mc;X`6lc;X`6mc;`6lc;`6fmc;`66flcۘmc|klƴƶ1MmLklSƔƶ1EmLklƤƶ1ImLklƄƶ1AmklƸƶ1Nmklc9ob6sKݫƋhEs"xܮmPn6^0s/۩ƶCml۵mlƶMmllZ,0à M@" H U0(XRi7ޝ>a qm؎Ɓv6㶱Ўvvvh`{;n#lk`k;n[q;܎v6v};nq;Xߎwk?n ֶqSdޛv6^qxю?mݎv6'mՎ???7ގ{؎ƃv6G;nqmҎmimv;3V;#oߞS;>7ڎv6nqkm\mmJ;nq۸Ԏv6.q;׎mimv&޶o>%|b(I? e>9PSCO e>=Gg2PBe>'P柄24y~ A1ŃH$翗 2?ed6doуg?e0PCPKB|i(C/ ert9D!G;No98VG7Outqt8o6G7{-qt8_ң  s   LayerElementMaterialI    VersionIe    NameS   MappingInformationTypeS AllSame?   ReferenceInformationTypeS IndexToDirectf   Materialsi     LayerI    VersionId  LayerElement   TypeS LayerElementNormal    +TypedIndexI y LayerElementP   TypeS LayerElementMateriall   +TypedIndexI  LayerElement   TypeS LayerElementUV   +TypedIndexI O  ! GeometryLД* S + GeometryS Mesh  m Verticesd ` ۲ C C @ ۲? C C @ ۲ C< C ۲? C< C    PolygonVertexIndexi       Edgesi     =   GeometryVersionI|    LayerElementNormalI z   VersionIe    NameS    MappingInformationTypeS ByVertice  ReferenceInformationTypeS Directr  m Normalsd ` ? < ? < ? < ? <    LayerElementUVI    VersionIe   NameS map1    MappingInformationTypeS ByPolygonVertex@   ReferenceInformationTypeS IndexToDirect  M UVd @ ,0? ? ,0? ?   UVIndexi        LayerElementMaterialI    VersionIe /   NameS ^  MappingInformationTypeS AllSame   ReferenceInformationTypeS IndexToDirect   Materialsi  B   LayerI    VersionId c LayerElement:   TypeS LayerElementNormalV   +TypedIndexI  LayerElement   TypeS LayerElementMaterial   +TypedIndexI 5 LayerElement    TypeS LayerElementUV(   +TypedIndexI   ! GeometryLЪ* S + GeometryS Mesh  m Verticesd ` ۲ C C @ ۲? C C @ ۲ C< C ۲? C< C C   PolygonVertexIndexi    r   Edgesi        GeometryVersionI|    LayerElementNormalI    VersionIe    NameS    MappingInformationTypeS ByVerticeG  ReferenceInformationTypeS Direct  m Normalsd ` ? < ? < ? < ? < 0   LayerElementUVI    VersionIe (  NameS map1_   MappingInformationTypeS ByPolygonVertex   ReferenceInformationTypeS IndexToDirect  M UVd @ ,0? ? ,0? ?#   UVIndexi        LayerElementMaterialI o   VersionIe    NameS   MappingInformationTypeS AllSame   ReferenceInformationTypeS IndexToDirect   Materialsi     LayerI O   VersionId  LayerElement   TypeS LayerElementNormal   +TypedIndexI % LayerElement   TypeS LayerElementMaterial   +TypedIndexI  LayerElementb   TypeS LayerElementUV~   +TypedIndexI   ! GeometryLЬ* S + GeometryS Mesh]  m Verticesd ` ۲ C C @ ۲? C C @ ۲ C< C ۲? C< C    PolygonVertexIndexi       Edgesi        GeometryVersionI| +   LayerElementNormalI &   VersionIe <   NameS m   MappingInformationTypeS ByVertice  ReferenceInformationTypeS Direct  m Normalsd ` ? < ? < ? < ? <    LayerElementUVI d   VersionIe ~  NameS map1   MappingInformationTypeS ByPolygonVertex   ReferenceInformationTypeS IndexToDirectH  M UVd @ ,0? ? ,0? ?y   UVIndexi     u   LayerElementMaterialI    VersionIe    NameS +  MappingInformationTypeS AllSameA   ReferenceInformationTypeS IndexToDirecth   Materialsi     LayerI    VersionId  LayerElement   TypeS LayerElementNormal   +TypedIndexI { LayerElementR   TypeS LayerElementMaterialn   +TypedIndexI  LayerElement   TypeS LayerElementUV   +TypedIndexI Q  ! GeometryLИ* S + GeometryS Mesh  m Verticesd ` ۲ C C @ ۲? C C @ ۲ C< C ۲? C< C    PolygonVertexIndexi       Edgesi     ?   GeometryVersionI|    LayerElementNormalI |   VersionIe    NameS    MappingInformationTypeS ByVertice  ReferenceInformationTypeS Directt  m Normalsd ` ? < ? < ? < ? <    LayerElementUVI    VersionIe   NameS map1    MappingInformationTypeS ByPolygonVertexB   ReferenceInformationTypeS IndexToDirect  M UVd @ ,0? ? ,0? ?   UVIndexi        LayerElementMaterialI    VersionIe 1   NameS `  MappingInformationTypeS AllSame   ReferenceInformationTypeS IndexToDirect   Materialsi  D   LayerI    VersionId e LayerElement<   TypeS LayerElementNormalX   +TypedIndexI  LayerElement   TypeS LayerElementMaterial   +TypedIndexI 7 LayerElement   TypeS LayerElementUV*   +TypedIndexI   ! GeometryLТ* S + GeometryS Mesh   m Verticesd ` ۲ C C @ ۲? C C @ ۲ C< C ۲? C< C E   PolygonVertexIndexi    t   Edgesi        GeometryVersionI|    LayerElementNormalI    VersionIe    NameS    MappingInformationTypeS ByVerticeI  ReferenceInformationTypeS Direct  m Normalsd ` ? < ? < ? < ? < 2   LayerElementUVI    VersionIe *  NameS map1a   MappingInformationTypeS ByPolygonVertex   ReferenceInformationTypeS IndexToDirect  M UVd @ ,0? ? ,0? ?%   UVIndexi     !   LayerElementMaterialI q   VersionIe    NameS   MappingInformationTypeS AllSame   ReferenceInformationTypeS IndexToDirect   Materialsi     LayerI Q   VersionId  LayerElement   TypeS LayerElementNormal   +TypedIndexI ' LayerElement   TypeS LayerElementMaterial   +TypedIndexI  LayerElementd   TypeS LayerElementUV   +TypedIndexI   . NodeAttributeLp_ S persp1 NodeAttributeS Camera8 Properties70T  > PS PositionS VectorS S AD D @D O}hb*@  > PS UpVectorS VectorS S AD\3&D D   F PS InterestPositionS VectorS S AD*icQF^ei^|{OG_9N5d<|g}~Wv]p}# +?G|w y>;N]ufmܾ_ɐ7_D,O\z /-x2aV.pLQ>;~moy>+c<">q"y9>/u +›~:ܟL~c?3u}_?~?wo#=s_osx5]j/?7wB~fK'0qn<">Nq6N5G>s~[?]|HG>;ygꚯxG߅|}g[x_ \M# +?g/nQx"G}+]y6N5b<#n_`uzGG:Vn#;~>{~/>ܫ߽W8oŇWNS#_#q"b^L}›/uϙqoҙ䩟f_8'DΧ_|NW0MϧzD;:ި_w|>{>sԯDy_#bб;ny Og}vIQt?5OG:Hm}|&^ x[f0?8y䏯n>3N^f?፺>•GG8į93\>l+^o<χ3O!KQ~;N]̻/u49^ZOswϝ7]j;NׅOlN7 m\ W9Wqͳ#jy@'_s<)GB̸ek#hO;>қo}ϯ_{ +O79Kx5]jǹ9|GBڦ(.gǩ[q11F4qͳ~ȿ.p{tO#GB(WqUske9e>gycCٛN`ӝk'G~h| <թCU>>_W8N5yN>{n}_^ȖQWj>s? 3dJ]uu~O}/~G }v\,xPG[CʺZuTWKu^OTG \m_yOC`u}Σ>wF:B5Gq"|+Ee|To <~f~a> cY?s]?{` &tS&|GM:Kϥq֛͛/t5Ͽ3>zU/y{?6~>_Gh}g>">c}"x_ɯ~h}S?3+ׁq}ݿr>ǹ_qٿb6} +a)__g6 =`/;-xu# +vOc?(|VpOu*<v}֑|/V3Yu?󩯺~ ~b{xt~<:?99Ώ9}Ж&r~pGyr~~bZΏ9?.8&5_e]L~_օu|v~p;}O7*}Gx#>׃~8Ov]ws}/r <#D}^}ⱟ/>o zayq7Wp%zN~7*^p\9Nē}~q}xO~ol8A |7S2   PolygonVertexIndexi   xsG"Uj۶mvj]m۶R۶yk׮}9Ͻ'y$ 30!Cp1A|Wcb#uGI⫚Ɨ59&/j>JL|`L|Ԙ2>h1U|Rcc4QnjiÚ5;k>N|ܘ1ޭڵvm7KUsov5zm7GVsvs+5rm7OTs/|/^kn⹚nx[(knE⩚nx6)]-vKc5ݒhmT 햎Gjnenx[.햏jnnŸ[)V{jnUnո[-V;jn5n͸6[,n]ۭv5ݺqS͗ƚn 6jnښn㸦$6jnʚn".jnAqimU\RsmvE5Zqan>ίvjnܚn89ήvjn]̚n8=Njn=Ԛn8;Nj>(knℚq|mWsm֮cjn8cYs)va5ݡCjn5cmwT\svā5ݱq@mw\_۹5 _mv@[;)NknSbس;-Nkn3bgƮ5YKmwv\s۝;vƎ5yCmw~l_s]vƶ5EM͏cت6;1ծ.-kncؼ涻26Mkncظ涻66 kncX涻1֫nukncX涻5֪n5kncX64V]vw*5=rmwoTs+v +5|m`,Ws=v25#tm78%knbX{"힌EknbXƝPX{.힏knbŘ{)橹^knWb՘{-樹^k>8ވjn7c֚{;fމjnwcƚ{?͞jvƴ5G1MmqL]s}SvƔ5g1EmyL^s}v_Ƥ5W1ImuL\s}vƄ5w1Am}_sv?Ƹ5O1Nm6 ƪ]-ƬcvkI3Fv5b%F#v5o1_ _svCbؚn?Zkna>dp5jnok_knv#տv#?vvFYsۍ^{m7fn5_jnqjnqkn⇚n涛 &oknojv5$Um7i|YsM_v5Sg5ݔim7U|RsMvG5ݴam7]|PsMv3{5݌nm7SSsov[5ݬfm6QQ=^jn9՚nx涛;^扗jnyŚnx涛?jnٚnx[8jnEɚnx[<했jn%њl\[:행kne㡚nx[>Vkn㾚n[9VknU㮚n[=ֈkn5㶚n[;n։knu㦚lvm~Psmvu5Fqmmq\SsmWvU5fqemy\Qsmv[e5ݠ*.knm⢚n۸..kn⼚l8vmSSsgvY5ݮqfm[Qsv{i5ݞqjmWRs'vI5ݾqbm_Ps!jnؚ8;(jnȺ3|LỚj>BW|t5|Ԯu5]j>VW󱻚|ܮ条p]ow zp]ߞ;w}s;s7ߓpc6  e Edgesi   X x q( qs^h46FhSQŢ(EQ(Ebv)uE;ENsohwEcS==O: ɷ6{|#~O)? J8DK<$J:dK>SJTQC 4BtC 1L1,p-<P‰$XI$T$\)Rʨh蠋`Ƙ`f),KVYgmv#N8-\kn灠 N$O"ɤN&O!ŔRFUPGMF] C0S03q;>ˆ H  ~FEr*ziv:馗~淌34Ocgh !;$D +idEyPD )jjf~M;tK? 38L9xsy+`-vx>3q{ᎏSDC $BdCQcʩ_QO#ʹN' Ì2$7   NameS o7   MappingInformationTypeS ByVertice7  ReferenceInformationTypeS Direct$D  q Normalsdz  d xmZm]E\"Q-)Dd)!vHbibtc"4a]*"fb SJ TF|fwzzy?;wvf=t]?Usa㼝#k),odžx:!G /7r%.Y+J;l#vO~W˃~ӑC~vG9Ooo&s)[n+y">.):agg̷z糺ݙ>nw;ozo6޾3VcdOF[n<<]̮#ͧ<~nK.`ځΙB/>үW~l~cOqaϡ\:Q̷'D~0^í^!~^DZ,v"uy^m 7=H} \yq{z坣+w#Ӌe٣ho/~_Gk`|٣Cܙnwp(|uS~p˻'?Q?Olz_zd{=!3llݷmGCOuWOOߴx~Z^|O{!6/nt뇋<|>GnIq'G+~>&׿y%*xsGc6r>Oo>ϖx\h3qOQ-q?Cnt>G=_edm>Ц5״^[ݺL?봧+N9^ W:MgNI'q_yOxO~[#Gr&ˁ?X^pdtq18'>c;; +~8ƗZ3B]IZ ~"aAkGGB'ƕw +o>c_G|/t|{~}wSs/)sxg>N:VlGx1݆xp5V/h_33QM^ʟ蓈{=ȑ:5r}m-ek|kgg<^|_tLw5WOusIWmݧϖ'G~N|>xY ."r G?<>| n#|S>!{rٷ+V:-ui72Fݱtܽ}ݷHK߅~~am~˳zO"-pO>+GܫN0OָX?tic~W[}]DN{5 O8  +Ҹ߱w[w6=Wu{n~ܿw'Q{t?޿MZ'֕Y'od]=q 9/'ix$o| ݿMo̿5οo|wO56>Sۼ \_ab~8:h^L'EG#$_?)/qοm<$?Gk<~Qy ϓ-=ϫxH|g|Z8~~Oׯ2O +u`|{~;(㸏}Jm&G/3_'_ S5G?Qh_'|/ܯ?N ?䨏v}#gx 3gx><{|jWO'/W~|cO\ħޟO'eZ +/U}]ٟ<۟a>n3q>ŗm&^gw0[m;v|''+U}sx_W~|j_'/W~|b>qO'^'O'NWv`U)O'^q?n=q>vޓϧi;)'b|O\|ǕOs.?磝OO\ٟ>1wO|O|5ĵO\k|b5ڗO'_'^'O'_''{u]{W<>q O'~Gvxf>W}?}ώܟ|_'Swy|gb>q'>O'wl^x_W~|jWėoU'>t1v3b=wf;_=GԿ|bO|b>ﶝ0|⚟n1j^98>#\kw\5|o~obO|}[ħ~a>1/}NOλy'^'x|,>q'_':ݟ9Ǖ=ߗul35[3vOSݟ2=H3'>'W~|b>1}+^{|b>u}ͧv>1O|>d_8/>'?1>qy|'։5|b>>'W~'r1O|mOO\#|kw'?q?898>Q35X|Kĕ9|hwO|_|Z~'kĕO\'Kĕ>Oskk|io82돼+?>q O|ć+?>1z_<9O<}]^>~T=ɇ:rr??\*ÌW)3^:wdxx57k=x/^+_/<'_/qXgda>qXOg3ula>qXg ubaqX/g+ji׳uF}3N8ӷ3:}7N83fa82Ì:8ӏ9e~qXduYa~qie~Uuu7uXa~Wu}uX?aTus/uX9uz'N83:3v8ʹOvڽ[ ʛ sX!ak74a톅90v#iT:sX1a46aƅ90uvÜfMOʰvSnj:͕qX34Oa8|u?N di:-qX3Haeiь:-qX3Da8tZ:[2uXeNa:PuZRi:*uXUNaV:QuZVi::uXuvie6mT۸k7kIn:fuXv[amUۺkMn:vuXv;avTvd;۵k[n:uX=v{aS۷k_n:uXvafaR;kwXf^:QuXva펭W;kwB:IuXvaNڝV;kwF:YuX4윲vaί]Pk7kwQ:%uXKva.]QkwU:5uXkva ;1<$}Sxha޷z}[xdQwGz}Wxlqz}_xbI'z +O~0<5oķp Ɂ Ɂ Ɂ Ɂ ` ` Ɂ Ɂ @ Ɂ @ Ɂ Ɂ? +V  M PolygonVertexIndexi @         jV  - Edgesi       V   GeometryVersionI| X   LayerElementNormalI V   VersionIe V   NameS W   MappingInformationTypeS ByPolygonVertexEW  ReferenceInformationTypeS DirectX   Normalsd0  @.Y> @.Y> .Y> .Y> y @y? `y y @y? `y y @y? `y @y @y? y? @y @y? y? @y @y? y? @y? y? @y? @y? y? @y? @y? y? @y? @y? `y? y @y? `y? y @y? y? y Z   LayerElementUVI ,Y   VersionIe FY  NameS map1}Y   MappingInformationTypeS ByPolygonVertexY   ReferenceInformationTypeS IndexToDirectpZ  UVd ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Z  M UVIndexi @            [   LayerElementMaterialI [   VersionIe 3[   NameS b[  MappingInformationTypeS AllSame[   ReferenceInformationTypeS IndexToDirect[   Materialsi  F]   LayerI [   VersionId g\ LayerElement>\   TypeS LayerElementNormalZ\   +TypedIndexI \ LayerElement\   TypeS LayerElementMaterial\   +TypedIndexI 9] LayerElement]   TypeS LayerElementUV,]   +TypedIndexI ^  & NodeAttributeL$ S NodeAttributeS Null] Properties70]  ! PS LookS enumS S I ^  TypeFlagsS Null u`  $ ModelL0q* S pCube1 ModelS Meshc^   VersionI /` Properties70^  + PS RotationActiveS boolS S I ^  ( PS InheritTypeS enumS S I @_  G PS + ScalingMaxS Vector3DS VectorS D D D _  8 PS DefaultAttributeIndexS intS IntegerS I _  O PS Lcl TranslationS Lcl TranslationS S A+DF e:׿D +t%@D`dM?"`  1 PS currentUVSetS KStringS S US map1 E`   ShadingCTh`   CullingS + CullingOff b  ( ModelL@q* S pCylinder1 ModelS Mesh`   VersionI b Properties70a  + PS RotationActiveS boolS S I Pa  ( PS InheritTypeS enumS S I a  G PS + ScalingMaxS Vector3DS VectorS D D D a  8 PS DefaultAttributeIndexS intS IntegerS I Gb  N PS Lcl TranslationS Lcl TranslationS S AD}@Dm\& @DE@b  1 PS currentUVSetS KStringS S US map1 b   ShadingCTb   CullingS + CullingOff e  % ModelLPr* S pPlane1 ModelS Mesh)c   VersionI e Properties70{c  + PS RotationActiveS boolS S I c  ( PS InheritTypeS enumS S I d  G PS + ScalingMaxS Vector3DS VectorS D D D Ld  8 PS DefaultAttributeIndexS intS IntegerS I d  N PS Lcl TranslationS Lcl TranslationS S AD D DF1!@d  H PS Lcl RotationS Lcl RotationS S AD V@D D Re  F PS Lcl ScalingS Lcl ScalingS S ADO^z@DO^z@DO^z@e  1 PS currentUVSetS KStringS S US map1 e   ShadingCTe   CullingS + CullingOff h  % ModelL`r* S pPlane2 ModelS Mesh4f   VersionI h Properties70f  + PS RotationActiveS boolS S I f  ( PS InheritTypeS enumS S I g  G PS + ScalingMaxS Vector3DS VectorS D D D Wg  8 PS DefaultAttributeIndexS intS IntegerS I g  N PS Lcl TranslationS Lcl TranslationS S AD D D3؈"@ h  H PS Lcl RotationS Lcl RotationS S AD V@D D ]h  F PS Lcl ScalingS Lcl ScalingS S ADO^z@DO^z@DO^z@h  1 PS currentUVSetS KStringS S US map1 h   ShadingCTh   CullingS + CullingOff k  % ModelLpr* S pPlane3 ModelS Mesh?i   VersionI k Properties70i  + PS RotationActiveS boolS S I i  ( PS InheritTypeS enumS S I j  G PS + ScalingMaxS Vector3DS VectorS D D D bj  8 PS DefaultAttributeIndexS intS IntegerS I j  N PS Lcl TranslationS Lcl TranslationS S AD D D` $@k  H PS Lcl RotationS Lcl RotationS S AD V@D D hk  F PS Lcl ScalingS Lcl ScalingS S ADO^z@DO^z@DO^z@k  1 PS currentUVSetS KStringS S US map1 k   ShadingCTk   CullingS + CullingOff o  % ModelL#r* S pPlane4 ModelS MeshJl   VersionI n Properties70l  + PS RotationActiveS boolS S I l  ( PS InheritTypeS enumS S I 'm  G PS + ScalingMaxS Vector3DS VectorS D D D mm  8 PS DefaultAttributeIndexS intS IntegerS I m  N PS Lcl TranslationS Lcl TranslationS S AD D D0&yP&@n  H PS Lcl RotationS Lcl RotationS S AD V@D D sn  F PS Lcl ScalingS Lcl ScalingS S ADO^z@DO^z@DO^z@n  1 PS currentUVSetS KStringS S US map1 n   ShadingCTn   CullingS + CullingOff r  % ModelL,r* S pPlane5 ModelS MeshUo   VersionI q Properties70o  + PS RotationActiveS boolS S I o  ( PS InheritTypeS enumS S I 2p  G PS + ScalingMaxS Vector3DS VectorS D D D xp  8 PS DefaultAttributeIndexS intS IntegerS I p  N PS Lcl TranslationS Lcl TranslationS S AD D Dhܲ %@*q  H PS Lcl RotationS Lcl RotationS S AD V@D D ~q  F PS Lcl ScalingS Lcl ScalingS S ADO^z@DO^z@DO^z@q  1 PS currentUVSetS KStringS S US map1 q   ShadingCTr   CullingS + CullingOff t  & ModelL5r* S persp1 ModelS Cameraar   VersionI t Properties70r  I PS PostRotationS Vector3DS VectorS D D VD +s  + PS RotationActiveS boolS S I @s  ( PS InheritTypeS enumS S I s  G PS + ScalingMaxS Vector3DS VectorS D D D s  8 PS DefaultAttributeIndexS intS IntegerS I 7t  N PS Lcl TranslationS Lcl TranslationS S AD D @D O}hb*@t  H PS Lcl RotationS Lcl RotationS S AD D f@D f@ t   ShadingCYt   CullingS + CullingOff kx  0 ModelL>r* S directionalLight1 ModelS Light;u   VersionI %x Properties70u  K PS RotationOffsetS Vector3DS VectorS Dh 3ZD!R/@D _J?  1 PS currentUVSetS KStringS S US map1 ։   ShadingCT   CullingS + CullingOff i  ' ModelLp* S pPyramid1 ModelS MeshX   VersionI # Properties70  + PS RotationActiveS boolS S I   ( PS InheritTypeS enumS S I 5  G PS + ScalingMaxS Vector3DS VectorS D D D {  8 PS DefaultAttributeIndexS intS IntegerS I ׋  N PS Lcl TranslationS Lcl TranslationS S AD4xK)D?f@D" +@  1 PS currentUVSetS KStringS S US map1 9   ShadingCT\   CullingS + CullingOff 2  ( ModelL"* S transform1 ModelS Null   VersionI  Properties70  + PS RotationActiveS boolS S I D  ( PS InheritTypeS enumS S I   G PS + ScalingMaxS Vector3DS VectorS D D D ߍ  8 PS DefaultAttributeIndexS intS IntegerS I    ShadingCY%   CullingS + CullingOff   * MaterialLH S normalMapTest MaterialS    VersionIf   + ShadingModelS phongɎ   +MultiLayerI  Properties701  A PS AmbientColorS ColorS S AD D D   A PS DiffuseColorS ColorS S AD ?D ?D ?  1 PS DiffuseFactorS NumberS S AD ?  6 PS TransparencyFactorS NumberS S AD ?S  B PS SpecularColorS ColorS S AD ?D ?D ?  4 PS ReflectionFactorS NumberS S AD ?  E PS EmissiveS Vector3DS VectorS D D D :  D PS AmbientS Vector3DS VectorS D D D   D PS DiffuseS Vector3DS VectorS D ?D ?D ?ߑ  E PS SpecularS Vector3DS VectorS D ?D ?D ?  2 PS ShininessS doubleS NumberS D 4@]  0 PS OpacityS doubleS NumberS D ?  5 PS ReflectivityS doubleS NumberS D ו  % MaterialL{ S lambert1 MaterialS    VersionIf 2  ShadingModelS lambertN   +MultiLayerI ʕ Properties70  A PS AmbientColorS ColorS S AD D D   A PS DiffuseColorS ColorS S AD ?D ?D ?D  1 PS DiffuseFactorS NumberS S AD ?  6 PS TransparencyFactorS NumberS S AD ?۔  E PS EmissiveS Vector3DS VectorS D D D -  D PS AmbientS Vector3DS VectorS D D D   D PS DiffuseS Vector3DS VectorS D ?D ?D ?  0 PS OpacityS doubleS NumberS D ?   ( MaterialLp S transparent MaterialS -   VersionIf P  + ShadingModelS phongl   +MultiLayerI  Properties70Ԗ  A PS AmbientColorS ColorS S AD D D #  A PS DiffuseColorS ColorS S AD ?D ?D ?b  1 PS DiffuseFactorS NumberS S AD ?  E PS TransparentColorS ColorS S AD *?D *?D *?  6 PS TransparencyFactorS NumberS S AD ?I  B PS SpecularColorS ColorS S AD ?D ?D ?  5 PS ShininessExponentS NumberS S AD|F?@Θ  4 PS ReflectionFactorS NumberS S AD ?!  E PS EmissiveS Vector3DS VectorS D D D s  D PS AmbientS Vector3DS VectorS D D D ř  D PS DiffuseS Vector3DS VectorS D ?D ?D ?  E PS SpecularS Vector3DS VectorS D ?D ?D ?X  2 PS ShininessS doubleS NumberS D|F?@  0 PS OpacityS doubleS NumberS D $T?ٚ  5 PS ReflectivityS doubleS NumberS D   ' MaterialLD S glasGreen1 MaterialS H   VersionIf k  + ShadingModelS phong   +MultiLayerI  Properties70  A PS AmbientColorS ColorS S AD D D >  A PS DiffuseColorS ColorS S AD D D }  1 PS DiffuseFactorS NumberS S AD ?М  E PS TransparentColorS ColorS S AD D ?D   6 PS TransparencyFactorS NumberS S AD ?d  B PS SpecularColorS ColorS S AD ?D ?D ?  5 PS ShininessExponentS NumberS S AD|F?@  4 PS ReflectionFactorS NumberS S AD ?<  E PS EmissiveS Vector3DS VectorS D D D   D PS AmbientS Vector3DS VectorS D D D   D PS DiffuseS Vector3DS VectorS D D D 3  E PS SpecularS Vector3DS VectorS D ?D ?D ?s  2 PS ShininessS doubleS NumberS D|F?@  0 PS OpacityS doubleS NumberS DVUUUUU?  5 PS ReflectivityS doubleS NumberS D &  $ MaterialLPL S glasRed MaterialS `   VersionIf   + ShadingModelS phong   +MultiLayerI  Properties70  A PS AmbientColorS ColorS S AD D D V  A PS DiffuseColorS ColorS S AD D D   1 PS DiffuseFactorS NumberS S AD ?  E PS TransparentColorS ColorS S AD ?D D ,  6 PS TransparencyFactorS NumberS S AD ?|  B PS SpecularColorS ColorS S AD ?D ?D ?  5 PS ShininessExponentS NumberS S AD|F?@  4 PS ReflectionFactorS NumberS S AD ?T  E PS EmissiveS Vector3DS VectorS D D D   D PS AmbientS Vector3DS VectorS D D D   D PS DiffuseS Vector3DS VectorS D D D K  E PS SpecularS Vector3DS VectorS D ?D ?D ?  2 PS ShininessS doubleS NumberS D|F?@ɤ  0 PS OpacityS doubleS NumberS DVUUUUU?   5 PS ReflectivityS doubleS NumberS D   ' MaterialL0N S glaseBlack MaterialS {   VersionIf   + ShadingModelS phong   +MultiLayerI  Properties70"  A PS AmbientColorS ColorS S AD D D q  A PS DiffuseColorS ColorS S AD D D   1 PS DiffuseFactorS NumberS S AD ?  6 PS TransparencyFactorS NumberS S AD ?D  B PS SpecularColorS ColorS S AD ?D ?D ?  5 PS ShininessExponentS NumberS S AD|F?@ɧ  4 PS ReflectionFactorS NumberS S AD ?  E PS EmissiveS Vector3DS VectorS D D D n  D PS AmbientS Vector3DS VectorS D D D   D PS DiffuseS Vector3DS VectorS D D D   E PS SpecularS Vector3DS VectorS D ?D ?D ?S  2 PS ShininessS doubleS NumberS D|F?@  0 PS OpacityS doubleS NumberS D ?ԩ  5 PS ReflectivityS doubleS NumberS D   % MaterialLP S glasBlue MaterialS A   VersionIf d  + ShadingModelS phong   +MultiLayerI  Properties70  A PS AmbientColorS ColorS S AD D D 7  A PS DiffuseColorS ColorS S AD D D v  1 PS DiffuseFactorS NumberS S AD ?ɫ  E PS TransparentColorS ColorS S AD D D ?   6 PS TransparencyFactorS NumberS S AD ?]  B PS SpecularColorS ColorS S AD ?D ?D ?  5 PS ShininessExponentS NumberS S AD|F?@  4 PS ReflectionFactorS NumberS S AD ?5  E PS EmissiveS Vector3DS VectorS D D D   D PS AmbientS Vector3DS VectorS D D D ٭  D PS DiffuseS Vector3DS VectorS D D D ,  E PS SpecularS Vector3DS VectorS D ?D ?D ?l  2 PS ShininessS doubleS NumberS D|F?@  0 PS OpacityS doubleS NumberS DVUUUUU?  5 PS ReflectivityS doubleS NumberS D <  ) MaterialL` S emissiveTest MaterialS ^   VersionIf   ShadingModelS unknown   +MultiLayerI / Properties70  PS MayaS CompoundS S "  . PS Maya|TypeIdS intS IntegerS I   ) MaterialLQ S specularTest MaterialS    VersionIf   + ShadingModelS phongҰ   +MultiLayerI  Properties70:  A PS AmbientColorS ColorS S AD D D   A PS DiffuseColorS ColorS S AD D D ȱ  1 PS DiffuseFactorS NumberS S AD ?   6 PS TransparencyFactorS NumberS S AD ?\  B PS SpecularColorS ColorS S AD "?D "?D "?  5 PS ShininessExponentS NumberS S AD|F?@  4 PS ReflectionFactorS NumberS S AD ?4  E PS EmissiveS Vector3DS VectorS D D D   D PS AmbientS Vector3DS VectorS D D D س  D PS DiffuseS Vector3DS VectorS D D D +  E PS SpecularS Vector3DS VectorS D "?D "?D "?k  2 PS ShininessS doubleS NumberS D|F?@  0 PS OpacityS doubleS NumberS D ?  5 PS ReflectivityS doubleS NumberS D   # VideoL S file2 VideoS ClipU  TypeS Clip Properties70  PS PathS KStringS XRefUrlS S\ C:/Users/Destranix/Documents/maya/projects/Test/images/Tardis_Displacement/Wood_007_ROUGH.tx +   UseMipMapI   a FilenameS\ C:/Users/Destranix/Documents/maya/projects/Test/images/Tardis_Displacement/Wood_007_ROUGH.tx  1 RelativeFilenameS, resources\textures\Tardis_Displacement\Wood_007_ROUGH.tx   ! TextureL# S file2 TextureS W   TypeS TextureVideoClipp   VersionI    TextureNameS file2 Texturep Properties70  4 PS CurrentTextureBlendModeS enumS S I -  ) PS UVSetS KStringS S S map1c  ( PS UseMaterialS boolS S I    MediaS file2 Video   a FileNameS\ C:/Users/Destranix/Documents/maya/projects/Test/images/Tardis_Displacement/Wood_007_ROUGH.txW  1 RelativeFilenameS, resources\textures\Tardis_Displacement\Wood_007_ROUGH.tx   ModelUVTranslationD D    ModelUVScalingD ?D ?߹  Texture_Alpha_SourceS None   CroppingI I I I   > ImplementationLv* S+ emissiveTest_Implementation ImplementationS    VersionId  Properties70ߺ  1 PS ShaderLanguageS KStringS S S SFX$  7 PS ShaderLanguageVersionS KStringS S S 28[  ) PS RenderAPIS KStringS S S   3 PS RootBindingNameS KStringS S S root  ( PS ShaderGraphS BlobS S I    +BinaryDataR SFX_WIN +Version=28 +GroupVersion=-1.000000 +Advanced=0 +HelpID=0 +ParentMaterial=0 +NumberOfNodes=5 +#NT=10100 1 Hw Material Base-Hw Shader Nodes-Core + PC=35 + name=1 v=5000 _Material + version=1 v=2003 1.842000 + posx=1 v=2003 10.000000 + posy=1 v=2003 10.000000 + classname=1 v=5000 Hw Material Base + submenuname=1 v=5000 Core + bitmapnodeindex=1 v=2002 10 + isadvanced=1 v=2001 1 + advanceddelete=1 v=2001 1 + helpid=1 v=2002 73 + grpnodecolor=1 v=5012 4 + grpPosX=1 v=2003 -1129.380005 + grpPosY=1 v=2003 -143.923004 + disableconsolidation_HwShader=2 e=1 v=2001 0 + value_ClampDynamicLights=2 e=1 v=2002 99 + value_MaxNumberLights=2 e=1 v=2002 3 + value_Gamma=2 e=2 v=2001 0 + value_Wireframe=2 e=3 v=2001 0 + value_DepthTest=2 e=4 v=2001 1 + value_DepthWrite=2 e=4 v=2001 1 + value_CastShadow=2 e=5 v=2001 1 + value_SurfaceMaskCutoff=2 e=6 v=2003 0.000000 + value_SSAO=2 e=7 v=2001 1 + options_Tessellation=2 e=900 v=5012 0 + value_FlatTessellationBlend=2 e=901 v=2003 0.000000 + value_BoundingBoxMultiplier=2 e=902 v=2003 1.000000 + value_ClippingBiasAdd=2 e=902 v=2003 5.000000 + options_Displacement=2 e=1000 v=5012 1 + options_VDM_CoordSys=2 e=1001 v=5012 1 + value_DisplacementMultiplier=2 e=1002 v=2003 1.000000 + value_DisplacementOffset=2 e=1003 v=2003 0.000000 + cgfxprofile_HwShader=2 e=1999 v=5012 0 + config_HwShader=2 e=2000 v=5012 1 + shadername_HwShader=2 e=2001 v=5000 + saveshadertodisk_HwShader=2 e=2002 v=5015 + group=-1 + ISC=9 + SVT=2002 2002 0 0 0 _NumberOfLights + SVT=5001 3002 0 0 0 _ObjectVertexPosition + SVT=5001 2003 0 0 0 + SVT=5001 3002 0 0 0 _Displacement + SVT=5001 5018 0 0 0 _SurfaceShader + SVT=5001 2003 0 0 0 _SurfaceMask + SVT=5001 2003 0 0 0 _SurfaceMaskCutoff + SVT=2001 2001 0 0 0 _Gamma + SVT=1001 1002 0 0 0 + OSC=0 +#NT=10100 1 Traditional Game Surface Shader-Hw Shader Nodes-Surface Shaders + PC=26 + name=1 v=5000 TraditionalGameSurfaceShader + version=1 v=2003 1.481000 + posx=1 v=2003 -200.000000 + posy=1 v=2003 10.000000 + previewswatch=1 v=2002 2 + classname=1 v=5000 Traditional Game Surface Shader + submenuname=1 v=5000 Surface Shaders + bitmapnodeindex=1 v=2002 10 + isadvanced=1 v=2001 1 + advanceddelete=1 v=2001 1 + helpid=1 v=2002 74 + grpnodecolor=1 v=5012 4 + grpPosX=1 v=2003 -990.607971 + grpPosY=1 v=2003 169.649994 + options_Diffuse=2 e=1 v=5012 0 + options_Specular=2 e=1 v=5012 0 + value_FlipBackFaces=2 e=1 v=2001 1 + value_TranslucencyDistortion=2 e=1100 v=2003 0.200000 + value_TranslucencyPower=2 e=1101 v=2003 3.000000 + value_TranslucencyMinimum=2 e=1102 v=2003 0.000000 + color_TranslucencyOuter=2 e=1104 v=3003 1.000000,0.640000,0.250000,1.000000 + color_TranslucencyMedium=2 e=1105 v=3003 1.000000,0.210000,0.140000,1.000000 + color_TranslucencyInner=2 e=1106 v=3003 0.250000,0.050000,0.020000,1.000000 + value_UseStreamLightData=2 e=1500 v=2001 0 + value_BakedLightColorSet=2 e=1502 v=5000 BakedLightColorSet + value_BakedLightColorSetUnshared=2 e=1503 v=2001 1 + group=-1 + ISC=17 + SVT=5001 2003 0 0 0 _Opacity + SVT=5001 3002 0 0 0 _Emissive + SVT=5001 2003 0 0 0 _AmbientOcclusion + SVT=5001 3002 0 0 0 _DiffuseColor + SVT=5001 2003 0 0 0 _SpecularPower + SVT=5001 3002 0 0 0 _SpecularColor + SVT=5001 3002 0 0 0 _Reflection + SVT=5001 2003 0 0 0 _ReflectionIntensity + SVT=5001 3002 0 0 0 _Normal + SVT=5001 3002 0 0 0 _ObjectThickness + SVT=5001 2003 0 0 0 _BlendedNormal + SVT=5001 2003 0 0 0 _BlendedNormalMask + SVT=5001 3002 0 0 0 _AnisotropicDirection + SVT=5001 3001 0 0 0 _AnisotropicSpread + SVT=5001 3002 0 0 0 _IBL + SVT=5001 2003 0 0 0 _Weight + SVT=1001 1002 0 0 0 + OSC=2 + SVT=5001 5018 0 _SurfaceShader + CC=1 + C=1 0 0 0 4 0 0 + CPC=0 + SVT=1001 1002 0 + CC=0 +#NT=20011 0 + PC=3 + posx=1 v=2003 -567.500000 + posy=1 v=2003 135.000000 + color=2 e=0 v=3003 0.159091,0.159091,0.159091,1.000000 + group=-1 + ISC=0 + OSC=6 + SVT=5001 3003 1 + CC=0 + SVT=5001 3002 2 + CC=1 + C=2 1 2 1 3 0 0 + CPC=0 + SVT=5001 2003 3 + CC=0 + SVT=5001 2003 4 + CC=0 + SVT=5001 2003 5 + CC=0 + SVT=5001 2003 6 + CC=0 +#NT=20011 0 + PC=3 + posx=1 v=2003 -490.500000 + posy=1 v=2003 -45.000000 + color=2 e=0 v=3003 0.462700,0.000000,0.839200,1.000000 + group=-1 + ISC=0 + OSC=6 + SVT=5001 3003 1 + CC=0 + SVT=5001 3002 2 + CC=1 + C=3 1 2 1 1 0 0 + CPC=0 + SVT=5001 2003 3 + CC=0 + SVT=5001 2003 4 + CC=0 + SVT=5001 2003 5 + CC=0 + SVT=5001 2003 6 + CC=0 +#NT=20011 0 + PC=3 + posx=1 v=2003 -537.305542 + posy=1 v=2003 315.972229 + color=2 e=0 v=3003 0.164773,0.164773,0.164773,1.000000 + group=-1 + ISC=0 + OSC=6 + SVT=5001 3003 1 + CC=0 + SVT=5001 3002 2 + CC=1 + C=4 1 2 1 5 0 0 + CPC=0 + SVT=5001 2003 3 + CC=0 + SVT=5001 2003 4 + CC=0 + SVT=5001 2003 5 + CC=0 + SVT=5001 2003 6 + CC=0 +   ' BindingTableL0 S root 1 BindingTableS k   VersionId  Properties70  . PS + TargetNameS KStringS S S root  0 PS + TargetTypeS KStringS S S shader   & AnimationStackLB S Take 001 AnimStackS } Properties70  0 PS + LocalStartS KTimeS TimeS LR^r   / PS LocalStopS KTimeS TimeS Lp65 /  4 PS ReferenceStartS KTimeS TimeS LR^r p  3 PS ReferenceStopS KTimeS TimeS Lp65   ' AnimationLayerLp k* S BaseLayer AnimLayerS   , AnimationCurveNodeL0C S Visibility AnimCurveNodeS  Properties70  4 PS d|VisibilityS + VisibilityS S AD ?   # AnimationCurveNodeL B S T AnimCurveNodeS  Properties70)  ' PS d|XS NumberS S ADF e:׿^  ' PS d|YS NumberS S AD +t%@  ' PS d|ZS NumberS S AD`dM?   # AnimationCurveNodeLB S S AnimCurveNodeS  Properties70=  ' PS d|XS NumberS S AD ?r  ' PS d|YS NumberS S AD ?  ' PS d|ZS NumberS S AD ?   # AnimationCurveNodeL`B S R AnimCurveNodeS  Properties70Q  ' PS d|XS NumberS S AD   ' PS d|YS NumberS S AD   ' PS d|ZS NumberS S AD 5   AnimationCurveL` S AnimCurveS +  DefaultD C   KeyVerI l   KeyTimel  R^r    KeyValueFloatf  ?   KeyAttrFlagsi      KeyAttrDataFloatf    (   KeyAttrRefCounti      AnimationCurveL` S AnimCurveS   DefaultD    KeyVerI    KeyTimel  R^r    KeyValueFloatf  -ӹ!   KeyAttrFlagsi  a [   KeyAttrDataFloatf       KeyAttrRefCounti      AnimationCurveL ` S AnimCurveS   DefaultD    KeyVerI ,   KeyTimel  R^r W   KeyValueFloatf  }@   KeyAttrFlagsi  a    KeyAttrDataFloatf       KeyAttrRefCounti   U   AnimationCurveL` S AnimCurveS K  DefaultD c   KeyVerI    KeyTimel  R^r    KeyValueFloatf  {m?   KeyAttrFlagsi  a    KeyAttrDataFloatf    H   KeyAttrRefCounti      AnimationCurveL` S AnimCurveS   DefaultD    KeyVerI    KeyTimel  R^r    KeyValueFloatf  ?A   KeyAttrFlagsi  a {   KeyAttrDataFloatf       KeyAttrRefCounti      AnimationCurveL ` S AnimCurveS   DefaultD #   KeyVerI L   KeyTimel  R^r w   KeyValueFloatf  ?   KeyAttrFlagsi  a    KeyAttrDataFloatf       KeyAttrRefCounti   u   AnimationCurveL~` S AnimCurveS k  DefaultD    KeyVerI    KeyTimel  R^r    KeyValueFloatf  ?   KeyAttrFlagsi  a ;   KeyAttrDataFloatf    h   KeyAttrRefCounti      AnimationCurveL` S AnimCurveS   DefaultD    KeyVerI    KeyTimel  R^r 7   KeyValueFloatf  a   KeyAttrFlagsi  a    KeyAttrDataFloatf       KeyAttrRefCounti   5   AnimationCurveL` S AnimCurveS +  DefaultD C   KeyVerI l   KeyTimel  R^r    KeyValueFloatf     KeyAttrFlagsi  a    KeyAttrDataFloatf    (   KeyAttrRefCounti      AnimationCurveL`` S AnimCurveS   DefaultD    KeyVerI    KeyTimel  R^r    KeyValueFloatf  !   KeyAttrFlagsi  a [   KeyAttrDataFloatf       KeyAttrRefCounti    Connections   CS OOL0q* L    CS OOL@q* L /   CS OOLPr* L V   CS OOL`r* L }   CS OOLpr* L    CS OOL#r* L    CS OOL,r* L    CS OOL5r* L    CS OOL>r* L @   CS OOLGr* L g   CS OOL * L    CS OOL0* L    CS OOL@* L    CS OOLP* L    CS OOL`* L *   CS OOLp* L Q   CS OOL"* L x   CS OOLp k* LB    CS OOL0C Lp k*    CS OOL B Lp k*    CS OOLB Lp k*    CS OOL`B Lp k* I  ' CS OPL# LH S NormalMapp   CS OOL L#    CS OOL* L0q*    CS OOLH L0q*   - CS OPL B L0q* S Lcl Translation1  * CS OPL`B L0q* S Lcl Rotationh  ) CS OPLB L0q* S Lcl Scaling  ( CS OPL0C L0q* S + Visibility   CS OOLҍ* L@q*    CS OOL{ L@q*    CS OOLД* LPr* :   CS OOLp LPr* a   CS OOLЪ* L`r*    CS OOLp L`r*    CS OOLЬ* Lpr*    CS OOLp Lpr*    CS OOLИ* L#r* $   CS OOLp L#r* K   CS OOLТ* L,r* r   CS OOLp L,r*    CS OOLp_ L5r*    CS OOLȱ L>r*    CS OOLލ* LGr*    CS OOLD LGr* 5   CS OOLPL LGr* \   CS OOL0N LGr*    CS OOLP LGr*    CS OOLč* L *    CS OOLD L *    CS OOLPL L *    CS OOL0N L * F   CS OOLP L * m   CS OOLМ* L0*    CS OOLD L0*    CS OOLPL L0*    CS OOL0N L0*    CS OOLP L0* 0   CS OOLЍ* L@* W   CS OOLD L@* ~   CS OOLPL L@*    CS OOL0N L@*    CS OOLP L@*    CS OOLм* LP*    CS OOLD LP* A   CS OOLPL LP* h   CS OOL0N LP*    CS OOLP LP*    CS OOL` Lv*    CS OOL0 Lv*    CS OOL΍* L`* +   CS OOL` L`* R   CS OOL* Lp* y   CS OOLQ Lp*    CS OOL$ L"*   * CS OPL` L0C S d|Visibility  ! CS OPL` L B S d|X6  ! CS OPL ` L B S d|Ye  ! CS OPL` L B S d|Z  ! CS OPL` LB S d|X  ! CS OPL ` LB S d|Y  ! CS OPL~` LB S d|Z!  ! CS OPL` L`B S d|XP  ! CS OPL` L`B S d|Y  ! CS OPL`` L`B S d|Z q Takes  CurrentS Take 001d  TakeS Take 001   FileNameS Take_001.tak+   LocalTimeLR^r Lp65 W   ReferenceTimeLR^r Lp65 e"s  Zj~ u) \ No newline at end of file diff --git a/test/models/glTF2/cameras/Cameras.gltf b/test/models/glTF2/cameras/Cameras.gltf new file mode 100644 index 000000000..25e9e24a3 --- /dev/null +++ b/test/models/glTF2/cameras/Cameras.gltf @@ -0,0 +1,98 @@ +{ + "scenes" : [ + { + "nodes" : [ 0, 1, 2 ] + } + ], + "nodes" : [ + { + "rotation" : [ -0.383, 0.0, 0.0, 0.92375 ], + "mesh" : 0 + }, + { + "translation" : [ 0.5, 0.5, 3.0 ], + "camera" : 0 + }, + { + "translation" : [ 0.5, 0.5, 3.0 ], + "camera" : 1 + } + ], + + "cameras" : [ + { + "type": "perspective", + "perspective": { + "aspectRatio": 1.0, + "yfov": 0.7, + "zfar": 100, + "znear": 0.01 + } + }, + { + "type": "orthographic", + "orthographic": { + "xmag": 1.0, + "ymag": 1.0, + "zfar": 100, + "znear": 0.01 + } + } + ], + + "meshes" : [ + { + "primitives" : [ { + "attributes" : { + "POSITION" : 1 + }, + "indices" : 0 + } ] + } + ], + + "buffers" : [ + { + "uri" : "simpleSquare.bin", + "byteLength" : 60 + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteOffset" : 0, + "byteLength" : 12, + "target" : 34963 + }, + { + "buffer" : 0, + "byteOffset" : 12, + "byteLength" : 48, + "target" : 34962 + } + ], + "accessors" : [ + { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 6, + "type" : "SCALAR", + "max" : [ 3 ], + "min" : [ 0 ] + }, + { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 4, + "type" : "VEC3", + "max" : [ 1.0, 1.0, 0.0 ], + "min" : [ 0.0, 0.0, 0.0 ] + } + ], + + "asset" : { + "version" : "2.0" + } +} diff --git a/test/models/glTF2/cameras/simpleSquare.bin b/test/models/glTF2/cameras/simpleSquare.bin new file mode 100644 index 000000000..a6edb3b0d Binary files /dev/null and b/test/models/glTF2/cameras/simpleSquare.bin differ diff --git a/test/models/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.bin b/test/models/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.bin new file mode 100644 index 000000000..7b14a1793 Binary files /dev/null and b/test/models/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.bin differ diff --git a/test/models/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.gltf b/test/models/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.gltf new file mode 100644 index 000000000..b1b720147 --- /dev/null +++ b/test/models/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.gltf @@ -0,0 +1,282 @@ +{ + "accessors": [ + { + "bufferView": 0, + "componentType": 5126, + "count": 24, + "type": "VEC3" + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 24, + "type": "VEC4" + }, + { + "bufferView": 2, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "max": [ + 0.0100000035, + 0.0100000035, + 0.01 + ], + "min": [ + -0.0100000044, + -0.0100000054, + -0.01 + ] + }, + { + "bufferView": 3, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "name": "thin" + }, + { + "bufferView": 4, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "max": [ + 0.0, + 0.01893253, + 0.0 + ], + "min": [ + 0.0, + 0.0, + 0.0 + ], + "name": "thin" + }, + { + "bufferView": 5, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "name": "thin" + }, + { + "bufferView": 6, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "name": "angle" + }, + { + "bufferView": 7, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "max": [ + 0.0, + 0.0198908355, + 0.0 + ], + "min": [ + 0.0, + 0.0, + 0.0 + ], + "name": "angle" + }, + { + "bufferView": 8, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "name": "angle" + }, + { + "bufferView": 9, + "componentType": 5123, + "count": 36, + "type": "SCALAR" + }, + { + "bufferView": 10, + "componentType": 5126, + "count": 127, + "type": "SCALAR", + "max": [ + 4.19999743 + ], + "min": [ + 0.0 + ] + }, + { + "bufferView": 11, + "componentType": 5126, + "count": 254, + "type": "SCALAR" + } + ], + "animations": [ + { + "channels": [ + { + "sampler": 0, + "target": { + "node": 0, + "path": "weights" + } + } + ], + "samplers": [ + { + "input": 10, + "interpolation": "LINEAR", + "output": 11 + } + ], + "name": "Square" + } + ], + "asset": { + "generator": "glTF Tools for Unity", + "version": "2.0" + }, + "bufferViews": [ + { + "buffer": 0, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 288, + "byteLength": 384 + }, + { + "buffer": 0, + "byteOffset": 672, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 960, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 1248, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 1536, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 1824, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 2112, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 2400, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 2688, + "byteLength": 72 + }, + { + "buffer": 0, + "byteOffset": 2760, + "byteLength": 508 + }, + { + "buffer": 0, + "byteOffset": 3268, + "byteLength": 1016 + } + ], + "buffers": [ + { + "uri": "AnimatedMorphCube.bin", + "byteLength": 4284 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 0, + "TANGENT": 1, + "POSITION": 2 + }, + "indices": 9, + "material": 0, + "targets": [ + { + "NORMAL": 3, + "POSITION": 4, + "TANGENT": 5 + }, + { + "NORMAL": 6, + "POSITION": 7, + "TANGENT": 8 + } + ] + } + ], + "weights": [ + 0.0, + 0.0 + ], + "name": "Cube" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorFactor": [ + 0.6038274, + 0.6038274, + 0.6038274, + 1.0 + ], + "metallicFactor": 0.0, + "roughnessFactor": 0.5 + }, + "name": "Material" + } + ], + "nodes": [ + { + "mesh": 0, + "rotation": [ + 0.0, + 0.7071067, + -0.7071068, + 0.0 + ], + "scale": [ + 100.0, + 100.0, + 100.0 + ], + "name": "AnimatedMorphCube" + } + ], + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ] +} \ No newline at end of file diff --git a/test/unit/SceneDiffer.cpp b/test/unit/SceneDiffer.cpp index fb000db29..684d9fee6 100644 --- a/test/unit/SceneDiffer.cpp +++ b/test/unit/SceneDiffer.cpp @@ -123,7 +123,7 @@ void SceneDiffer::showReport() { return; } - for ( std::vector::iterator it = m_diffs.begin(); it != m_diffs.end(); it++ ) { + for ( std::vector::iterator it = m_diffs.begin(); it != m_diffs.end(); ++it ) { std::cout << *it << "\n"; } diff --git a/test/unit/utFBXImporterExporter.cpp b/test/unit/utFBXImporterExporter.cpp index e597b23ff..1445e3c3e 100644 --- a/test/unit/utFBXImporterExporter.cpp +++ b/test/unit/utFBXImporterExporter.cpp @@ -276,3 +276,9 @@ TEST_F(utFBXImporterExporter, importEmbeddedFragmentedAsciiTest) { ASSERT_TRUE(scene->mTextures[0]->pcData); ASSERT_EQ(968029u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression splits data by 512Kb, it should be two parts for this texture"; } + +TEST_F(utFBXImporterExporter, fbxTokenizeTestTest) { + //Assimp::Importer importer; + //const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/transparentTest2.fbx", aiProcess_ValidateDataStructure); + //EXPECT_NE(nullptr, scene); +} diff --git a/test/unit/utVersion.cpp b/test/unit/utVersion.cpp index 5cfc91ccd..233b2fb0b 100644 --- a/test/unit/utVersion.cpp +++ b/test/unit/utVersion.cpp @@ -4,8 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2019, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -55,11 +53,11 @@ TEST_F( utVersion, aiGetLegalStringTest ) { } TEST_F( utVersion, aiGetVersionMinorTest ) { - EXPECT_EQ( aiGetVersionMinor(), 1U ); + EXPECT_EQ( aiGetVersionMinor(), 0U ); } TEST_F( utVersion, aiGetVersionMajorTest ) { - EXPECT_EQ( aiGetVersionMajor(), 4U ); + EXPECT_EQ( aiGetVersionMajor(), 5U ); } TEST_F( utVersion, aiGetCompileFlagsTest ) { diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 0ba5226cc..829d31451 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -375,9 +375,25 @@ TEST_F( utglTF2ImportExport, bug_import_simple_skin ) { EXPECT_NE( nullptr, scene ); } +TEST_F(utglTF2ImportExport, import_cameras) { + Assimp::Importer importer; + const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/cameras/Cameras.gltf", + aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); +} + #ifndef ASSIMP_BUILD_NO_EXPORT TEST_F( utglTF2ImportExport, exportglTF2FromFileTest ) { EXPECT_TRUE( exporterTest() ); } +TEST_F( utglTF2ImportExport, crash_in_anim_mesh_destructor ) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.gltf", + aiProcess_ValidateDataStructure); + ASSERT_NE( nullptr, scene ); + Assimp::Exporter exporter; + ASSERT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube_out.glTF")); +} + #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/tools/assimp_qt_viewer/CMakeLists.txt b/tools/assimp_qt_viewer/CMakeLists.txt deleted file mode 100644 index d8d8e27a9..000000000 --- a/tools/assimp_qt_viewer/CMakeLists.txt +++ /dev/null @@ -1,76 +0,0 @@ -set(PROJECT_VERSION "") -project(assimp_qt_viewer) - -# Qt5 requires cmake 3.1 or newer -cmake_minimum_required(VERSION 3.1) - -FIND_PACKAGE(OpenGL QUIET) - -# Qt5 version -FIND_PACKAGE(Qt5 COMPONENTS Gui Widgets OpenGL QUIET) - -SET(VIEWER_BUILD:BOOL FALSE) - -IF( Qt5Widgets_FOUND AND OPENGL_FOUND) - SET(VIEWER_BUILD TRUE) -ELSE( Qt5Widgets_FOUND AND OPENGL_FOUND) - SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "") - - IF (NOT Qt5_FOUND) - SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} Qt5") - ENDIF (NOT Qt5_FOUND) - - IF (NOT OPENGL_FOUND) - SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} OpengGL") - ENDIF (NOT OPENGL_FOUND) - - MESSAGE (WARNING "Build of assimp_qt_viewer is disabled. Unsatisfied dendencies: ${ASSIMP_QT_VIEWER_DEPENDENCIES}") -ENDIF( Qt5Widgets_FOUND AND OPENGL_FOUND) - -IF(VIEWER_BUILD) - INCLUDE_DIRECTORIES( - ${Assimp_SOURCE_DIR}/include - ${Assimp_SOURCE_DIR}/code - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${OPENGL_INCLUDE_DIR} - ) - - LINK_DIRECTORIES(${Assimp_BINARY_DIR}) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pedantic -Wall") - - SET(assimp_qt_viewer_SRCS - main.cpp - loggerview.hpp - loggerview.cpp - glview.hpp - glview.cpp - mainwindow.hpp - mainwindow.cpp - ) - - MESSAGE("assimp_qt_viewer use Qt5") - INCLUDE_DIRECTORIES(${Qt5Widgets_INCLUDES}) - qt5_wrap_ui(UISrcs mainwindow.ui) - qt5_wrap_cpp(MOCrcs mainwindow.hpp glview.hpp) - - add_executable(${PROJECT_NAME} ${assimp_qt_viewer_SRCS} ${UISrcs} ${MOCrcs}) - target_link_libraries(${PROJECT_NAME} Qt5::Gui Qt5::Widgets Qt5::OpenGL ${OPENGL_LIBRARIES} assimp) - - IF(WIN32) # Check if we are on Windows - IF(MSVC) # Check if we are using the Visual Studio compiler - #set_target_properties(TestProject PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") - ELSEIF(CMAKE_COMPILER_IS_GNUCXX) - # SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") # Not tested - ELSE() - MESSAGE(SEND_ERROR "You are using an unsupported Windows compiler! (Not MSVC or GCC)") - ENDIF() - ELSEIF(UNIX) - # Nothing special required - ELSE() - MESSAGE(SEND_ERROR "You are on an unsupported platform! (Not Win32 or Unix)") - ENDIF() - - SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) - INSTALL(TARGETS assimp_qt_viewer DESTINATION "${ASSIMP_BIN_INSTALL_DIR}") -ENDIF(VIEWER_BUILD) diff --git a/tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (en).odt b/tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (en).odt deleted file mode 100644 index 6e4e8c193..000000000 Binary files a/tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (en).odt and /dev/null differ diff --git a/tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (ru).odt b/tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (ru).odt deleted file mode 100644 index 6bd8f8dbb..000000000 Binary files a/tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (ru).odt and /dev/null differ diff --git a/tools/assimp_qt_viewer/glview.cpp b/tools/assimp_qt_viewer/glview.cpp deleted file mode 100644 index 97eba83a1..000000000 --- a/tools/assimp_qt_viewer/glview.cpp +++ /dev/null @@ -1,1161 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -#include "glview.hpp" - -// Header files, Qt. -#include - -// Header files, OpenGL. -#if defined(__APPLE__) -# include -#else -# include -#endif - -// Header files, DevIL. - -// Header files, Assimp. -#include - -#define STB_IMAGE_IMPLEMENTATION -#include "contrib/stb_image/stb_image.h" - -CGLView::SHelper_Mesh::SHelper_Mesh(const size_t pQuantity_Point, const size_t pQuantity_Line, const size_t pQuantity_Triangle, const SBBox& pBBox) -: Quantity_Point(pQuantity_Point) -, Quantity_Line(pQuantity_Line) -, Quantity_Triangle(pQuantity_Triangle) -, BBox(pBBox) { - Index_Point = pQuantity_Point ? new GLuint[pQuantity_Point * 1] : nullptr; - Index_Line = pQuantity_Line ? new GLuint[pQuantity_Line * 2] : nullptr; - Index_Triangle = pQuantity_Triangle ? new GLuint[pQuantity_Triangle * 3] : nullptr; -} - -CGLView::SHelper_Mesh::~SHelper_Mesh() { - delete [] Index_Point; - delete [] Index_Line; - delete [] Index_Triangle; -} - -void CGLView::SHelper_Camera::SetDefault() { - Position.Set(0, 0, 0); - Target.Set(0, 0, -1); - Rotation_AroundCamera = aiMatrix4x4(); - Rotation_Scene = aiMatrix4x4(); - Translation_ToScene.Set(0, 0, 2); -} - -static void set_float4(float f[4], float a, float b, float c, float d) { - f[0] = a; - f[1] = b; - f[2] = c; - f[3] = d; -} - -static void color4_to_float4(const aiColor4D *c, float f[4]) { - f[0] = c->r; - f[1] = c->g; - f[2] = c->b; - f[3] = c->a; -} - -void CGLView::Material_Apply(const aiMaterial* pMaterial) { - GLfloat tcol[4]; - aiColor4D taicol; - unsigned int max; - int ret1, ret2; - int texture_index = 0; - aiString texture_path; - - ///TODO: cache materials - // Disable color material because glMaterial is used. - glDisable(GL_COLOR_MATERIAL);///TODO: cache - - // Set texture. If assigned. - if(AI_SUCCESS == pMaterial->GetTexture(aiTextureType_DIFFUSE, texture_index, &texture_path)) { - //bind texture - unsigned int texture_ID = mTexture_IDMap.value(texture_path.data, 0); - - glBindTexture(GL_TEXTURE_2D, texture_ID); - } - // - // Set material parameters from scene or default values. - // - // Diffuse - set_float4(tcol, 0.8f, 0.8f, 0.8f, 1.0f); - if ( AI_SUCCESS == aiGetMaterialColor( pMaterial, AI_MATKEY_COLOR_DIFFUSE, &taicol )) { - color4_to_float4( &taicol, tcol ); - } - - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, tcol); - - // Specular - set_float4(tcol, 0.0f, 0.0f, 0.0f, 1.0f); - if ( AI_SUCCESS == aiGetMaterialColor( pMaterial, AI_MATKEY_COLOR_SPECULAR, &taicol )) { - color4_to_float4( &taicol, tcol ); - } - - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, tcol); - // Ambient - set_float4(tcol, 0.2f, 0.2f, 0.2f, 1.0f); - if ( AI_SUCCESS == aiGetMaterialColor( pMaterial, AI_MATKEY_COLOR_AMBIENT, &taicol )) { - color4_to_float4( &taicol, tcol ); - } - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, tcol); - - // Emission - set_float4(tcol, 0.0f, 0.0f, 0.0f, 1.0f); - if(AI_SUCCESS == aiGetMaterialColor(pMaterial, AI_MATKEY_COLOR_EMISSIVE, &taicol)) color4_to_float4(&taicol, tcol); - - glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, tcol); - // Shininess - ai_real shininess, strength; - - max = 1; - ret1 = aiGetMaterialFloatArray(pMaterial, AI_MATKEY_SHININESS, &shininess, &max); - // Shininess strength - max = 1; - ret2 = aiGetMaterialFloatArray(pMaterial, AI_MATKEY_SHININESS_STRENGTH, &strength, &max); - if((ret1 == AI_SUCCESS) && (ret2 == AI_SUCCESS)) { - glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength);///TODO: cache - } else { - glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f);///TODO: cache - set_float4(tcol, 0.0f, 0.0f, 0.0f, 0.0f); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, tcol); - } - - // Fill mode - GLenum fill_mode; - int wireframe; - - max = 1; - if(AI_SUCCESS == aiGetMaterialIntegerArray(pMaterial, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max)) - fill_mode = wireframe ? GL_LINE : GL_FILL; - else - fill_mode = GL_FILL; - - glPolygonMode(GL_FRONT_AND_BACK, fill_mode);///TODO: cache - // Fill side - int two_sided; - - max = 1; - if((AI_SUCCESS == aiGetMaterialIntegerArray(pMaterial, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided)///TODO: cache - glDisable(GL_CULL_FACE); - else - glEnable(GL_CULL_FACE); -} - -void CGLView::Matrix_NodeToRoot(const aiNode* pNode, aiMatrix4x4& pOutMatrix) -{ - const aiNode* node_cur; - std::list mat_list; - - pOutMatrix = aiMatrix4x4(); - // starting walk from current element to root - node_cur = pNode; - if(node_cur != nullptr) - { - do - { - // if cur_node is group then store group transformation matrix in list. - mat_list.push_back(node_cur->mTransformation); - node_cur = node_cur->mParent; - } while(node_cur != nullptr); - } - - // multiply all matrices in reverse order - for ( std::list::reverse_iterator rit = mat_list.rbegin(); rit != mat_list.rend(); rit++) - { - pOutMatrix = pOutMatrix * (*rit); - } -} - -void CGLView::ImportTextures(const QString& scenePath) { - auto LoadTexture = [&](const QString& pFileName) -> bool ///TODO: IME texture mode, operation. - { - GLuint id_ogl_texture;// OpenGL texture ID. - - if(!pFileName.startsWith(AI_EMBEDDED_TEXNAME_PREFIX)) - { - QString basepath = scenePath.left(scenePath.lastIndexOf('/') + 1);// path with '/' at the end. - QString fileloc = (basepath + pFileName); - - fileloc.replace('\\', "/"); - int x, y, n; - unsigned char *data = stbi_load(fileloc.toLocal8Bit(), &x, &y, &n, STBI_rgb_alpha ); - if ( nullptr == data ) { - LogError(QString("Couldn't load Image: %1").arg(fileloc)); - - return false; - } - - // Convert every colour component into unsigned byte. If your image contains alpha channel you can replace IL_RGB with IL_RGBA. - - glGenTextures(1, &id_ogl_texture);// Texture ID generation. - mTexture_IDMap[pFileName] = id_ogl_texture;// save texture ID for filename in map - glBindTexture(GL_TEXTURE_2D, id_ogl_texture);// Binding of texture ID. - // Redefine standard texture values - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// We will use linear interpolation for magnification filter. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);// We will use linear interpolation for minifying filter. - glTexImage2D(GL_TEXTURE_2D, 0, n, x, y, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, data );// Texture specification. - stbi_image_free(data); - // Cleanup - } - else - { - struct SPixel_Description - { - const char* FormatHint; - const GLint Image_InternalFormat; - const GLint Pixel_Format; - }; - - constexpr SPixel_Description Pixel_Description[] = { - {"rgba8880", GL_RGB, GL_RGB}, - {"rgba8888", GL_RGBA, GL_RGBA} - }; - - constexpr size_t Pixel_Description_Count = sizeof(Pixel_Description) / sizeof(SPixel_Description); - - size_t idx_description; - // Get texture index. - bool ok; - size_t idx_texture = pFileName.right(strlen(AI_EMBEDDED_TEXNAME_PREFIX)).toULong(&ok); - - if(!ok) - { - LogError("Can not get index of the embedded texture from path in material."); - - return false; - } - - // Create alias for conveniance. - const aiTexture& als = *mScene->mTextures[idx_texture]; - - if(als.mHeight == 0)// Compressed texture. - { - LogError("IME: compressed embedded textures are not implemented."); - } - else - { - ok = false; - for(size_t idx = 0; idx < Pixel_Description_Count; idx++) - { - if(als.CheckFormat(Pixel_Description[idx].FormatHint)) - { - idx_description = idx; - ok = true; - break; - } - } - - if(!ok) - { - LogError(QString("Unsupported format hint for embedded texture: [%1]").arg(als.achFormatHint)); - - return false; - } - - glGenTextures(1, &id_ogl_texture);// Texture ID generation. - mTexture_IDMap[pFileName] = id_ogl_texture;// save texture ID for filename in map - glBindTexture(GL_TEXTURE_2D, id_ogl_texture);// Binding of texture ID. - // Redefine standard texture values - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// We will use linear interpolation for magnification filter. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);// We will use linear interpolation for minifying filter. - // Texture specification. - glTexImage2D(GL_TEXTURE_2D, 0, Pixel_Description[idx_description].Image_InternalFormat, als.mWidth, als.mHeight, 0, - Pixel_Description[idx_description].Pixel_Format, GL_UNSIGNED_BYTE, (uint8_t*)als.pcData); - }// if(als.mHeight == 0) else - }// if(!filename.startsWith(AI_EMBEDDED_TEXNAME_PREFIX)) else - - return true; - };// auto LoadTexture = [&](const aiString& pPath) - - if(mScene == nullptr) - { - LogError("Trying to load textures for empty scene."); - - return; - } - - // - // Load textures. - // - // Get textures file names and number of textures. - for(size_t idx_material = 0; idx_material < mScene->mNumMaterials; idx_material++) { - int idx_texture = 0; - aiString path; - - do { - if (mScene->mMaterials[ idx_material ]->GetTexture( aiTextureType_DIFFUSE, idx_texture, &path ) != AI_SUCCESS) { - break; - } - - LoadTexture(QString(path.C_Str())); - idx_texture++; - } while(true); - }// for(size_t idx_material = 0; idx_material < mScene->mNumMaterials; idx_material++) - - // Textures list is empty, exit. - if(mTexture_IDMap.empty()) { - LogInfo("No textures for import."); - } -} - -void CGLView::BBox_GetForNode(const aiNode& pNode, const aiMatrix4x4& pParent_TransformationMatrix, SBBox& pNodeBBox, bool& pFirstAssign) -{ - aiMatrix4x4 mat_trans = pParent_TransformationMatrix * pNode.mTransformation; - - // Check if node has meshes - for(size_t idx_idx_mesh = 0; idx_idx_mesh < pNode.mNumMeshes; idx_idx_mesh++) - { - size_t idx_mesh; - SBBox bbox_local; - aiVector3D bbox_vertices[8]; - - idx_mesh = pNode.mMeshes[idx_idx_mesh]; - // Get vertices of mesh BBox - BBox_GetVertices(mHelper_Mesh[idx_mesh]->BBox, bbox_vertices); - // Transform vertices - for(size_t idx_vert = 0; idx_vert < 8; idx_vert++) bbox_vertices[idx_vert] *= mat_trans; - - // And create BBox for transformed mesh - BBox_GetFromVertices(bbox_vertices, 8, bbox_local); - - if(!pFirstAssign) - { - BBox_Extend(bbox_local, pNodeBBox); - } - else - { - pFirstAssign = false; - pNodeBBox = bbox_local; - } - }// for(size_t idx_idx_mesh = 0; idx_idx_mesh < pNode.mNumMeshes; idx_idx_mesh++) - - for(size_t idx_node = 0; idx_node < pNode.mNumChildren; idx_node++) - { - BBox_GetForNode(*pNode.mChildren[idx_node], mat_trans, pNodeBBox, pFirstAssign); - } -} - -void CGLView::BBox_Extend(const SBBox& pChild, SBBox& pParent) -{ - // search minimal... - AssignIfLesser(&pParent.Minimum.x, pChild.Minimum.x); - AssignIfLesser(&pParent.Minimum.y, pChild.Minimum.y); - AssignIfLesser(&pParent.Minimum.z, pChild.Minimum.z); - // and maximal values - AssignIfGreater(&pParent.Maximum.x, pChild.Maximum.x); - AssignIfGreater(&pParent.Maximum.y, pChild.Maximum.y); - AssignIfGreater(&pParent.Maximum.z, pChild.Maximum.z); -} - -void CGLView::BBox_GetVertices(const SBBox& pBBox, aiVector3D pVertex[8]) -{ - pVertex[0] = pBBox.Minimum; - pVertex[1].Set(pBBox.Minimum.x, pBBox.Minimum.y, pBBox.Maximum.z); - pVertex[2].Set(pBBox.Minimum.x, pBBox.Maximum.y, pBBox.Maximum.z); - pVertex[3].Set(pBBox.Minimum.x, pBBox.Maximum.y, pBBox.Minimum.z); - - pVertex[4].Set(pBBox.Maximum.x, pBBox.Minimum.y, pBBox.Minimum.z); - pVertex[5].Set(pBBox.Maximum.x, pBBox.Minimum.y, pBBox.Maximum.z); - pVertex[6] = pBBox.Maximum; - pVertex[7].Set(pBBox.Maximum.x, pBBox.Maximum.y, pBBox.Minimum.z); - -} - -void CGLView::BBox_GetFromVertices(const aiVector3D* pVertices, const size_t pVerticesQuantity, SBBox& pBBox) -{ - if(pVerticesQuantity == 0) - { - pBBox.Maximum.Set(0, 0, 0); - pBBox.Minimum.Set(0, 0, 0); - - return; - } - - // Assign first values. - pBBox.Minimum = pVertices[0]; - pBBox.Maximum = pVertices[0]; - - for(size_t idx_vert = 1; idx_vert < pVerticesQuantity; idx_vert++) - { - const ai_real x = pVertices[idx_vert].x; - const ai_real y = pVertices[idx_vert].y; - const ai_real z = pVertices[idx_vert].z; - - // search minimal... - AssignIfLesser(&pBBox.Minimum.x, x); - AssignIfLesser(&pBBox.Minimum.y, y); - AssignIfLesser(&pBBox.Minimum.z, z); - // and maximal values - AssignIfGreater(&pBBox.Maximum.x, x); - AssignIfGreater(&pBBox.Maximum.y, y); - AssignIfGreater(&pBBox.Maximum.z, z); - } -} - -void CGLView::LogInfo(const QString& pMessage) { - Assimp::DefaultLogger::get()->info(pMessage.toStdString()); -} - -void CGLView::LogError(const QString& pMessage) { - Assimp::DefaultLogger::get()->error(pMessage.toStdString()); -} - -void CGLView::Draw_Node(const aiNode* pNode) { - aiMatrix4x4 mat_node = pNode->mTransformation; - - // Apply node transformation matrix. - mat_node.Transpose(); - glPushMatrix(); -#ifdef ASSIMP_DOUBLE_PRECISION - glMultMatrixd((GLdouble*)mat_node[0]); -#else - glMultMatrixf((GLfloat*)&mat_node); -#endif // ASSIMP_DOUBLE_PRECISION - - // Draw all meshes assigned to this node - for(size_t idx_mesh_arr = 0; idx_mesh_arr < pNode->mNumMeshes; idx_mesh_arr++) Draw_Mesh(pNode->mMeshes[idx_mesh_arr]); - - // Draw all children nodes - for(size_t idx_node = 0; idx_node < pNode->mNumChildren; idx_node++) Draw_Node(pNode->mChildren[idx_node]); - - // Restore transformation matrix. - glPopMatrix(); -} - -void CGLView::Draw_Mesh(const size_t pMesh_Index) -{ - // Check argument - if(pMesh_Index >= mHelper_Mesh_Quantity) return; - - aiMesh& mesh_cur = *mScene->mMeshes[pMesh_Index]; - - if(!mesh_cur.HasPositions()) return;// Nothing to draw. - - // If mesh use material then apply it - if(mScene->HasMaterials()) Material_Apply(mScene->mMaterials[mesh_cur.mMaterialIndex]); - - // - // Vertices array - // - glEnableClientState(GL_VERTEX_ARRAY); -#if ASSIMP_DOUBLE_PRECISION - glVertexPointer(3, GL_DOUBLE, 0, mesh_cur.mVertices); -#else - glVertexPointer(3, GL_FLOAT, 0, mesh_cur.mVertices); -#endif // ASSIMP_DOUBLE_PRECISION - - if(mesh_cur.HasVertexColors(0)) - { - glEnable(GL_COLOR_MATERIAL);///TODO: cache - glEnableClientState(GL_COLOR_ARRAY); -#ifdef ASSIMP_DOUBLE_PRECISION - glColorPointer(4, GL_DOUBLE, 0, mesh_cur.mColors[0]); -#else - glColorPointer(4, GL_FLOAT, 0, mesh_cur.mColors[0]); -#endif // ASSIMP_DOUBLE_PRECISION - } - - // - // Texture coordinates array - // - if(mesh_cur.HasTextureCoords(0)) - { - glEnableClientState(GL_TEXTURE_COORD_ARRAY); -#ifdef ASSIMP_DOUBLE_PRECISION - glTexCoordPointer(2, GL_DOUBLE, sizeof(aiVector3D), mesh_cur.mTextureCoords[0]); -#else - glTexCoordPointer(2, GL_FLOAT, sizeof(aiVector3D), mesh_cur.mTextureCoords[0]); -#endif // ASSIMP_DOUBLE_PRECISION - } - - // - // Normals array - // - if(mesh_cur.HasNormals()) - { - glEnableClientState(GL_NORMAL_ARRAY); -#ifdef ASSIMP_DOUBLE_PRECISION - glNormalPointer(GL_DOUBLE, 0, mesh_cur.mNormals); -#else - glNormalPointer(GL_FLOAT, 0, mesh_cur.mNormals); -#endif // ASSIMP_DOUBLE_PRECISION - } - - // - // Draw arrays - // - SHelper_Mesh& helper_cur = *mHelper_Mesh[pMesh_Index]; - - if(helper_cur.Quantity_Triangle > 0) glDrawElements(GL_TRIANGLES, helper_cur.Quantity_Triangle * 3, GL_UNSIGNED_INT, helper_cur.Index_Triangle); - if(helper_cur.Quantity_Line > 0) glDrawElements(GL_LINES,helper_cur.Quantity_Line * 2, GL_UNSIGNED_INT, helper_cur.Index_Line); - if(helper_cur.Quantity_Point > 0) glDrawElements(GL_POINTS, helper_cur.Quantity_Point, GL_UNSIGNED_INT, helper_cur.Index_Point); - - // - // Clean up - // - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); -} - -void CGLView::Draw_BBox(const SBBox& pBBox) -{ - aiVector3D vertex[8]; - - BBox_GetVertices(pBBox, vertex); - // Draw - if(mLightingEnabled) glDisable(GL_LIGHTING);///TODO: display list - - glEnable(GL_COLOR_MATERIAL); - glBindTexture(GL_TEXTURE_1D, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glBindTexture(GL_TEXTURE_3D, 0); - const QColor c_w(Qt::white); - - glColor3f(c_w.redF(), c_w.greenF(), c_w.blueF()); - - glBegin(GL_LINE_STRIP); -# ifdef ASSIMP_DOUBLE_PRECISION - glVertex3dv(&vertex[0][0]), glVertex3dv(&vertex[1][0]), glVertex3dv(&vertex[2][0]), glVertex3dv(&vertex[3][0]), glVertex3dv(&vertex[0][0]);// "Minimum" side. - glVertex3dv(&vertex[4][0]), glVertex3dv(&vertex[5][0]), glVertex3dv(&vertex[6][0]), glVertex3dv(&vertex[7][0]), glVertex3dv(&vertex[4][0]);// Edge and "maximum" side. -# else - glVertex3fv(&vertex[0][0]), glVertex3fv(&vertex[1][0]), glVertex3fv(&vertex[2][0]), glVertex3fv(&vertex[3][0]), glVertex3fv(&vertex[0][0]);// "Minimum" side. - glVertex3fv(&vertex[4][0]), glVertex3fv(&vertex[5][0]), glVertex3fv(&vertex[6][0]), glVertex3fv(&vertex[7][0]), glVertex3fv(&vertex[4][0]);// Edge and "maximum" side. -# endif // ASSIMP_DOUBLE_PRECISION - glEnd(); - - glBegin(GL_LINES); -# ifdef ASSIMP_DOUBLE_PRECISION - glVertex3dv(&vertex[1][0]), glVertex3dv(&vertex[5][0]); - glVertex3dv(&vertex[2][0]), glVertex3dv(&vertex[6][0]); - glVertex3dv(&vertex[3][0]), glVertex3dv(&vertex[7][0]); -# else - glVertex3fv(&vertex[1][0]), glVertex3fv(&vertex[5][0]); - glVertex3fv(&vertex[2][0]), glVertex3fv(&vertex[6][0]); - glVertex3fv(&vertex[3][0]), glVertex3fv(&vertex[7][0]); -# endif // ASSIMP_DOUBLE_PRECISION - glEnd(); - glDisable(GL_COLOR_MATERIAL); - if(mLightingEnabled) glEnable(GL_LIGHTING); - -} - -void CGLView::Enable_Textures(const bool pEnable) { - if(pEnable) { - glEnable(GL_TEXTURE_1D); - glEnable(GL_TEXTURE_2D); - glEnable(GL_TEXTURE_3D); - } else { - glDisable(GL_TEXTURE_1D); - glDisable(GL_TEXTURE_2D); - glDisable(GL_TEXTURE_3D); - } -} - -void CGLView::initializeGL() { - mGLContext_Current = true; - initializeOpenGLFunctions(); - glClearColor(0.5f, 0.5f, 0.5f, 1.0f); - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_NORMALIZE); - glEnable(GL_TEXTURE_2D); - glEnable( GL_MULTISAMPLE ); - - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT); - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - glDisable(GL_COLOR_MATERIAL); - - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - - glFrontFace(GL_CCW); -} - -void CGLView::resizeGL(int width, int height) { - mCamera_Viewport_AspectRatio = (GLdouble)width / height; - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(mCamera_FOVY, mCamera_Viewport_AspectRatio, 1.0, 100000.0);///TODO: znear/zfar depend on scene size. -} - -void CGLView::drawCoordSystem() { - // Disable lighting. Colors must be bright and colorful) - if ( mLightingEnabled ) glDisable( GL_LIGHTING );///TODO: display list - - // For same reason - disable textures. - glBindTexture(GL_TEXTURE_1D, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glBindTexture(GL_TEXTURE_3D, 0); - glEnable(GL_COLOR_MATERIAL); - glBegin(GL_LINES); - - // X, -X - glColor3f(1.0f, 0.0f, 0.0f), glVertex3f(0.0, 0.0, 0.0), glVertex3f(100000.0, 0.0, 0.0); - glColor3f(0.5f, 0.5f, 1.0f), glVertex3f(0.0, 0.0, 0.0), glVertex3f(-100000.0, 0.0, 0.0); - // Y, -Y - glColor3f(0.0f, 1.0f, 0.0f), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 100000.0, 0.0); - glColor3f(1.0f, 0.0f, 1.0f), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, -100000.0, 0.0); - // Z, -Z - glColor3f(0.0f, 0.0f, 1.0f), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, 100000.0); - glColor3f(1.0f, 1.0f, 0.0f), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, -100000.0); - glColor3f(1.0f, 1.0f, 1.0f); - - glEnd(); - // Restore previous state of lighting. - if (mLightingEnabled) { - glEnable( GL_LIGHTING ); - } -} - -void CGLView::paintGL() { - QTime time_paintbegin; - - time_paintbegin = QTime::currentTime(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - // Apply current camera transformations. -#if ASSIMP_DOUBLE_PRECISION - glMultMatrixd((GLdouble*)&mHelper_Camera.Rotation_AroundCamera); - glTranslated(-mHelper_Camera.Translation_ToScene.x, -mHelper_Camera.Translation_ToScene.y, -mHelper_Camera.Translation_ToScene.z); - glMultMatrixd((GLdouble*)&mHelper_Camera.Rotation_Scene); -#else - glMultMatrixf((GLfloat*)&mHelper_Camera.Rotation_AroundCamera); - glTranslatef(-mHelper_Camera.Translation_ToScene.x, -mHelper_Camera.Translation_ToScene.y, -mHelper_Camera.Translation_ToScene.z); - glMultMatrixf((GLfloat*)&mHelper_Camera.Rotation_Scene); -#endif // ASSIMP_DOUBLE_PRECISION - - // Coordinate system - if ( mScene_AxesEnabled ) { - drawCoordSystem(); - } - - glDisable(GL_COLOR_MATERIAL); - - // Scene - if(mScene != nullptr) { - Draw_Node(mScene->mRootNode); - // Scene BBox - if (mScene_DrawBBox) { - Draw_BBox( mScene_BBox ); - } - } - - emit Paint_Finished((size_t) time_paintbegin.msecsTo(QTime::currentTime()), mHelper_Camera.Translation_ToScene.Length()); -} - - -CGLView::CGLView( QWidget *pParent ) -: QOpenGLWidget( pParent ) -, mGLContext_Current( false ) { - // set initial view - mHelper_CameraDefault.SetDefault(); - Camera_Set( 0 ); -} - -CGLView::~CGLView() { - FreeScene(); -} - -void CGLView::FreeScene() { - // Set scene to null and after that \ref paintGL will not try to render it. - mScene = nullptr; - // Clean helper objects. - if(mHelper_Mesh != nullptr) - { - for(size_t idx_mesh = 0; idx_mesh < mHelper_Mesh_Quantity; idx_mesh++) delete mHelper_Mesh[idx_mesh]; - - delete [] mHelper_Mesh; - mHelper_Mesh = nullptr; - } - - mHelper_Mesh_Quantity = 0; - // Delete textures - const int id_tex_size = mTexture_IDMap.size(); - - if(id_tex_size) - { - GLuint* id_tex = new GLuint[id_tex_size]; - QMap::iterator it = mTexture_IDMap.begin(); - - for(int idx = 0; idx < id_tex_size; idx++, it++) - { - id_tex[idx] = it.value(); - } - - glDeleteTextures(id_tex_size, id_tex); - mTexture_IDMap.clear(); - delete [] id_tex; - } -} - -void CGLView::SetScene(const aiScene *pScene, const QString& pScenePath) { - FreeScene();// Clear old data - // Why checking here, not at begin of function. Because old scene may not exist at know. So, need cleanup. - if (pScene == nullptr) { - return; - } - - mScene = pScene;// Copy pointer of new scene. - - // - // Meshes - // - // Create helper objects for meshes. This allow to render meshes as OpenGL arrays. - if(mScene->HasMeshes()) - { - // Create mesh helpers array. - mHelper_Mesh_Quantity = mScene->mNumMeshes; - mHelper_Mesh = new SHelper_Mesh*[mScene->mNumMeshes]; - - // Walk through the meshes and extract needed data and, also calculate BBox. - for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++) - { - aiMesh& mesh_cur = *mScene->mMeshes[idx_mesh]; - - // - // Calculate BBox - // - SBBox mesh_bbox; - - BBox_GetFromVertices(mesh_cur.mVertices, mesh_cur.mNumVertices, mesh_bbox); - // - // Create vertices indices arrays splitted by primitive type. - // - size_t indcnt_p = 0;// points quantity - size_t indcnt_l = 0;// lines quantity - size_t indcnt_t = 0;// triangles quantity - - if(mesh_cur.HasFaces()) - { - // Usual way: all faces are triangles - if(mesh_cur.mPrimitiveTypes == aiPrimitiveType_TRIANGLE) - { - indcnt_t = mesh_cur.mNumFaces; - } - else - { - // Calculate count of primitives by types. - for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++) - { - if(mesh_cur.mFaces[idx_face].mNumIndices == 3) - indcnt_t++; - else if(mesh_cur.mFaces[idx_face].mNumIndices == 2) - indcnt_l++; - else if(mesh_cur.mFaces[idx_face].mNumIndices == 1) - indcnt_p++; - } - }// if(mesh_cur.mPrimitiveTypes == aiPrimitiveType_TRIANGLE) else - - // Create helper - mHelper_Mesh[idx_mesh] = new SHelper_Mesh(indcnt_p, indcnt_l, indcnt_t, mesh_bbox); - // Fill indices arrays - indcnt_p = 0, indcnt_l = 0, indcnt_t = 0;// Reuse variables as indices - for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++) - { - if(mesh_cur.mFaces[idx_face].mNumIndices == 3) - { - mHelper_Mesh[idx_mesh]->Index_Triangle[indcnt_t++] = mesh_cur.mFaces[idx_face].mIndices[0]; - mHelper_Mesh[idx_mesh]->Index_Triangle[indcnt_t++] = mesh_cur.mFaces[idx_face].mIndices[1]; - mHelper_Mesh[idx_mesh]->Index_Triangle[indcnt_t++] = mesh_cur.mFaces[idx_face].mIndices[2]; - } - else if(mesh_cur.mFaces[idx_face].mNumIndices == 2) - { - mHelper_Mesh[idx_mesh]->Index_Line[indcnt_l++] = mesh_cur.mFaces[idx_face].mIndices[0]; - mHelper_Mesh[idx_mesh]->Index_Line[indcnt_l++] = mesh_cur.mFaces[idx_face].mIndices[1]; - } - else if(mesh_cur.mFaces[idx_face].mNumIndices == 1) - { - mHelper_Mesh[idx_mesh]->Index_Point[indcnt_p++] = mesh_cur.mFaces[idx_face].mIndices[0]; - } - }// for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++) - }// if(mesh_cur.HasFaces()) - else - { - // If mesh has no faces then vertices can be just points set. - indcnt_p = mesh_cur.mNumVertices; - // Create helper - mHelper_Mesh[idx_mesh] = new SHelper_Mesh(indcnt_p, 0, 0, mesh_bbox); - // Fill indices arrays - for(size_t idx = 0; idx < indcnt_p; idx++) mHelper_Mesh[idx_mesh]->Index_Point[idx] = idx; - - }// if(mesh_cur.HasFaces()) else - }// for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++) - }// if(mScene->HasMeshes()) - - // - // Scene BBox - // - // For calculating right BBox we must walk through all nodes and apply transformation to meshes BBoxes - if(mHelper_Mesh_Quantity > 0) - { - bool first_assign = true; - aiMatrix4x4 mat_root; - - BBox_GetForNode(*mScene->mRootNode, mat_root, mScene_BBox, first_assign); - mScene_Center = mScene_BBox.Maximum + mScene_BBox.Minimum; - mScene_Center /= 2; - } - else - { - mScene_BBox = {{0, 0, 0}, {0, 0, 0}}; - mScene_Center = {0, 0, 0}; - }// if(mHelper_Mesh_Count > 0) else - - // - // Textures - // - ImportTextures(pScenePath); - - // - // Light sources - // - Lighting_Enable(); - // If scene has no lights then enable default - if(!mScene->HasLights()) - { - const GLfloat col_amb[4] = { 0.2, 0.2, 0.2, 1.0 }; - SLightParameters lp; - - lp.Type = aiLightSource_POINT; - lp.Ambient.r = col_amb[0], lp.Ambient.g = col_amb[1], lp.Ambient.b = col_amb[2], lp.Ambient.a = col_amb[3]; - lp.Diffuse = { 1.0, 1.0, 1.0, 1.0 }; - lp.Specular = lp.Diffuse; - lp.For.Point.Position = mScene_Center; - lp.For.Point.Attenuation_Constant = 1; - lp.For.Point.Attenuation_Linear = 0; - lp.For.Point.Attenuation_Quadratic = 0; - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col_amb); - Lighting_EditSource(0, lp); - emit SceneObject_LightSource("_default");// Light source will be enabled in signal handler. - } - else - { - for(size_t idx_light = 0; idx_light < mScene->mNumLights; idx_light++) - { - SLightParameters lp; - QString name; - const aiLight& light_cur = *mScene->mLights[idx_light]; - - auto col3_to_col4 = [](const aiColor3D& pCol3) -> aiColor4D { return aiColor4D(pCol3.r, pCol3.g, pCol3.b, 1.0); }; - - ///TODO: find light source node and apply all transformations - // General properties - name = light_cur.mName.C_Str(); - lp.Ambient = col3_to_col4(light_cur.mColorAmbient); - lp.Diffuse = col3_to_col4(light_cur.mColorDiffuse); - lp.Specular = col3_to_col4(light_cur.mColorSpecular); - lp.Type = light_cur.mType; - // Depend on type properties - switch(light_cur.mType) - { - case aiLightSource_DIRECTIONAL: - lp.For.Directional.Direction = light_cur.mDirection; - break; - case aiLightSource_POINT: - lp.For.Point.Position = light_cur.mPosition; - lp.For.Point.Attenuation_Constant = light_cur.mAttenuationConstant; - lp.For.Point.Attenuation_Linear = light_cur.mAttenuationLinear; - lp.For.Point.Attenuation_Quadratic = light_cur.mAttenuationQuadratic; - break; - case aiLightSource_SPOT: - lp.For.Spot.Position = light_cur.mPosition; - lp.For.Spot.Direction = light_cur.mDirection; - lp.For.Spot.Attenuation_Constant = light_cur.mAttenuationConstant; - lp.For.Spot.Attenuation_Linear = light_cur.mAttenuationLinear; - lp.For.Spot.Attenuation_Quadratic = light_cur.mAttenuationQuadratic; - lp.For.Spot.CutOff = light_cur.mAngleOuterCone; - break; - case aiLightSource_AMBIENT: - lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0; - name.append("_unsup_ambient"); - break; - case aiLightSource_AREA: - lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0; - name.append("_unsup_area"); - break; - case aiLightSource_UNDEFINED: - lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0; - name.append("_unsup_undefined"); - break; - default: - lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0; - name.append("_unsupported_invalid"); - break; - }// switch(light_cur.mType) - - // Add light source - // Use index if name is empty. - if (name.isEmpty()) { - name += QString( "%1" ).arg( idx_light ); - } - - Lighting_EditSource(idx_light, lp); - emit SceneObject_LightSource(name);// Light source will be enabled in signal handler. - }// for(size_t idx_light = 0; idx_light < mScene->mNumLights; idx_light++) - }// if(!mScene->HasLights()) else - - // - // Cameras - // - if(!mScene->HasCameras()) - { - mCamera_DefaultAdded = true; - mHelper_CameraDefault.SetDefault(); - // Calculate distance from camera to scene. Distance must be enoguh for that viewport contain whole scene. - const GLfloat tg_angle = tan(mCamera_FOVY / 2); - - GLfloat val_x = ((mScene_BBox.Maximum.x - mScene_BBox.Minimum.x) / 2) / (mCamera_Viewport_AspectRatio * tg_angle); - GLfloat val_y = ((mScene_BBox.Maximum.y - mScene_BBox.Minimum.y) / 2) / tg_angle; - GLfloat val_step = val_x; - - AssignIfGreater(val_step, val_y); - mHelper_CameraDefault.Translation_ToScene.Set(mScene_Center.x, mScene_Center.y, val_step + mScene_BBox.Maximum.z); - emit SceneObject_Camera("_default"); - } - else - { - mCamera_DefaultAdded = false; - for(size_t idx_cam = 0; idx_cam < mScene->mNumCameras; idx_cam++) - { - emit SceneObject_Camera(mScene->mCameras[idx_cam]->mName.C_Str()); - } - }// if(!mScene->HasCameras()) else -} - -void CGLView::Lighting_Enable() { - mLightingEnabled = true; - glEnable(GL_LIGHTING); -} - -void CGLView::Lighting_Disable() { - glDisable( GL_LIGHTING ); - mLightingEnabled = false; -} - -void CGLView::Lighting_EditSource(const size_t pLightNumber, const SLightParameters& pLightParameters) -{ - const size_t light_num = GL_LIGHT0 + pLightNumber; - - GLfloat farr[4]; - - if(pLightNumber >= GL_MAX_LIGHTS) return;///TODO: return value; - - // Ambient color - farr[0] = pLightParameters.Ambient.r; - farr[1] = pLightParameters.Ambient.g; - farr[2] = pLightParameters.Ambient.b; - farr[3] = pLightParameters.Ambient.a; - glLightfv(light_num, GL_AMBIENT, farr); - - // Diffuse color - farr[0] = pLightParameters.Diffuse.r; - farr[1] = pLightParameters.Diffuse.g; - farr[2] = pLightParameters.Diffuse.b; - farr[3] = pLightParameters.Diffuse.a; - glLightfv(light_num, GL_DIFFUSE, farr); - - // Specular color - farr[0] = pLightParameters.Specular.r; - farr[1] = pLightParameters.Specular.g; - farr[2] = pLightParameters.Specular.b; - farr[3] = pLightParameters.Specular.a; - glLightfv(light_num, GL_SPECULAR, farr); - - // Other parameters - switch(pLightParameters.Type) - { - case aiLightSource_DIRECTIONAL: - // Direction - farr[0] = pLightParameters.For.Directional.Direction.x, farr[1] = pLightParameters.For.Directional.Direction.y; - farr[2] = pLightParameters.For.Directional.Direction.z; farr[3] = 0; - glLightfv(light_num, GL_POSITION, farr); - break; - case aiLightSource_POINT: - // Position - farr[0] = pLightParameters.For.Point.Position.x, farr[1] = pLightParameters.For.Point.Position.y; - farr[2] = pLightParameters.For.Point.Position.z; farr[3] = 1; - glLightfv(light_num, GL_POSITION, farr); - // Attenuation - glLightf(light_num, GL_CONSTANT_ATTENUATION, pLightParameters.For.Point.Attenuation_Constant); - glLightf(light_num, GL_LINEAR_ATTENUATION, pLightParameters.For.Point.Attenuation_Linear); - glLightf(light_num, GL_QUADRATIC_ATTENUATION, pLightParameters.For.Point.Attenuation_Quadratic); - glLightf(light_num, GL_SPOT_CUTOFF, 180.0); - break; - case aiLightSource_SPOT: - // Position - farr[0] = pLightParameters.For.Spot.Position.x, farr[1] = pLightParameters.For.Spot.Position.y, farr[2] = pLightParameters.For.Spot.Position.z; farr[3] = 1; - glLightfv(light_num, GL_POSITION, farr); - // Attenuation - glLightf(light_num, GL_CONSTANT_ATTENUATION, pLightParameters.For.Spot.Attenuation_Constant); - glLightf(light_num, GL_LINEAR_ATTENUATION, pLightParameters.For.Spot.Attenuation_Linear); - glLightf(light_num, GL_QUADRATIC_ATTENUATION, pLightParameters.For.Spot.Attenuation_Quadratic); - // Spot specific - farr[0] = pLightParameters.For.Spot.Direction.x, farr[1] = pLightParameters.For.Spot.Direction.y, farr[2] = pLightParameters.For.Spot.Direction.z; farr[3] = 0; - glLightfv(light_num, GL_SPOT_DIRECTION, farr); - glLightf(light_num, GL_SPOT_CUTOFF, pLightParameters.For.Spot.CutOff); - break; - default:// For unknown light source types use point source. - // Position - farr[0] = pLightParameters.For.Point.Position.x, farr[1] = pLightParameters.For.Point.Position.y; - farr[2] = pLightParameters.For.Point.Position.z; farr[3] = 1; - glLightfv(light_num, GL_POSITION, farr); - // Attenuation - glLightf(light_num, GL_CONSTANT_ATTENUATION, 1); - glLightf(light_num, GL_LINEAR_ATTENUATION, 0); - glLightf(light_num, GL_QUADRATIC_ATTENUATION, 0); - glLightf(light_num, GL_SPOT_CUTOFF, 180.0); - break; - }// switch(pLightParameters.Type) -} - -void CGLView::Lighting_EnableSource(const size_t pLightNumber) { - if(pLightNumber >= GL_MAX_LIGHTS) return;///TODO: return value; - - glEnable(GL_LIGHT0 + pLightNumber); -} - -void CGLView::Lighting_DisableSource(const size_t pLightNumber) -{ - if(pLightNumber >= GL_MAX_LIGHTS) return;///TODO: return value; - - glDisable(GL_LIGHT0 + pLightNumber); -} - -void CGLView::Camera_Set(const size_t pCameraNumber) -{ - SHelper_Camera& hcam = mHelper_Camera;// reference with short name for conveniance. - aiVector3D up; - - if(mCamera_DefaultAdded || (pCameraNumber >= mScene->mNumCameras))// If default camera used then 'pCameraNumber' doesn't matter. - { - // Transformation parameters - hcam = mHelper_CameraDefault; - up.Set(0, 1, 0); - } - else - { - const aiCamera& camera_cur = *mScene->mCameras[pCameraNumber]; - const aiNode* camera_node; - - aiMatrix4x4 camera_mat; - aiQuaternion camera_quat_rot; - aiVector3D camera_tr; - - up = camera_cur.mUp; - // - // Try to get real coordinates of the camera. - // - // Find node - camera_node = mScene->mRootNode->FindNode(camera_cur.mName); - if(camera_node != nullptr) Matrix_NodeToRoot(camera_node, camera_mat); - - hcam.Position = camera_cur.mLookAt; - hcam.Target = camera_cur.mPosition; - hcam.Rotation_AroundCamera = aiMatrix4x4(camera_quat_rot.GetMatrix()); - hcam.Rotation_AroundCamera.Transpose(); - // get components of transformation matrix. - camera_mat.DecomposeNoScaling(camera_quat_rot, camera_tr); - hcam.Rotation_Scene = aiMatrix4x4(); - hcam.Translation_ToScene = camera_tr; - } - - // Load identity matrix - travel to world begin. - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - // Set camera and update picture - gluLookAt(hcam.Position.x, hcam.Position.y, hcam.Position.z, hcam.Target.x, hcam.Target.y, hcam.Target.z, up.x, up.y, up.z); -} - -void CGLView::Camera_RotateScene(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z, const aiMatrix4x4* pMatrix_Rotation_Initial) { - auto deg2rad = [](const GLfloat pDegree) -> GLfloat { - return pDegree * AI_MATH_PI / 180.0f; - }; - - aiMatrix4x4 mat_rot; - - mat_rot.FromEulerAnglesXYZ(deg2rad(pAngle_X), deg2rad(pAngle_Y), deg2rad(pAngle_Z)); - if(pMatrix_Rotation_Initial != nullptr) - mHelper_Camera.Rotation_Scene = *pMatrix_Rotation_Initial * mat_rot; - else - mHelper_Camera.Rotation_Scene *= mat_rot; -} - -void CGLView::Camera_Rotate(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z, const aiMatrix4x4* pMatrix_Rotation_Initial) -{ - auto deg2rad = [](const GLfloat pDegree) -> GLfloat { return pDegree * AI_MATH_PI / 180.0; }; - - aiMatrix4x4 mat_rot; - - mat_rot.FromEulerAnglesXYZ(deg2rad(pAngle_X), deg2rad(pAngle_Y), deg2rad(pAngle_Z)); - if(pMatrix_Rotation_Initial != nullptr) - mHelper_Camera.Rotation_AroundCamera = *pMatrix_Rotation_Initial * mat_rot; - else - mHelper_Camera.Rotation_AroundCamera *= mat_rot; -} - -void CGLView::Camera_Translate(const GLfloat pTranslate_X, const GLfloat pTranslate_Y, const GLfloat pTranslate_Z) -{ - aiVector3D vect_tr(pTranslate_X, pTranslate_Y, pTranslate_Z); - - vect_tr *= mHelper_Camera.Rotation_AroundCamera; - mHelper_Camera.Translation_ToScene += vect_tr; -} - -void CGLView::Camera_Matrix(aiMatrix4x4& pRotation_Camera, aiMatrix4x4& pRotation_Scene, aiVector3D& pTranslation_Camera) -{ - pRotation_Camera = mHelper_Camera.Rotation_AroundCamera; - pRotation_Scene = mHelper_Camera.Rotation_Scene; - pTranslation_Camera = mHelper_Camera.Translation_ToScene; -} diff --git a/tools/assimp_qt_viewer/glview.hpp b/tools/assimp_qt_viewer/glview.hpp deleted file mode 100644 index 3cdb1fd11..000000000 --- a/tools/assimp_qt_viewer/glview.hpp +++ /dev/null @@ -1,456 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -#pragma once - -// Header files, Qt. -#include -#if ASSIMP_QT4_VIEWER -# include -#else -# include -# include -#endif // ASSIMP_QT4_VIEWER - -// Header files Assimp -#include - -/// \class CGLView -/// Class which hold and render scene. -#if ASSIMP_QT4_VIEWER -class CGLView : public QGLWidget -#else -class CGLView : public QOpenGLWidget, protected QOpenGLFunctions -#endif // ASSIMP_QT4_VIEWER -{ - Q_OBJECT - - /**********************************/ - /************* Types **************/ - /**********************************/ - -private: - - /// \struct SBBox - /// Bounding box for object. - struct SBBox - { - aiVector3D Minimum;///< Minimum values of coordinates. - aiVector3D Maximum;///< Maximum values of coordinates. - }; - - /// \struct SHelper_Mesh - /// Helper object for fast rendering of mesh (\ref aiMesh). - struct SHelper_Mesh - { - const size_t Quantity_Point;///< Quantity of points. - const size_t Quantity_Line;///< Quantity of lines. - const size_t Quantity_Triangle;///< Quantity of triangles. - GLuint* Index_Point;///< Array of indices for drawing points. - GLuint* Index_Line;///< Array of indices for drawing lines. - GLuint* Index_Triangle;///< Array of indices for drawing triangles. - - const SBBox BBox;///< BBox of mesh. - - /// \fn explicit SHelper_Mesh(const size_t pQuantity_Point, const size_t pQuantity_Line, const size_t pQuantity_Triangle, const SBBox& pBBox = {{0, 0, 0}, {0, 0, 0}}) - /// Constructor. - /// \param [in] pQuantity_Point - quantity of points. - /// \param [in] pQuantity_Line - quantity of lines. - /// \param [in] pQuantity_Triangle - quantity of triangles. - /// \param [in] pBBox - BBox of mesh. - explicit SHelper_Mesh(const size_t pQuantity_Point, const size_t pQuantity_Line, const size_t pQuantity_Triangle, const SBBox& pBBox = {{0, 0, 0}, {0, 0, 0}}); - - /// \fn ~SHelper_Mesh() - /// Destructor. - ~SHelper_Mesh(); - }; - - /// \struct SHelper_Camera - /// Information about position of the camera in space. - struct SHelper_Camera - { - aiVector3D Position;///< Coordinates of the camera. - aiVector3D Target;///< Target point of the camera. - // Transformation path: - // set Camera -> Rotation_AroundCamera -> Translation_ToScene -> Rotation_Scene -> draw Scene - aiMatrix4x4 Rotation_AroundCamera;///< Rotation matrix which set rotation angles of the scene around camera. - aiMatrix4x4 Rotation_Scene;///< Rotation matrix which set rotation angles of the scene around own center. - aiVector3D Translation_ToScene;///< Translation vector from camera to the scene. - - /// \fn void SetDefault() - /// Set default parameters of camera. - void SetDefault(); - }; - -public: - - /// \enum ELightType - /// Type of light source. - enum class ELightType { Directional, Point, Spot }; - - /// \struct SLightParameters - /// Parameters of light source. - struct SLightParameters - { - aiLightSourceType Type;///< Type of light source. - - aiColor4D Ambient;///< Ambient RGBA intensity of the light. - aiColor4D Diffuse;///< Diffuse RGBA intensity of the light. - aiColor4D Specular;///< Specular RGBA intensity of the light. - - union UFor - { - /// \struct SDirectional - /// Parameters of directional light source. - struct SDirectional - { - aiVector3D Direction; - - SDirectional() {} - } Directional; - - /// \struct SPoint - /// Parameters of point light source. - struct SPoint - { - aiVector3D Position; - GLfloat Attenuation_Constant; - GLfloat Attenuation_Linear; - GLfloat Attenuation_Quadratic; - - SPoint() {} - } Point; - - /// \struct SSpot - /// Parameters of spot light source. - struct SSpot - { - aiVector3D Position; - GLfloat Attenuation_Constant; - GLfloat Attenuation_Linear; - GLfloat Attenuation_Quadratic; - aiVector3D Direction; - GLfloat CutOff; - - SSpot() {} - } Spot; - - UFor() {} - } For; - - SLightParameters() {} - }; - - /**********************************/ - /************ Variables ***********/ - /**********************************/ - -private: - -#if !ASSIMP_QT4_VIEWER - // Qt5 widget has another behavior, so you must to know that you already made context are current. Yes, its a dirty hack. Better decision are welcome. - bool mGLContext_Current;///< Widget's GL-context made current. -#endif // ASSIMP_QT4_VIEWER - // Scene - const aiScene* mScene = nullptr;///< Copy of pointer to scene (\ref aiScene). - SBBox mScene_BBox;///< Bounding box of scene. - aiVector3D mScene_Center;///< Coordinates of center of the scene. - bool mScene_DrawBBox = false;///< Flag which control drawing scene BBox. - bool mScene_AxesEnabled = true;///< Flag which control drawing axes of the coordinate system. - // Meshes - size_t mHelper_Mesh_Quantity = 0;///< Quantity of meshes in scene. - SHelper_Mesh** mHelper_Mesh = nullptr;///< Array of pointers to helper objects for drawing mesh. Sequence of meshes are equivalent to \ref aiScene::mMeshes. - // Cameras - SHelper_Camera mHelper_Camera;///< Information about current camera placing in space. - SHelper_Camera mHelper_CameraDefault;///< Information about default camera initial placing in space. - bool mCamera_DefaultAdded = true;///< If true then scene has no defined cameras and default was added, if false - scene has defined cameras. - GLdouble mCamera_FOVY = 45.0;///< Specifies the field of view angle, in degrees, in the y direction. - GLdouble mCamera_Viewport_AspectRatio;///< Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). - // Lighting - bool mLightingEnabled = false;///< If true then OpenGL lighting is enabled (glEnable(GL_LIGHTING)), if false - disabled. - ///TODO: map is goooood, but not for case when one image can be used in different materials with difference in: texture transformation, targeting of the - /// texture (ambient or emission, or even height map), texture properties. - QMap mTexture_IDMap;///< Map image filenames to textures ID's. - - /**********************************/ - /************ Functions ***********/ - /**********************************/ - -private: - - // Why in some cases pointers are used? Because: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36566 - template void AssignIfLesser(TArg* pBaseValue, const TArg pTestValue) { if(pTestValue < *pBaseValue) *pBaseValue = pTestValue; } - template void AssignIfGreater(TArg* pBaseValue, const TArg pTestValue) { if(pTestValue > *pBaseValue) *pBaseValue = pTestValue; } - - template void AssignIfLesser(TArg& pBaseValue, const TArg pTestValue) { if(pTestValue < pBaseValue) pBaseValue = pTestValue; } - template void AssignIfGreater(TArg& pBaseValue, const TArg pTestValue) { if(pTestValue > pBaseValue) pBaseValue = pTestValue; } - - /// \fn void Material_Apply(const aiMaterial* pMaterial) - /// Enable pointed material. - /// \param [in] pMaterial - pointer to material which must be used. - void Material_Apply(const aiMaterial* pMaterial); - - /// \fn void Matrix_NodeToRoot(const aiNode* pNode, aiMatrix4x4& pOutMatrix) - /// Calculate matrix for transforming coordinates from pointed node to root node (read as "global coordinate system"). - /// \param [in] pNode - pointer initial node from which relative coordintaes will be taken, - /// \param [out] pOutMatrix - matrix for transform relative coordinates in \ref pNode to coordinates in root node (\ref aiScene::mRootNode). - void Matrix_NodeToRoot(const aiNode* pNode, aiMatrix4x4& pOutMatrix); - - /// \fn void ImportTextures() - /// Import textures. - /// \param [in] pScenePath - path to the file of the scene. - void ImportTextures(const QString& pScenePath); - - /// \fn void BBox_GetForNode(const aiNode& pNode, const aiMatrix4x4& pParentNode_TransformationMatrix, SBBox& pNodeBBox, bool& pFirstAssign) - /// Calculate BBox for pointed node. Function walk thru child nodes and apply all transformations. - /// \param [in] pNode - reference to node for which needed BBox. - /// \param [in] pParent_TransformationMatrix - reference to parent (parent for pNode) transformation matrix. - /// \param [in,out] pNodeBBox - reference to where pNode BBox will be placed. It will expanded by child nodes BBoxes. - /// \param [in] pFirstAssign - means that pNodeBBox not contain valid BBox at now and assign ('=') will used for setting new value, If - /// false then \ref BBox_Extend will be used for setting new BBox. - void BBox_GetForNode(const aiNode& pNode, const aiMatrix4x4& pParent_TransformationMatrix, SBBox& pNodeBBox, bool& pFirstAssign); - - /// \fn void BBox_Extend(const SBBox& pChild, SBBox& pParent) - /// Check and if need - extend current node BBox with BBox of child node. - /// \param [in] pChild - reference to BBox which used for extend parent BBox. - /// \param [in.out] pParent - BBox which will be extended using child BBox. - void BBox_Extend(const SBBox& pChild, SBBox& pParent); - - /// \fn void BBox_GetVertices(const SBBox& pBBox, aiVector3D pVertices[8]) - /// Get vertices of a parallelepiped which is described by BBox. - /// \param [in] pBBox - input BBox. - /// \param [out] pVertices - array of vertices. - void BBox_GetVertices(const SBBox& pBBox, aiVector3D pVertices[8]); - - /// \fn void BBox_GetFromVertices(const aiVector3D* pVertices, const size_t pVerticesQuantity, SBBox& pBBox) - /// Calculate BBox for vertices array. - /// \param [in] pVertices - vertices array. - /// \param [in] pVerticesQuantity - quantity of vertices in array. If 0 then pBBox will be assigned with {{0, 0, 0}, {0, 0, 0}}. - /// \param [out] pBBox - calculated BBox. - void BBox_GetFromVertices(const aiVector3D* pVertices, const size_t pVerticesQuantity, SBBox& pBBox); - - /********************************************************************/ - /************************ Logging functions *************************/ - /********************************************************************/ - - /// \fn void LogInfo(const QString& pMessage) - /// Add message with severity "Warning" to log. - void LogInfo(const QString& pMessage); - - /// \fn void LogError(const QString& pMessage) - /// Add message with severity "Error" to log. - void LogError(const QString& pMessage); - - /********************************************************************/ - /************************** Draw functions **************************/ - /********************************************************************/ - - /// \fn void Draw_Node(const aiNode* pNode) - /// Apply node transformation and draw meshes assigned to this node. - /// \param [in] pNode - pointer to node for drawing (\ref aiNode). - void Draw_Node(const aiNode* pNode); - - /// \fn void Draw_Mesh(const size_t pMesh_Index) - /// Draw mesh. - /// \param [in] pMesh_Index - index of mesh which must be drawn. Index point to mesh in \ref mHelper_Mesh. - void Draw_Mesh(const size_t pMesh_Index); - - /// \fn void Draw_BBox(const SBBox& pBBox) - /// Draw bounding box using lines. - /// \param [in] pBBox - bounding box for drawing. - void Draw_BBox(const SBBox& pBBox); - - /********************************************************************/ - /*********************** Override functions ************************/ - /********************************************************************/ - -protected: - - /// \fn void drawCoordSystem() - /// Draw axes of the coordinate system. - void drawCoordSystem(); - - /// \fn void initializeGL() override - /// Override function to initialise OpenGL. - void initializeGL() override; - - /// \fn void resizeGL(int pWidth, int pHeight) override - /// \param [in] pWidth - new width of viewport. - /// \param [in] pHeight - new height of viewport. - void resizeGL(int pWidth, int pHeight) override; - - /// \fn void paintGL() override - /// Override function for rendering. - void paintGL() override; - -public: - - /********************************************************************/ - /********************** Constructor/Destructor **********************/ - /********************************************************************/ - - /// \fn explicit CGLView(QWidget* pParent) - /// Constructor. - /// \param [in] pParent - parent widget. - explicit CGLView(QWidget* pParent); - - /// \fn virtual ~CGLView() - /// Destructor. - virtual ~CGLView(); - - /********************************************************************/ - /********************* Scene control functions **********************/ - /********************************************************************/ - - /// \fn void FreeScene() - /// Free all helper objects data. - void FreeScene(); - - /// \fn void SetScene(const aiScene* pScene) - /// Set scene for rendering. - /// \param [in] pScene - pointer to scene. - /// \param [in] pScenePath - path to the file of the scene. - void SetScene(const aiScene* pScene, const QString& pScenePath); - - /// \fn void Enable_SceneBBox(const bool pEnable) - /// Enable drawing scene bounding box. - /// \param [in] pEnable - if true then bbox will be drawing, if false - will not be drawing. - void Enable_SceneBBox(const bool pEnable) { mScene_DrawBBox = pEnable; } - - /// \fn void Enable_Textures(const bool pEnable) - /// Control textures drawing. - /// \param [in] pEnable - if true then enable textures, false - disable textures. - void Enable_Textures(const bool pEnable); - - /// \fn void Enable_Axes(const bool pEnable) - /// Control axes drawing. - /// \param [in] pEnable - if true then enable axes, false - disable axes. - void Enable_Axes(const bool pEnable) { this->mScene_AxesEnabled = pEnable; } - - /********************************************************************/ - /******************** Lighting control functions ********************/ - /********************************************************************/ - - /// \fn void Lighting_Enable() - /// Enable OpenGL lighting. - void Lighting_Enable(); - - /// \fn void Lighting_Disable() - /// Disable OpenGL lighting. - void Lighting_Disable(); - - /// \fn void Lighting_EditSource(const size_t pLightNumber, const SLightParameters& pLightParameters) - /// Edit light source properties. - /// \param [in] pLightNumber - light source number. \ref aiScene::mLights. - /// \param [in] pLightParameters - light source parameters. - void Lighting_EditSource(const size_t pLightNumber, const SLightParameters& pLightParameters);///TODO: function set - - /// \fn void Lighting_EnableSource(const size_t pLightNumber) - /// Enable light source. - /// \param [in] pLightNumber - light source number. \ref aiScene::mLights. - void Lighting_EnableSource(const size_t pLightNumber); - - ///void Lighting_DisableSource(const size_t pLightNumber) - /// Disable light source, - /// \param [in] pLightNumber - light source number. \ref aiScene::mLights. - void Lighting_DisableSource(const size_t pLightNumber); - - /********************************************************************/ - /******************** Cameras control functions *********************/ - /********************************************************************/ - - /// \fn void Camera_Set(const size_t pCameraNumber) - /// Set view from pointed camera. - /// \param [in] pCamera_Index - index of the camera (\ref aiScene::mCameras). - void Camera_Set(const size_t pCameraNumber); - - /// \fn void Camera_RotateScene(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z, const aiMatrix4x4* pMatrix_Rotation_Initial) - /// Rotate scene around axisees. - /// \param [in] pAngle_X - specifies the angle of rotation around axis oX, in degrees. - /// \param [in] pAngle_Y - specifies the angle of rotation around axis oY, in degrees. - /// \param [in] pAngle_Z - specifies the angle of rotation around axis oZ, in degrees. - /// \param [in] pMatrix_Rotation_Initial - matrix from which calculates new transformation matrix. If not set (equal to nullptr) then current transformation matrix - /// will be used. - void Camera_RotateScene(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z, const aiMatrix4x4* pMatrix_Rotation_Initial = nullptr); - - /// \fn void Camera_Rotate(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z, const aiMatrix4x4* pMatrix_Rotation_Initial = nullptr) - /// Rotate camera around axisees. - /// \param [in] pAngle_X - specifies the angle of rotation around axis oX, in degrees. - /// \param [in] pAngle_Y - specifies the angle of rotation around axis oY, in degrees. - /// \param [in] pAngle_Z - specifies the angle of rotation around axis oZ, in degrees. - /// \param [in] pMatrix_Rotation_Initial - matrix from which calculates new transformation matrix. If not set (equal to nullptr) then current transformation matrix - /// will be used. - void Camera_Rotate(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z, const aiMatrix4x4* pMatrix_Rotation_Initial = nullptr); - - /// \fn void Camera_Translate(const size_t pTranslate_X, const size_t pTranslate_Y, const size_t pTranslate_Z) - /// Translate camera along axises. In local coordinates. - /// \param [in] pTranslate_X - specifies the X coordinate of translation vector. - /// \param [in] pTranslate_Y - specifies the Y coordinate of translation vector. - /// \param [in] pTranslate_Z - specifies the Z coordinate of translation vector. - void Camera_Translate(const GLfloat pTranslate_X, const GLfloat pTranslate_Y, const GLfloat pTranslate_Z); - - /// \fn void Camera_Matrix(aiMatrix4x4& pRotation_Camera, aiMatrix4x4& pRotation_Scene, aiVector3D& pTranslation_Camera) - /// Return data about camera position in world. - /// \param [out] pRotation_Camera - rotation matrix which set rotation angles of the scene around camera. - /// \param [out] pRotation_Scene - rotation matrix which set rotation angles of the scene around own center. - /// \param [out] pTranslation_Camera - translation vector from camera to the scene. - void Camera_Matrix(aiMatrix4x4& pRotation_Camera, aiMatrix4x4& pRotation_Scene, aiVector3D& pTranslation_Camera); - -signals: - - /// \fn void Paint_Finished(const size_t pPaintTime, const GLfloat pDistance) - ///< Signal. Emits when execution of \ref paintGL is end. - /// \param [out] pPaintTime_ms - time spent for rendering, in milliseconds. - /// \param [out] pDistance - distance between current camera and center of the scene. \sa SHelper_Camera::Translation_ToScene. - void Paint_Finished(const size_t pPaintTime_ms, const GLfloat pDistance); - - /// \fn void SceneObject_Camera(const QString& pName) - /// Signal. Emit for every camera found in scene. Also for default camera. - /// \param [out] pName - name of the camera. - void SceneObject_Camera(const QString& pName); - - /// \fn void SceneObject_LightSource(const QString& pName) - /// Signal. Emit for every light source found in scene. Also for default light source. - /// \param [out] pName - name of the light source. - void SceneObject_LightSource(const QString& pName); -};// class CGLView diff --git a/tools/assimp_qt_viewer/loggerview.cpp b/tools/assimp_qt_viewer/loggerview.cpp deleted file mode 100644 index 2e0d15547..000000000 --- a/tools/assimp_qt_viewer/loggerview.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -#include "loggerview.hpp" - -// Header files, Qt. -#include -#include - -CLoggerView::CLoggerView(QTextBrowser* pOutputWidget) -: mOutputWidget(pOutputWidget) { - // empty -} - -CLoggerView::~CLoggerView() { - mOutputWidget = nullptr; -} - -void CLoggerView::write(const char *pMessage) { - if (nullptr == mOutputWidget) { - return; - } - - mOutputWidget->insertPlainText(QString("[%1] %2").arg(QTime::currentTime().toString()).arg(pMessage)); -} diff --git a/tools/assimp_qt_viewer/loggerview.hpp b/tools/assimp_qt_viewer/loggerview.hpp deleted file mode 100644 index 9011f671f..000000000 --- a/tools/assimp_qt_viewer/loggerview.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -#pragma once - -// Header files, Assimp. -#include - -class QTextBrowser; - -/// @class CLoggerView -/// @brief GUI-stream for Assimp logging sub-sytem. Get data for logging and write it to output widget. -class CLoggerView final : public ::Assimp::LogStream { -public: - /// @brief The class constructor. - /// @param [in] pOutputWidget - pointer to output widget. - explicit CLoggerView( QTextBrowser* pOutputWidget ); - - /// @brief The class destructor. - virtual ~CLoggerView(); - - /// Write message to output widget. Used by Assimp. - /// \param [in] pMessage - message for displaying. - virtual void write(const char *pMessage); - -private: - QTextBrowser * mOutputWidget; ///< Widget for displaying messages. -}; diff --git a/tools/assimp_qt_viewer/main.cpp b/tools/assimp_qt_viewer/main.cpp deleted file mode 100644 index 6dfdd4981..000000000 --- a/tools/assimp_qt_viewer/main.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -// Thanks to acorn89 for support. - -// Header files, project. -#include "mainwindow.hpp" - -// Header files, Qt. -#include - -int main(int argc, char *argv[]) { - QApplication app(argc, argv); - MainWindow win; - win.show(); - - return app.exec(); -} diff --git a/tools/assimp_qt_viewer/mainwindow.cpp b/tools/assimp_qt_viewer/mainwindow.cpp deleted file mode 100644 index 82c2fcbe3..000000000 --- a/tools/assimp_qt_viewer/mainwindow.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -#include "mainwindow.hpp" -#include "ui_mainwindow.h" - -// Header files, Assimp. -#include -#include - -#ifndef __unused - #define __unused __attribute__((unused)) -#endif // __unused - -using namespace Assimp; - - -void MainWindow::ImportFile(const QString &pFileName) { - QTime time_begin = QTime::currentTime(); - - if ( mScene != nullptr ) { - mImporter.FreeScene(); - mGLView->FreeScene(); - } - - // Try to import scene. - mScene = mImporter.ReadFile(pFileName.toStdString(), aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_ValidateDataStructure | \ - aiProcess_GenUVCoords | aiProcess_TransformUVCoords | aiProcess_FlipUVs); - if ( mScene != nullptr ) { - ui->lblLoadTime->setText(QString::number(time_begin.secsTo(QTime::currentTime()))); - LogInfo("Import done: " + pFileName); - // Prepare widgets for new scene. - ui->leFileName->setText(pFileName.right(pFileName.length() - pFileName.lastIndexOf('/') - 1)); - ui->lstLight->clear(); - ui->lstCamera->clear(); - ui->cbxLighting->setChecked(true); mGLView->Lighting_Enable(); - ui->cbxBBox->setChecked(false); mGLView->Enable_SceneBBox(false); - ui->cbxTextures->setChecked(true); mGLView->Enable_Textures(true); - - // - // Fill info labels - // - // Cameras - ui->lblCameraCount->setText(QString::number(mScene->mNumCameras)); - // Lights - ui->lblLightCount->setText(QString::number(mScene->mNumLights)); - // Meshes, faces, vertices. - size_t qty_face = 0; - size_t qty_vert = 0; - - for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++) { - qty_face += mScene->mMeshes[idx_mesh]->mNumFaces; - qty_vert += mScene->mMeshes[idx_mesh]->mNumVertices; - } - - ui->lblMeshCount->setText(QString::number(mScene->mNumMeshes)); - ui->lblFaceCount->setText(QString::number(qty_face)); - ui->lblVertexCount->setText(QString::number(qty_vert)); - // Animation - if(mScene->mNumAnimations) - ui->lblHasAnimation->setText("yes"); - else - ui->lblHasAnimation->setText("no"); - - // - // Set scene for GL viewer. - // - mGLView->SetScene(mScene, pFileName); - // Select first camera - ui->lstCamera->setCurrentRow(0); - mGLView->Camera_Set(0); - // Scene is loaded, do first rendering. - LogInfo("Scene is ready for rendering."); -#if ASSIMP_QT4_VIEWER - mGLView->updateGL(); -#else - mGLView->update(); -#endif // ASSIMP_QT4_VIEWER - } - else - { - ResetSceneInfos(); - - QString errorMessage = QString("Error parsing \'%1\' : \'%2\'").arg(pFileName).arg(mImporter.GetErrorString()); - QMessageBox::critical(this, "Import error", errorMessage); - LogError(errorMessage); - }// if(mScene != nullptr) -} - -void MainWindow::ResetSceneInfos() -{ - ui->lblLoadTime->clear(); - ui->leFileName->clear(); - ui->lblMeshCount->setText("0"); - ui->lblFaceCount->setText("0"); - ui->lblVertexCount->setText("0"); - ui->lblCameraCount->setText("0"); - ui->lblLightCount->setText("0"); - ui->lblHasAnimation->setText("no"); -} - -/********************************************************************/ -/************************ Logging functions *************************/ -/********************************************************************/ - -void MainWindow::LogInfo(const QString& pMessage) -{ - Assimp::DefaultLogger::get()->info(pMessage.toStdString()); -} - -void MainWindow::LogError(const QString& pMessage) -{ - Assimp::DefaultLogger::get()->error(pMessage.toStdString()); -} - -/********************************************************************/ -/*********************** Override functions ************************/ -/********************************************************************/ - -void MainWindow::mousePressEvent(QMouseEvent* pEvent) -{ - const QPoint ms_pt = pEvent->pos(); - aiVector3D temp_v3; - - // Check if GLView is pointed. - if(childAt(ms_pt) == mGLView) - { - if(!mMouse_Transformation.Position_Pressed_Valid) - { - mMouse_Transformation.Position_Pressed_Valid = true;// set flag - // Store current transformation matrices. - mGLView->Camera_Matrix(mMouse_Transformation.Rotation_AroundCamera, mMouse_Transformation.Rotation_Scene, temp_v3); - } - - if(pEvent->button() & Qt::LeftButton) - mMouse_Transformation.Position_Pressed_LMB = ms_pt; - else if(pEvent->button() & Qt::RightButton) - mMouse_Transformation.Position_Pressed_RMB = ms_pt; - } - else - { - mMouse_Transformation.Position_Pressed_Valid = false; - } -} - -void MainWindow::mouseReleaseEvent(QMouseEvent *pEvent) -{ - if(pEvent->buttons() == 0) mMouse_Transformation.Position_Pressed_Valid = false; - -} - -void MainWindow::mouseMoveEvent(QMouseEvent* pEvent) -{ - if(mMouse_Transformation.Position_Pressed_Valid) - { - if(pEvent->buttons() & Qt::LeftButton) - { - GLfloat dx = 180 * GLfloat(pEvent->x() - mMouse_Transformation.Position_Pressed_LMB.x()) / mGLView->width(); - GLfloat dy = 180 * GLfloat(pEvent->y() - mMouse_Transformation.Position_Pressed_LMB.y()) / mGLView->height(); - - if(pEvent->modifiers() & Qt::ShiftModifier) - mGLView->Camera_RotateScene(dy, 0, dx, &mMouse_Transformation.Rotation_Scene);// Rotate around oX and oZ axises. - else - mGLView->Camera_RotateScene(dy, dx, 0, &mMouse_Transformation.Rotation_Scene);// Rotate around oX and oY axises. - - #if ASSIMP_QT4_VIEWER - mGLView->updateGL(); - #else - mGLView->update(); - #endif // ASSIMP_QT4_VIEWER - } - - if(pEvent->buttons() & Qt::RightButton) - { - GLfloat dx = 180 * GLfloat(pEvent->x() - mMouse_Transformation.Position_Pressed_RMB.x()) / mGLView->width(); - GLfloat dy = 180 * GLfloat(pEvent->y() - mMouse_Transformation.Position_Pressed_RMB.y()) / mGLView->height(); - - if(pEvent->modifiers() & Qt::ShiftModifier) - mGLView->Camera_Rotate(dy, 0, dx, &mMouse_Transformation.Rotation_AroundCamera);// Rotate around oX and oZ axises. - else - mGLView->Camera_Rotate(dy, dx, 0, &mMouse_Transformation.Rotation_AroundCamera);// Rotate around oX and oY axises. - - #if ASSIMP_QT4_VIEWER - mGLView->updateGL(); - #else - mGLView->update(); - #endif // ASSIMP_QT4_VIEWER - } - } -} - -void MainWindow::keyPressEvent(QKeyEvent* pEvent) -{ -GLfloat step; - - if(pEvent->modifiers() & Qt::ControlModifier) - step = 10; - else if(pEvent->modifiers() & Qt::AltModifier) - step = 100; - else - step = 1; - - if(pEvent->key() == Qt::Key_A) - mGLView->Camera_Translate(-step, 0, 0); - else if(pEvent->key() == Qt::Key_D) - mGLView->Camera_Translate(step, 0, 0); - else if(pEvent->key() == Qt::Key_W) - mGLView->Camera_Translate(0, step, 0); - else if(pEvent->key() == Qt::Key_S) - mGLView->Camera_Translate(0, -step, 0); - else if(pEvent->key() == Qt::Key_Up) - mGLView->Camera_Translate(0, 0, -step); - else if(pEvent->key() == Qt::Key_Down) - mGLView->Camera_Translate(0, 0, step); - -#if ASSIMP_QT4_VIEWER - mGLView->updateGL(); -#else - mGLView->update(); -#endif // ASSIMP_QT4_VIEWER -} - -/********************************************************************/ -/********************** Constructor/Destructor **********************/ -/********************************************************************/ - -MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent), ui(new Ui::MainWindow), - mScene(nullptr) -{ - - // other variables - mMouse_Transformation.Position_Pressed_Valid = false; - - ui->setupUi(this); - // Create OpenGL widget - mGLView = new CGLView(this); - mGLView->setMinimumSize(800, 600); - mGLView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); - mGLView->setFocusPolicy(Qt::StrongFocus); - // Connect to GLView signals. - connect(mGLView, SIGNAL(Paint_Finished(size_t, GLfloat)), SLOT(Paint_Finished(size_t, GLfloat))); - connect(mGLView, SIGNAL(SceneObject_Camera(QString)), SLOT(SceneObject_Camera(QString))); - connect(mGLView, SIGNAL(SceneObject_LightSource(QString)), SLOT(SceneObject_LightSource(QString))); - // and add it to layout - ui->hlMainView->insertWidget(0, mGLView, 4); - // Create logger - mLoggerView = new CLoggerView(ui->tbLog); - DefaultLogger::create("", Logger::VERBOSE); - DefaultLogger::get()->attachStream(mLoggerView, DefaultLogger::Debugging | DefaultLogger::Info | DefaultLogger::Err | DefaultLogger::Warn); - - ResetSceneInfos(); -} - -MainWindow::~MainWindow() -{ -using namespace Assimp; - - DefaultLogger::get()->detatchStream(mLoggerView, DefaultLogger::Debugging | DefaultLogger::Info | DefaultLogger::Err | DefaultLogger::Warn); - DefaultLogger::kill(); - - if(mScene != nullptr) mImporter.FreeScene(); - if(mLoggerView != nullptr) delete mLoggerView; - if(mGLView != nullptr) delete mGLView; - delete ui; -} - -/********************************************************************/ -/****************************** Slots *******************************/ -/********************************************************************/ - -void MainWindow::Paint_Finished(const size_t pPaintTime_ms, const GLfloat pDistance) -{ - ui->lblRenderTime->setText(QString::number(pPaintTime_ms)); - ui->lblDistance->setText(QString::number(pDistance)); -} - -void MainWindow::SceneObject_Camera(const QString& pName) -{ - ui->lstCamera->addItem(pName); -} - -void MainWindow::SceneObject_LightSource(const QString& pName) -{ - ui->lstLight->addItem(pName); - // After item added "currentRow" is still contain old value (even '-1' if first item added). Because "currentRow"/"currentItem" is changed by user interaction, - // not by "addItem". So, "currentRow" must be set manually. - ui->lstLight->setCurrentRow(ui->lstLight->count() - 1); - // And after "selectAll" handler of "signal itemSelectionChanged" will get right "currentItem" and "currentRow" values. - ui->lstLight->selectAll(); -} - -void MainWindow::on_butOpenFile_clicked() { - aiString filter_temp; - mImporter.GetExtensionList( filter_temp ); - - QString filename, filter; - filter = filter_temp.C_Str(); - filter.replace(';', ' '); - filter.append(" ;; All (*.*)"); - filename = QFileDialog::getOpenFileName(this, "Choose the file", "", filter); - - if (!filename.isEmpty()) { - ImportFile( filename ); - } -} - -void MainWindow::on_butExport_clicked() -{ - using namespace Assimp; - -#ifndef ASSIMP_BUILD_NO_EXPORT - QString filename, filter, format_id; - Exporter exporter; - QTime time_begin; - aiReturn rv; - QStringList exportersList; - QMap exportersMap; - - - if(mScene == nullptr) - { - QMessageBox::critical(this, "Export error", "Scene is empty"); - - return; - } - - for (size_t i = 0; i < exporter.GetExportFormatCount(); ++i) - { - const aiExportFormatDesc* desc = exporter.GetExportFormatDescription(i); - exportersList.push_back(desc->id + QString(": ") + desc->description); - exportersMap.insert(desc->id, desc); - } - - // get an exporter - bool dialogSelectExporterOk; - QString selectedExporter = QInputDialog::getItem(this, "Export format", "Select the exporter : ", exportersList, 0, false, &dialogSelectExporterOk); - if (!dialogSelectExporterOk) - return; - - // build the filter - QString selectedId = selectedExporter.left(selectedExporter.indexOf(':')); - filter = QString("*.") + exportersMap[selectedId]->fileExtension; - - // get file path - filename = QFileDialog::getSaveFileName(this, "Set file name", "", filter); - // if it's canceled - if (filename == "") - return; - - // begin export - time_begin = QTime::currentTime(); - rv = exporter.Export(mScene, selectedId.toLocal8Bit(), filename.toLocal8Bit(), aiProcess_FlipUVs); - ui->lblExportTime->setText(QString::number(time_begin.secsTo(QTime::currentTime()))); - if(rv == aiReturn_SUCCESS) - LogInfo("Export done: " + filename); - else - { - QString errorMessage = QString("Export failed: ") + filename; - LogError(errorMessage); - QMessageBox::critical(this, "Export error", errorMessage); - } -#endif -} - -void MainWindow::on_cbxLighting_clicked(bool pChecked) -{ - if(pChecked) - mGLView->Lighting_Enable(); - else - mGLView->Lighting_Disable(); - - mGLView->update(); -} - -void MainWindow::on_lstLight_itemSelectionChanged() -{ -bool selected = ui->lstLight->isItemSelected(ui->lstLight->currentItem()); - - if(selected) - mGLView->Lighting_EnableSource(ui->lstLight->currentRow()); - else - mGLView->Lighting_DisableSource(ui->lstLight->currentRow()); - -#if ASSIMP_QT4_VIEWER - mGLView->updateGL(); -#else - mGLView->update(); -#endif // ASSIMP_QT4_VIEWER -} - -void MainWindow::on_lstCamera_clicked( const QModelIndex &) -{ - mGLView->Camera_Set(ui->lstLight->currentRow()); -#if ASSIMP_QT4_VIEWER - mGLView->updateGL(); -#else - mGLView->update(); -#endif // ASSIMP_QT4_VIEWER -} - -void MainWindow::on_cbxBBox_clicked(bool checked) -{ - mGLView->Enable_SceneBBox(checked); -#if ASSIMP_QT4_VIEWER - mGLView->updateGL(); -#else - mGLView->update(); -#endif // ASSIMP_QT4_VIEWER -} - -void MainWindow::on_cbxDrawAxes_clicked(bool checked) -{ - mGLView->Enable_Axes(checked); -#if ASSIMP_QT4_VIEWER - mGLView->updateGL(); -#else - mGLView->update(); -#endif // ASSIMP_QT4_VIEWER -} - -void MainWindow::on_cbxTextures_clicked(bool checked) -{ - mGLView->Enable_Textures(checked); - mGLView->update(); -} diff --git a/tools/assimp_qt_viewer/mainwindow.hpp b/tools/assimp_qt_viewer/mainwindow.hpp deleted file mode 100644 index 1ebd19996..000000000 --- a/tools/assimp_qt_viewer/mainwindow.hpp +++ /dev/null @@ -1,148 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -#pragma once - -// Header files, Qt. -#if defined ASSIMP_QT4_VIEWER -# include -#else -# include -#endif - -// Header files, project. -#include "glview.hpp" -#include "loggerview.hpp" - -// Header files, Assimp. -#include -#include - -namespace Ui { - class MainWindow; -} - -/// \class MainWindow -/// Main window and algorithms. -class MainWindow : public QMainWindow { - Q_OBJECT - - struct SMouse_Transformation; - -public: - /// @brief The class constructor. - /// \param [in] pParent - pointer to parent widget. - explicit MainWindow( QWidget* pParent = 0 ); - - /// @brief The class destructor. - ~MainWindow(); - - /// Import scene from file. - /// \param [in] pFileName - path and name of the file. - void ImportFile(const QString& pFileName); - - /// Reset informations about the scene - void ResetSceneInfos(); - - /// Add message with severity "Warning" to log. - void LogInfo(const QString& pMessage); - - /// Add message with severity "Error" to log. - void LogError(const QString& pMessage); - -protected: - /// Override function which handles mouse event "button pressed". - /// \param [in] pEvent - pointer to event data. - void mousePressEvent(QMouseEvent* pEvent) override; - - /// Override function which handles mouse event "button released". - /// \param [in] pEvent - pointer to event data. - void mouseReleaseEvent(QMouseEvent *pEvent) override; - - /// Override function which handles mouse event "move". - /// \param [in] pEvent - pointer to event data. - void mouseMoveEvent(QMouseEvent* pEvent) override; - - /// Override function which handles key event "key pressed". - /// \param [in] pEvent - pointer to event data. - void keyPressEvent(QKeyEvent* pEvent) override; - -private slots: - /// Show paint/render time and distance between camera and center of the scene. - /// \param [in] pPaintTime_ms - paint time in milliseconds. - void Paint_Finished(const size_t pPaintTime_ms, const GLfloat pDistance); - - /// Add camera name to list. - /// \param [in] pName - name of the camera. - void SceneObject_Camera(const QString& pName); - - /// Add lighting source name to list. - /// \param [in] pName - name of the light source, - void SceneObject_LightSource(const QString& pName); - - void on_butOpenFile_clicked(); - void on_butExport_clicked(); - void on_cbxLighting_clicked(bool pChecked); - void on_lstLight_itemSelectionChanged(); - void on_lstCamera_clicked(const QModelIndex &index); - void on_cbxBBox_clicked(bool checked); - void on_cbxTextures_clicked(bool checked); - void on_cbxDrawAxes_clicked(bool checked); - -private: - Ui::MainWindow *ui; - CGLView *mGLView;///< Pointer to OpenGL render. - CLoggerView *mLoggerView;///< Pointer to logging object. - Assimp::Importer mImporter;///< Assimp importer. - const aiScene* mScene;///< Pointer to loaded scene (\ref aiScene). - - /// \struct SMouse_Transformation - /// Holds data about transformation of the scene/camera when mouse us used. - struct SMouse_Transformation { - bool Position_Pressed_Valid;///< Mouse button pressed on GLView. - QPoint Position_Pressed_LMB;///< Position where was pressed left mouse button. - QPoint Position_Pressed_RMB;///< Position where was pressed right mouse button. - aiMatrix4x4 Rotation_AroundCamera;///< Rotation matrix which set rotation angles of the scene around camera. - aiMatrix4x4 Rotation_Scene;///< Rotation matrix which set rotation angles of the scene around own center. - } mMouse_Transformation; -}; diff --git a/tools/assimp_qt_viewer/mainwindow.ui b/tools/assimp_qt_viewer/mainwindow.ui deleted file mode 100644 index 04208f585..000000000 --- a/tools/assimp_qt_viewer/mainwindow.ui +++ /dev/null @@ -1,544 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 641 - 778 - - - - MainWindow - - - - - - - - - QLayout::SetDefaultConstraint - - - - - - - - 0 - 0 - - - - Qt::NoFocus - - - File - - - - - - Qt::NoFocus - - - Open file - - - - - - - Qt::NoFocus - - - File name - - - - - - - - 160 - 16777215 - - - - Qt::NoFocus - - - false - - - true - - - - - - - Qt::NoFocus - - - Load time, s - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - Qt::Horizontal - - - - - - - Qt::NoFocus - - - Export - - - - - - - Qt::NoFocus - - - Export time, s - - - - - - - Qt::NoFocus - - - - - - - - - - - - - - 0 - 0 - - - - Qt::NoFocus - - - Info - - - - - - Qt::NoFocus - - - Render time, ms - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - Meshes - - - - - - - Qt::NoFocus - - - Faces - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - Vertices - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - Lights - - - - - - - Qt::NoFocus - - - Cameras - - - - - - - Qt::NoFocus - - - Animation - - - - - - - false - - - Qt::NoFocus - - - Shaders - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - false - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Distance - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - false - - - Qt::NoFocus - - - Dynamics - - - - - - Qt::NoFocus - - - Animation start - - - - - - - Qt::NoFocus - - - Animation stop - - - - - - - - - - - - - - Qt::NoFocus - - - 2 - - - - Log - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - Qt::NoFocus - - - - - - - - Lights and cameras - - - - - - Qt::NoFocus - - - Light sources of the scene - - - QAbstractItemView::SelectedClicked - - - false - - - QAbstractItemView::MultiSelection - - - - - - - Qt::NoFocus - - - Cameras of the scene - - - QAbstractItemView::NoEditTriggers - - - false - - - - - - - - Control - - - - - - Enable/Disable OpenGL lighting - - - Lighting - - - true - - - - - - - Scene BBox - - - - - - - Textures - - - - - - - Show Axes - - - true - - - - - - - - - - - - - - - - - installEventFilter() - -