From f0714a27f0782c531c8ed8b7b36c38dbc6564b98 Mon Sep 17 00:00:00 2001 From: Filip Wasil Date: Wed, 10 Sep 2014 12:00:58 +0200 Subject: [PATCH] Android JNI asset extraction support (API 9+) Signed-off-by: Filip Wasil --- CREDITS | 3 + INSTALL | 8 ++ code/AndroidJNIIOSystem.cpp | 168 ++++++++++++++++++++++++++++++++++++ code/AndroidJNIIOSystem.h | 91 +++++++++++++++++++ code/CMakeLists.txt | 15 +++- code/DefaultIOStream.h | 3 + code/Importer.cpp | 30 ++++++- include/assimp/Importer.hpp | 25 ++++++ include/assimp/config.h | 8 ++ 9 files changed, 345 insertions(+), 6 deletions(-) create mode 100644 code/AndroidJNIIOSystem.cpp create mode 100644 code/AndroidJNIIOSystem.h diff --git a/CREDITS b/CREDITS index 5d45a9e92..2e7485fb7 100644 --- a/CREDITS +++ b/CREDITS @@ -148,3 +148,6 @@ Bugfixes for uv-tanget calculation. - Jonne Nauha Ogre Binary format support + +- Filip Wasil, Tieto Poland Sp. z o.o. +Android JNI asset extraction support diff --git a/INSTALL b/INSTALL index 563fda397..756a7240f 100644 --- a/INSTALL +++ b/INSTALL @@ -42,4 +42,12 @@ toolchain (for standard GNU makefiles: cmake -G 'Unix Makefiles'). Afterwards, use the generated build files to perform the actual build. +------------------------------ +Building for Android +------------------------------ +When building for android this flag must be introduced to CMAKE: + +-DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake + +where "android.toolchain.cmake" is a toolchain script for android (Can be easily found in web) diff --git a/code/AndroidJNIIOSystem.cpp b/code/AndroidJNIIOSystem.cpp new file mode 100644 index 000000000..15b9ba7e2 --- /dev/null +++ b/code/AndroidJNIIOSystem.cpp @@ -0,0 +1,168 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2012, 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. +--------------------------------------------------------------------------- +*/ + +/** @file Android extension of DefaultIOSystem using the standard C file functions */ + + +#include "AssimpPCH.h" +#if __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) + +#include +#include "AndroidJNIIOSystem.h" +#include "DefaultIOStream.h" + +using namespace Assimp; + +// ------------------------------------------------------------------------------------------------ +// Constructor. +AndroidJNIIOSystem::AndroidJNIIOSystem(ANativeActivity* activity) +{ + AndroidActivityInit(activity); +} + +// ------------------------------------------------------------------------------------------------ +// Destructor. +AndroidJNIIOSystem::~AndroidJNIIOSystem() +{ + // nothing to do here +} + +// ------------------------------------------------------------------------------------------------ +// Tests for the existence of a file at the given path. +bool AndroidJNIIOSystem::Exists( const char* pFile) const +{ + AAsset* asset = AAssetManager_open(mApkAssetManager, pFile, + AASSET_MODE_UNKNOWN); + FILE* file = ::fopen( (mApkWorkspacePath + getOsSeparator() + std::string(pFile)).c_str(), "rb"); + + if (!asset && !file) + { + __android_log_print(ANDROID_LOG_ERROR, "Assimp", "Asset manager can not find: %s", pFile); + return false; + } + + __android_log_print(ANDROID_LOG_ERROR, "Assimp", "Asset exists"); + if (file) + ::fclose( file); + return true; +} + +// ------------------------------------------------------------------------------------------------ +// Inits Android extractor +void AndroidJNIIOSystem::AndroidActivityInit(ANativeActivity* activity) +{ + mApkWorkspacePath = activity->internalDataPath; + mApkAssetManager = activity->assetManager; +} + +// ------------------------------------------------------------------------------------------------ +// Extracts android asset +bool AndroidJNIIOSystem::AndroidExtractAsset(std::string name) +{ + std::string newPath = mApkWorkspacePath + getOsSeparator() + name; + + DefaultIOSystem io; + + // Do not extract if extracted already + if ( io.Exists(newPath.c_str()) ) { + __android_log_print(ANDROID_LOG_DEFAULT, "Assimp", "Asset already extracted"); + return true; + } + // Open file + AAsset* asset = AAssetManager_open(mApkAssetManager, name.c_str(), + AASSET_MODE_UNKNOWN); + std::string assetContent; + + if (asset != NULL) { + // Find size + off_t assetSize = AAsset_getLength(asset); + + // Prepare input buffer + assetContent.resize(assetSize); + + // Store input buffer + AAsset_read(asset, &assetContent[0], assetSize); + + // Close + AAsset_close(asset); + + // Prepare output buffer + std::ofstream assetExtracted(newPath.c_str(), + std::ios::out | std::ios::binary); + if (!assetExtracted) { + __android_log_print(ANDROID_LOG_ERROR, "assimp", + "Can not open output file"); + } + + // Write output buffer into a file + assetExtracted.write(assetContent.c_str(), strlen(assetContent.c_str())); + assetExtracted.close(); + + __android_log_print(ANDROID_LOG_DEFAULT, "Assimp", "Asset extracted"); + } else { + __android_log_print(ANDROID_LOG_ERROR, "assimp", "Asset not found: %s", name.c_str()); + return false; + } + return true; +} + +// ------------------------------------------------------------------------------------------------ +// Open a new file with a given path. +IOStream* AndroidJNIIOSystem::Open( const char* strFile, const char* strMode) +{ + ai_assert(NULL != strFile); + ai_assert(NULL != strMode); + + std::string fullPath(mApkWorkspacePath + getOsSeparator() + std::string(strFile)); + if (Exists(strFile)) + AndroidExtractAsset(std::string(strFile)); + + FILE* file = ::fopen( fullPath.c_str(), strMode); + + if( NULL == file) + return NULL; + + __android_log_print(ANDROID_LOG_ERROR, "assimp", "AndroidIOSystem: file %s opened", fullPath.c_str()); + return new DefaultIOStream(file, fullPath); +} + +#undef PATHLIMIT +#endif // __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) diff --git a/code/AndroidJNIIOSystem.h b/code/AndroidJNIIOSystem.h new file mode 100644 index 000000000..5d1585c02 --- /dev/null +++ b/code/AndroidJNIIOSystem.h @@ -0,0 +1,91 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2012, 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. + +---------------------------------------------------------------------- +*/ + +/** @file Android implementation of IOSystem using the standard C file functions. + * Aimed to ease the acces to android assets */ + +#if __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) +#ifndef AI_ANDROIDJNIIOSYSTEM_H_INC +#define AI_ANDROIDJNIIOSYSTEM_H_INC + +#include "DefaultIOSystem.h" +#include +#include + +namespace Assimp { + +// --------------------------------------------------------------------------- +/** Android extension to DefaultIOSystem using the standard C file functions */ +class AndroidJNIIOSystem : public DefaultIOSystem +{ +public: + + /** Initialize android activity data */ + std::string mApkWorkspacePath; + AAssetManager* mApkAssetManager; + + /** Constructor. */ + AndroidJNIIOSystem(ANativeActivity* activity); + + /** Destructor. */ + ~AndroidJNIIOSystem(); + + // ------------------------------------------------------------------- + /** Tests for the existence of a file at the given path. */ + bool Exists( const char* pFile) const; + + // ------------------------------------------------------------------- + /** Opens a file at the given path, with given mode */ + IOStream* Open( const char* strFile, const char* strMode); + + // ------------------------------------------------------------------------------------------------ + // Inits Android extractor + void AndroidActivityInit(ANativeActivity* activity); + + // ------------------------------------------------------------------------------------------------ + // Extracts android asset + bool AndroidExtractAsset(std::string name); + +}; + +} //!ns Assimp + +#endif //AI_ANDROIDJNIIOSYSTEM_H_INC +#endif //__ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index f9a09378e..e8fce9943 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -104,6 +104,8 @@ SET( Common_SRCS DefaultIOStream.h DefaultIOSystem.cpp DefaultIOSystem.h + AndroidJNIIOSystem.cpp + AndroidJNIIOSystem.h CInterfaceIOWrapper.h Hash.h Importer.cpp @@ -702,7 +704,12 @@ ADD_LIBRARY( assimp ${assimp_src} ) SET_PROPERTY(TARGET assimp PROPERTY DEBUG_POSTFIX ${ASSIMP_DEBUG_POSTFIX}) -TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES}) +if(ANDROID) + TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} android log) +else(ANDROID) + TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES}) +endif(ANDROID) + SET_TARGET_PROPERTIES( assimp PROPERTIES VERSION ${ASSIMP_VERSION} SOVERSION ${ASSIMP_SOVERSION} # use full version @@ -717,7 +724,11 @@ endif() # assimp can #include "unzip.h" if (UNZIP_FOUND) INCLUDE_DIRECTORIES(${UNZIP_INCLUDE_DIRS}) - TARGET_LINK_LIBRARIES(assimp ${UNZIP_LIBRARIES}) + if(ANDROID) + TARGET_LINK_LIBRARIES(assimp ${UNZIP_LIBRARIES} android log) + else(ANDROID) + TARGET_LINK_LIBRARIES(assimp ${UNZIP_LIBRARIES}) + endif(ANDROID) else (UNZIP_FOUND) INCLUDE_DIRECTORIES("../contrib/unzip") endif (UNZIP_FOUND) diff --git a/code/DefaultIOStream.h b/code/DefaultIOStream.h index da1eed0b8..6ddf94c23 100644 --- a/code/DefaultIOStream.h +++ b/code/DefaultIOStream.h @@ -56,6 +56,9 @@ namespace Assimp { class DefaultIOStream : public IOStream { friend class DefaultIOSystem; +#if __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) + friend class AndroidJNIIOSystem; +#endif //__ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) protected: DefaultIOStream (); diff --git a/code/Importer.cpp b/code/Importer.cpp index c6b9daf67..4ded759a2 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -65,6 +65,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "BaseProcess.h" #include "DefaultIOStream.h" +#if __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) +#include "AndroidJNIIOSystem.h" +#include +#include +#endif //__ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) #include "DefaultIOSystem.h" #include "DefaultProgressHandler.h" #include "GenericProperty.h" @@ -132,8 +137,8 @@ void AllocateFromAssimpHeap::operator delete[] ( void* data) { } // ------------------------------------------------------------------------------------------------ -// Importer constructor. -Importer::Importer() +// Importer defaults loader. +inline void Importer::InitDefaults() { // allocate the pimpl first pimpl = new ImporterPimpl(); @@ -143,7 +148,7 @@ Importer::Importer() // Allocate a default IO handler pimpl->mIOHandler = new DefaultIOSystem; - pimpl->mIsDefaultHandler = true; + pimpl->mIsDefaultHandler = true; pimpl->bExtraVerbose = false; // disable extra verbose mode by default pimpl->mProgressHandler = new DefaultProgressHandler(); @@ -155,13 +160,30 @@ Importer::Importer() // Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list. pimpl->mPPShared = new SharedPostProcessInfo(); for (std::vector::iterator it = pimpl->mPostProcessingSteps.begin(); - it != pimpl->mPostProcessingSteps.end(); + it != pimpl->mPostProcessingSteps.end(); ++it) { (*it)->SetSharedData(pimpl->mPPShared); } } +// ------------------------------------------------------------------------------------------------ +// Importer constructor. +Importer::Importer() +{ + InitDefaults(); +} + +// ------------------------------------------------------------------------------------------------ +// Jni android Importer constructor to ease the assets access on Android JNI projects. +#if __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) +Importer::Importer(ANativeActivity* activity) +{ + InitDefaults(); + SetIOHandler(new AndroidJNIIOSystem(activity)); +} +#endif //__ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) + // ------------------------------------------------------------------------------------------------ // Destructor of Importer Importer::~Importer() diff --git a/include/assimp/Importer.hpp b/include/assimp/Importer.hpp index 5e7797b99..4845c51e6 100644 --- a/include/assimp/Importer.hpp +++ b/include/assimp/Importer.hpp @@ -53,6 +53,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "types.h" #include "config.h" +#if __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) +#include +#include +#include +#include +#include +#endif //__ANDROID__ and __ANDROID_API__ > 9 and defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) + namespace Assimp { // ======================================================================= // Public interface to Assimp @@ -125,6 +133,15 @@ public: */ Importer(); +#if __ANDROID__ and __ANDROID_API__ > 9 and defined(AI_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) + // ------------------------------------------------------------------- + /** Constructor. Inits the AndroidJniIOSystem. + * + * Call ReadFile() to start the import process. The configuration + * property table is initially empty. + */ + Importer(ANativeActivity* activity); +#endif //__ANDROID__ and __ANDROID_API__ > 9 and defined(AI_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT) // ------------------------------------------------------------------- /** Copy constructor. * @@ -134,6 +151,14 @@ public: */ Importer(const Importer& other); + // ------------------------------------------------------------------- + /** Inits Importer defaults. + * + * This function inits the defaults for Importer class + * + */ + void InitDefaults(); + // ------------------------------------------------------------------- /** Destructor. The object kept ownership of the imported data, * which now will be destroyed along with the object. diff --git a/include/assimp/config.h b/include/assimp/config.h index 6bd31aada..56ef8f3b5 100644 --- a/include/assimp/config.h +++ b/include/assimp/config.h @@ -841,6 +841,14 @@ enum aiComponent */ #define AI_CONFIG_IMPORT_IFC_SKIP_SPACE_REPRESENTATIONS "IMPORT_IFC_SKIP_SPACE_REPRESENTATIONS" + /** @brief Specifies whether the Android JNI asset extraction is supported. + * + * Turn on this option if you want to manage assets in native + * Android application without having to keep the internal directory and asset + * manager pointer. + */ + #define AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT "AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT" + // --------------------------------------------------------------------------- /** @brief Specifies whether the IFC loader skips over