Merge branch 'master' into patch-1

pull/2577/head
Kim Kulling 2019-08-14 21:21:18 +02:00 committed by GitHub
commit a9b4909a2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 2685 additions and 2590 deletions

View File

@ -341,7 +341,7 @@ SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
IF (is_multi_config OR (CMAKE_BUILD_TYPE STREQUAL "Debug")) IF (INJECT_DEBUG_POSTFIX AND (CMAKE_BUILD_TYPE STREQUAL "Debug"))
SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools") SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools")
ELSE() ELSE()
SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools") SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools")

View File

@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <string> #include <string>
#include <vector> #include <vector>
@ -58,11 +59,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory> #include <memory>
#include "D3MFOpcPackage.h" #include "D3MFOpcPackage.h"
#ifdef ASSIMP_USE_HUNTER
# include <minizip/unzip.h>
#else
# include <unzip.h>
#endif
#include <assimp/irrXMLWrapper.h> #include <assimp/irrXMLWrapper.h>
#include "3MFXmlTags.h" #include "3MFXmlTags.h"
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
@ -453,7 +449,7 @@ bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bo
if ( nullptr == pIOHandler ) { if ( nullptr == pIOHandler ) {
return false; return false;
} }
if ( !D3MF::D3MFOpcPackage::isZipArchive( pIOHandler, filename ) ) { if ( !ZipArchiveIOSystem::isZipArchive( pIOHandler, filename ) ) {
return false; return false;
} }
D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename ); D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename );

View File

@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <cstdlib> #include <cstdlib>
#include <memory> #include <memory>
@ -56,344 +57,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <map> #include <map>
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#ifdef ASSIMP_USE_HUNTER
# include <minizip/unzip.h>
#else
# include <unzip.h>
#endif
#include "3MFXmlTags.h" #include "3MFXmlTags.h"
namespace Assimp { namespace Assimp {
namespace D3MF { namespace D3MF {
class IOSystem2Unzip {
public:
static voidpf open(voidpf opaque, const char* filename, int mode);
static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size);
static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size);
static long tell(voidpf opaque, voidpf stream);
static long seek(voidpf opaque, voidpf stream, uLong offset, int origin);
static int close(voidpf opaque, voidpf stream);
static int testerror(voidpf opaque, voidpf stream);
static zlib_filefunc_def get(IOSystem* pIOHandler);
};
voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
IOSystem* io_system = reinterpret_cast<IOSystem*>(opaque);
const char* mode_fopen = NULL;
if((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) {
mode_fopen = "rb";
} else {
if(mode & ZLIB_FILEFUNC_MODE_EXISTING) {
mode_fopen = "r+b";
} else {
if(mode & ZLIB_FILEFUNC_MODE_CREATE) {
mode_fopen = "wb";
}
}
}
return (voidpf) io_system->Open(filename, mode_fopen);
}
uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) {
IOStream* io_stream = (IOStream*) stream;
return static_cast<uLong>(io_stream->Read(buf, 1, size));
}
uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) {
IOStream* io_stream = (IOStream*) stream;
return static_cast<uLong>(io_stream->Write(buf, 1, size));
}
long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) {
IOStream* io_stream = (IOStream*) stream;
return static_cast<long>(io_stream->Tell());
}
long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) {
IOStream* io_stream = (IOStream*) stream;
aiOrigin assimp_origin;
switch (origin) {
default:
case ZLIB_FILEFUNC_SEEK_CUR:
assimp_origin = aiOrigin_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END:
assimp_origin = aiOrigin_END;
break;
case ZLIB_FILEFUNC_SEEK_SET:
assimp_origin = aiOrigin_SET;
break;
}
return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1);
}
int IOSystem2Unzip::close(voidpf opaque, voidpf stream) {
IOSystem* io_system = (IOSystem*) opaque;
IOStream* io_stream = (IOStream*) stream;
io_system->Close(io_stream);
return 0;
}
int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) {
return 0;
}
zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
zlib_filefunc_def mapping;
#ifdef ASSIMP_USE_HUNTER
mapping.zopen_file = (open_file_func)open;
mapping.zread_file = (read_file_func)read;
mapping.zwrite_file = (write_file_func)write;
mapping.ztell_file = (tell_file_func)tell;
mapping.zseek_file = (seek_file_func)seek;
mapping.zclose_file = (close_file_func)close;
mapping.zerror_file = (error_file_func)testerror;
#else
mapping.zopen_file = open;
mapping.zread_file = read;
mapping.zwrite_file = write;
mapping.ztell_file = tell;
mapping.zseek_file = seek;
mapping.zclose_file = close;
mapping.zerror_file = testerror;
#endif
mapping.opaque = reinterpret_cast<voidpf>(pIOHandler);
return mapping;
}
class ZipFile : public IOStream {
friend class D3MFZipArchive;
public:
explicit ZipFile(size_t size);
virtual ~ZipFile();
size_t Read(void* pvBuffer, size_t pSize, size_t pCount );
size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/);
size_t FileSize() const;
aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/);
size_t Tell() const;
void Flush();
private:
void *m_Buffer;
size_t m_Size;
};
ZipFile::ZipFile(size_t size)
: m_Buffer( nullptr )
, m_Size(size) {
ai_assert(m_Size != 0);
m_Buffer = ::malloc(m_Size);
}
ZipFile::~ZipFile() {
::free(m_Buffer);
m_Buffer = NULL;
}
size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) {
const size_t size = pSize * pCount;
ai_assert(size <= m_Size);
std::memcpy(pvBuffer, m_Buffer, size);
return size;
}
size_t ZipFile::Write(const void* pvBuffer, size_t size, size_t pCount ) {
const size_t size_to_write( size * pCount );
if ( 0 == size_to_write ) {
return 0U;
}
return 0U;
}
size_t ZipFile::FileSize() const {
return m_Size;
}
aiReturn ZipFile::Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
return aiReturn_FAILURE;
}
size_t ZipFile::Tell() const {
return 0;
}
void ZipFile::Flush() {
// empty
}
class D3MFZipArchive : public IOSystem {
public:
static const unsigned int FileNameSize = 256;
D3MFZipArchive(IOSystem* pIOHandler, const std::string & rFile);
~D3MFZipArchive();
bool Exists(const char* pFile) const;
char getOsSeparator() const;
IOStream* Open(const char* pFile, const char* pMode = "rb");
void Close(IOStream* pFile);
bool isOpen() const;
void getFileList(std::vector<std::string> &rFileList);
private:
bool mapArchive();
private:
unzFile m_ZipFileHandle;
std::map<std::string, ZipFile*> m_ArchiveMap;
};
// ------------------------------------------------------------------------------------------------
// Constructor.
D3MFZipArchive::D3MFZipArchive(IOSystem* pIOHandler, const std::string& rFile)
: m_ZipFileHandle( nullptr )
, m_ArchiveMap() {
if (! rFile.empty()) {
zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
if(m_ZipFileHandle != nullptr ) {
mapArchive();
}
}
}
// ------------------------------------------------------------------------------------------------
// Destructor.
D3MFZipArchive::~D3MFZipArchive() {
for(auto &file : m_ArchiveMap) {
delete file.second;
}
m_ArchiveMap.clear();
if(m_ZipFileHandle != nullptr) {
unzClose(m_ZipFileHandle);
m_ZipFileHandle = nullptr;
}
}
// ------------------------------------------------------------------------------------------------
// Returns true, if the archive is already open.
bool D3MFZipArchive::isOpen() const {
return (m_ZipFileHandle != nullptr );
}
// ------------------------------------------------------------------------------------------------
// Returns true, if the filename is part of the archive.
bool D3MFZipArchive::Exists(const char* pFile) const {
ai_assert(pFile != nullptr );
if ( pFile == nullptr ) {
return false;
}
std::string filename(pFile);
std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(filename);
bool exist( false );
if(it != m_ArchiveMap.end()) {
exist = true;
}
return exist;
}
// ------------------------------------------------------------------------------------------------
// Returns the separator delimiter.
char D3MFZipArchive::getOsSeparator() const {
#ifndef _WIN32
return '/';
#else
return '\\';
#endif
}
// ------------------------------------------------------------------------------------------------
// Opens a file, which is part of the archive.
IOStream *D3MFZipArchive::Open(const char* pFile, const char* /*pMode*/) {
ai_assert(pFile != NULL);
IOStream* result = NULL;
std::map<std::string, ZipFile*>::iterator it = m_ArchiveMap.find(pFile);
if(it != m_ArchiveMap.end()) {
result = static_cast<IOStream*>(it->second);
}
return result;
}
// ------------------------------------------------------------------------------------------------
// Close a filestream.
void D3MFZipArchive::Close(IOStream *pFile) {
(void)(pFile);
ai_assert(pFile != NULL);
// We don't do anything in case the file would be opened again in the future
}
// ------------------------------------------------------------------------------------------------
// Returns the file-list of the archive.
void D3MFZipArchive::getFileList(std::vector<std::string> &rFileList) {
rFileList.clear();
for(const auto &file : m_ArchiveMap) {
rFileList.push_back(file.first);
}
}
// ------------------------------------------------------------------------------------------------
// Maps the archive content.
bool D3MFZipArchive::mapArchive() {
bool success = false;
if(m_ZipFileHandle != NULL) {
if(m_ArchiveMap.empty()) {
// At first ensure file is already open
if(unzGoToFirstFile(m_ZipFileHandle) == UNZ_OK) {
// Loop over all files
do {
char filename[FileNameSize];
unz_file_info fileInfo;
if(unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, NULL, 0, NULL, 0) == UNZ_OK) {
// The file has EXACTLY the size of uncompressed_size. In C
// you need to mark the last character with '\0', so add
// another character
if(fileInfo.uncompressed_size != 0 && unzOpenCurrentFile(m_ZipFileHandle) == UNZ_OK) {
std::pair<std::map<std::string, ZipFile*>::iterator, bool> result = m_ArchiveMap.insert(std::make_pair(filename, new ZipFile(fileInfo.uncompressed_size)));
if(unzReadCurrentFile(m_ZipFileHandle, result.first->second->m_Buffer, fileInfo.uncompressed_size) == (long int) fileInfo.uncompressed_size) {
if(unzCloseCurrentFile(m_ZipFileHandle) == UNZ_OK) {
// Nothing to do anymore...
}
}
}
}
} while(unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE);
}
}
success = true;
}
return success;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr; typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr;
@ -453,7 +121,7 @@ public:
D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile) D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
: mRootStream(nullptr) : mRootStream(nullptr)
, mZipArchive() { , mZipArchive() {
mZipArchive.reset( new D3MF::D3MFZipArchive( pIOHandler, rFile ) ); mZipArchive.reset( new ZipArchiveIOSystem( pIOHandler, rFile ) );
if(!mZipArchive->isOpen()) { if(!mZipArchive->isOpen()) {
throw DeadlyImportError("Failed to open file " + rFile+ "."); throw DeadlyImportError("Failed to open file " + rFile+ ".");
} }
@ -481,14 +149,14 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
ASSIMP_LOG_DEBUG(rootFile); ASSIMP_LOG_DEBUG(rootFile);
mZipArchive->Close(fileStream);
mRootStream = mZipArchive->Open(rootFile.c_str()); mRootStream = mZipArchive->Open(rootFile.c_str());
ai_assert( mRootStream != nullptr ); ai_assert( mRootStream != nullptr );
if ( nullptr == mRootStream ) { if ( nullptr == mRootStream ) {
throw DeadlyExportError( "Cannot open root-file in archive : " + rootFile ); throw DeadlyExportError( "Cannot open root-file in archive : " + rootFile );
} }
mZipArchive->Close( fileStream );
} else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) { } else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES",file); ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES",file);
} else { } else {
@ -499,7 +167,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
} }
D3MFOpcPackage::~D3MFOpcPackage() { D3MFOpcPackage::~D3MFOpcPackage() {
// empty mZipArchive->Close(mRootStream);
} }
IOStream* D3MFOpcPackage::RootStream() const { IOStream* D3MFOpcPackage::RootStream() const {
@ -516,15 +184,6 @@ bool D3MFOpcPackage::validate() {
return mZipArchive->Exists( ModelRef.c_str() ); return mZipArchive->Exists( ModelRef.c_str() );
} }
bool D3MFOpcPackage::isZipArchive( IOSystem* pIOHandler, const std::string& rFile ) {
D3MF::D3MFZipArchive ar( pIOHandler, rFile );
if ( !ar.isOpen() ) {
return false;
}
return true;
}
std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) { std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) {
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream)); std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream));
std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get())); std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get()));

View File

@ -49,6 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/irrXMLWrapper.h> #include <assimp/irrXMLWrapper.h>
namespace Assimp { namespace Assimp {
class ZipArchiveIOSystem;
namespace D3MF { namespace D3MF {
using XmlReader = irr::io::IrrXMLReader ; using XmlReader = irr::io::IrrXMLReader ;
@ -60,22 +62,19 @@ struct OpcPackageRelationship {
std::string target; std::string target;
}; };
class D3MFZipArchive;
class D3MFOpcPackage { class D3MFOpcPackage {
public: public:
D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile ); D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile );
~D3MFOpcPackage(); ~D3MFOpcPackage();
IOStream* RootStream() const; IOStream* RootStream() const;
bool validate(); bool validate();
static bool isZipArchive( IOSystem* pIOHandler, const std::string& rFile );
protected: protected:
std::string ReadPackageRootRelationship(IOStream* stream); std::string ReadPackageRootRelationship(IOStream* stream);
private: private:
IOStream* mRootStream; IOStream* mRootStream;
std::unique_ptr<D3MFZipArchive> mZipArchive; std::unique_ptr<ZipArchiveIOSystem> mZipArchive;
}; };
} // Namespace D3MF } // Namespace D3MF

View File

@ -104,6 +104,7 @@ SET( PUBLIC_HEADERS
${HEADER_PATH}/Exporter.hpp ${HEADER_PATH}/Exporter.hpp
${HEADER_PATH}/DefaultIOStream.h ${HEADER_PATH}/DefaultIOStream.h
${HEADER_PATH}/DefaultIOSystem.h ${HEADER_PATH}/DefaultIOSystem.h
${HEADER_PATH}/ZipArchiveIOSystem.h
${HEADER_PATH}/SceneCombiner.h ${HEADER_PATH}/SceneCombiner.h
${HEADER_PATH}/fast_atof.h ${HEADER_PATH}/fast_atof.h
${HEADER_PATH}/qnan.h ${HEADER_PATH}/qnan.h
@ -172,6 +173,7 @@ SET( Common_SRCS
Common/DefaultProgressHandler.h Common/DefaultProgressHandler.h
Common/DefaultIOStream.cpp Common/DefaultIOStream.cpp
Common/DefaultIOSystem.cpp Common/DefaultIOSystem.cpp
Common/ZipArchiveIOSystem.cpp
Common/PolyTools.h Common/PolyTools.h
Common/Importer.cpp Common/Importer.cpp
Common/IFF.h Common/IFF.h
@ -688,8 +690,6 @@ ADD_ASSIMP_IMPORTER( Q3BSP
Q3BSP/Q3BSPFileParser.cpp Q3BSP/Q3BSPFileParser.cpp
Q3BSP/Q3BSPFileImporter.h Q3BSP/Q3BSPFileImporter.h
Q3BSP/Q3BSPFileImporter.cpp Q3BSP/Q3BSPFileImporter.cpp
Q3BSP/Q3BSPZipArchive.h
Q3BSP/Q3BSPZipArchive.cpp
) )
ADD_ASSIMP_IMPORTER( RAW ADD_ASSIMP_IMPORTER( RAW

View File

@ -580,15 +580,11 @@ struct Image
{ {
std::string mFileName; std::string mFileName;
/** If image file name is zero, embedded image data /** Embedded image data */
*/
std::vector<uint8_t> mImageData; std::vector<uint8_t> mImageData;
/** If image file name is zero, file format of /** File format hint ofembedded image data */
* embedded image data.
*/
std::string mEmbeddedFormat; std::string mEmbeddedFormat;
}; };
/** An animation channel. */ /** An animation channel. */

View File

@ -57,6 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/SkeletonMeshBuilder.h> #include <assimp/SkeletonMeshBuilder.h>
#include <assimp/CreateAnimMesh.h> #include <assimp/CreateAnimMesh.h>
#include <assimp/ZipArchiveIOSystem.h>
#include "time.h" #include "time.h"
#include "math.h" #include "math.h"
@ -73,12 +74,12 @@ static const aiImporterDesc desc = {
"", "",
"", "",
"http://collada.org", "http://collada.org",
aiImporterFlags_SupportTextFlavour, aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportCompressedFlavour,
1, 1,
3, 3,
1, 1,
5, 5,
"dae" "dae zae"
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -112,9 +113,20 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
// check file extension // check file extension
const std::string extension = GetExtension(pFile); const std::string extension = GetExtension(pFile);
if (extension == "dae") { bool readSig = checkSig && (pIOHandler != nullptr);
if (!readSig) {
if (extension == "dae" || extension == "zae") {
return true; return true;
} }
}
if (readSig) {
// Look for a DAE file inside, but don't extract it
ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
if (zip_archive.isOpen())
return !ColladaParser::ReadZaeManifest(zip_archive).empty();
}
// XML - too generic, we need to open the file and search for typical keywords // XML - too generic, we need to open the file and search for typical keywords
if (extension == "xml" || !extension.length() || checkSig) { if (extension == "xml" || !extension.length() || checkSig) {
@ -164,6 +176,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
// parse the input file // parse the input file
ColladaParser parser(pIOHandler, pFile); ColladaParser parser(pIOHandler, pFile);
if( !parser.mRootNode) { if( !parser.mRootNode) {
throw DeadlyImportError( "Collada: File came out empty. Something is wrong here."); throw DeadlyImportError( "Collada: File came out empty. Something is wrong here.");
} }
@ -185,6 +198,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
FillMaterials(parser, pScene); FillMaterials(parser, pScene);
// Apply unit-size scale calculation // Apply unit-size scale calculation
pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0, pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0,
0, parser.mUnitSize, 0, 0, 0, parser.mUnitSize, 0, 0,
0, 0, parser.mUnitSize, 0, 0, 0, parser.mUnitSize, 0,
@ -222,6 +236,9 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
// store all materials // store all materials
StoreSceneMaterials(pScene); StoreSceneMaterials(pScene);
// store all textures
StoreSceneTextures(pScene);
// store all lights // store all lights
StoreSceneLights(pScene); StoreSceneLights(pScene);
@ -315,6 +332,7 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Resolve UV channels // Resolve UV channels
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler, void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
const Collada::SemanticMappingTable& table) { const Collada::SemanticMappingTable& table) {
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel); std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
if (it != table.mMap.end()) { if (it != table.mMap.end()) {
@ -354,7 +372,8 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
if (out->mType == aiLightSource_AMBIENT) { if (out->mType == aiLightSource_AMBIENT) {
out->mColorDiffuse = out->mColorSpecular = aiColor3D(0, 0, 0); out->mColorDiffuse = out->mColorSpecular = aiColor3D(0, 0, 0);
out->mColorAmbient = srcLight->mColor*srcLight->mIntensity; out->mColorAmbient = srcLight->mColor*srcLight->mIntensity;
} else { }
else {
// collada doesn't differentiate between these color types // collada doesn't differentiate between these color types
out->mColorDiffuse = out->mColorSpecular = srcLight->mColor*srcLight->mIntensity; out->mColorDiffuse = out->mColorSpecular = srcLight->mColor*srcLight->mIntensity;
out->mColorAmbient = aiColor3D(0, 0, 0); out->mColorAmbient = aiColor3D(0, 0, 0);
@ -372,12 +391,14 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
// epsilon chosen to be 0.1 // epsilon chosen to be 0.1
out->mAngleOuterCone = std::acos(std::pow(0.1f, 1.f / srcLight->mFalloffExponent)) + out->mAngleOuterCone = std::acos(std::pow(0.1f, 1.f / srcLight->mFalloffExponent)) +
out->mAngleInnerCone; out->mAngleInnerCone;
} else { }
else {
out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle); out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle);
if (out->mAngleOuterCone < out->mAngleInnerCone) if (out->mAngleOuterCone < out->mAngleInnerCone)
std::swap(out->mAngleInnerCone, out->mAngleOuterCone); std::swap(out->mAngleInnerCone, out->mAngleOuterCone);
} }
} else { }
else {
out->mAngleOuterCone = AI_DEG_TO_RAD(srcLight->mOuterAngle); out->mAngleOuterCone = AI_DEG_TO_RAD(srcLight->mOuterAngle);
} }
} }
@ -428,6 +449,7 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col
out->mAspect = std::tan(AI_DEG_TO_RAD(srcCamera->mHorFov)) / out->mAspect = std::tan(AI_DEG_TO_RAD(srcCamera->mHorFov)) /
std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov)); std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov));
} }
} else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) { } else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) {
out->mHorizontalFOV = 2.0f * AI_RAD_TO_DEG(std::atan(srcCamera->mAspect * out->mHorizontalFOV = 2.0f * AI_RAD_TO_DEG(std::atan(srcCamera->mAspect *
std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov) * 0.5f))); std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov) * 0.5f)));
@ -466,11 +488,13 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
} }
} }
if( nullptr == srcMesh) { if( nullptr == srcMesh) {
ASSIMP_LOG_WARN_F( "Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping." ); ASSIMP_LOG_WARN_F( "Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping." );
continue; continue;
} }
} else { }
else {
// ID found in the mesh library -> direct reference to an unskinned mesh // ID found in the mesh library -> direct reference to an unskinned mesh
srcMesh = srcMeshIt->second; srcMesh = srcMeshIt->second;
} }
@ -491,7 +515,8 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
if (meshMatIt != mid.mMaterials.end()) { if (meshMatIt != mid.mMaterials.end()) {
table = &meshMatIt->second; table = &meshMatIt->second;
meshMaterial = table->mMatName; meshMaterial = table->mMatName;
} else { }
else {
ASSIMP_LOG_WARN_F("Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <", ASSIMP_LOG_WARN_F("Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <",
mid.mMeshOrController, ">."); mid.mMeshOrController, ">.");
if (!mid.mMaterials.empty()) { if (!mid.mMaterials.empty()) {
@ -527,7 +552,8 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
std::map<ColladaMeshIndex, size_t>::const_iterator dstMeshIt = mMeshIndexByID.find(index); std::map<ColladaMeshIndex, size_t>::const_iterator dstMeshIt = mMeshIndexByID.find(index);
if (dstMeshIt != mMeshIndexByID.end()) { if (dstMeshIt != mMeshIndexByID.end()) {
newMeshRefs.push_back(dstMeshIt->second); newMeshRefs.push_back(dstMeshIt->second);
} else { }
else {
// else we have to add the mesh to the collection and store its newly assigned index at the node // else we have to add the mesh to the collection and store its newly assigned index at the node
aiMesh* dstMesh = CreateMesh(pParser, srcMesh, submesh, srcController, vertexStart, faceStart); aiMesh* dstMesh = CreateMesh(pParser, srcMesh, submesh, srcController, vertexStart, faceStart);
@ -766,6 +792,7 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
IndexPairVector::const_iterator iit = weightStartPerVertex[orgIndex]; IndexPairVector::const_iterator iit = weightStartPerVertex[orgIndex];
size_t pairCount = pSrcController->mWeightCounts[orgIndex]; size_t pairCount = pSrcController->mWeightCounts[orgIndex];
for( size_t b = 0; b < pairCount; ++b, ++iit) { for( size_t b = 0; b < pairCount; ++b, ++iit) {
const size_t jointIndex = iit->first; const size_t jointIndex = iit->first;
const size_t vertexIndex = iit->second; const size_t vertexIndex = iit->second;
@ -1048,7 +1075,8 @@ void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, floa
{ {
values[i].mKeys.push_back(k); values[i].mKeys.push_back(k);
return; return;
} else if (time > values[i].mTime && time < values[i+1].mTime) }
else if (time > values[i].mTime && time < values[i + 1].mTime)
{ {
MorphTimeValues val; MorphTimeValues val;
val.mTime = time; val.mTime = time;
@ -1150,7 +1178,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
entry.mSubElement = 2; entry.mSubElement = 2;
else else
ASSIMP_LOG_WARN_F("Unknown anim subelement <", subElement, ">. Ignoring"); ASSIMP_LOG_WARN_F("Unknown anim subelement <", subElement, ">. Ignoring");
} else { }
else {
// no subelement following, transformId is remaining string // no subelement following, transformId is remaining string
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1); entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1);
} }
@ -1208,7 +1237,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
{ {
entry.mTargetId = entry.mTransformId; entry.mTargetId = entry.mTransformId;
entry.mTransformId = ""; entry.mTransformId = "";
} else }
else
continue; continue;
} }
@ -1377,7 +1407,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
} }
anims.push_back(dstAnim); anims.push_back(dstAnim);
} else }
else
{ {
ASSIMP_LOG_WARN("Collada loader: found empty animation channel, ignored. Please check your exporter."); ASSIMP_LOG_WARN("Collada loader: found empty animation channel, ignored. Please check your exporter.");
} }
@ -1615,7 +1646,8 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce
effect.mTransparent.a = 1.f; effect.mTransparent.a = 1.f;
mat.AddProperty(&effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT); mat.AddProperty(&effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
} else { }
else {
effect.mTransparency *= effect.mTransparent.a; effect.mTransparency *= effect.mTransparent.a;
} }
@ -1735,14 +1767,19 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars
} }
// if this is an embedded texture image setup an aiTexture for it // if this is an embedded texture image setup an aiTexture for it
if (imIt->second.mFileName.empty()) if (!imIt->second.mImageData.empty())
{ {
if (imIt->second.mImageData.empty()) {
throw DeadlyImportError("Collada: Invalid texture, no data or file reference given");
}
aiTexture* tex = new aiTexture(); aiTexture* tex = new aiTexture();
// Store embedded texture name reference
tex->mFilename.Set(imIt->second.mFileName.c_str());
result.Set(imIt->second.mFileName);
// TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
// result.data[0] = '*';
// result.length = 1 + ASSIMP_itoa10(result.data + 1, static_cast<unsigned int>(MAXLEN - 1), static_cast<int32_t>(mTextures.size()));
// setup format hint // setup format hint
if (imIt->second.mEmbeddedFormat.length() > 3) { if (imIt->second.mEmbeddedFormat.length() > 3) {
ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters"); ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters");
@ -1755,20 +1792,15 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars
tex->pcData = (aiTexel*)new char[tex->mWidth]; tex->pcData = (aiTexel*)new char[tex->mWidth];
memcpy(tex->pcData, &imIt->second.mImageData[0], tex->mWidth); memcpy(tex->pcData, &imIt->second.mImageData[0], tex->mWidth);
// TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
// In FBX files textures are now stored internally by Assimp with their filename included
// Now Assimp can lookup through the loaded textures after all data is processed
// We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
// This may occur on this case too, it has to be studied
// setup texture reference string
result.data[0] = '*';
result.length = 1 + ASSIMP_itoa10(result.data+1,static_cast<unsigned int>(MAXLEN-1),static_cast<int32_t>(mTextures.size()));
// and add this texture to the list // and add this texture to the list
mTextures.push_back(tex); mTextures.push_back(tex);
} }
else else
{ {
if (imIt->second.mFileName.empty()) {
throw DeadlyImportError("Collada: Invalid texture, no data or file reference given");
}
result.Set(imIt->second.mFileName); result.Set(imIt->second.mFileName);
ConvertPath(result); ConvertPath(result);
} }
@ -1813,7 +1845,8 @@ void ColladaLoader::ConvertPath (aiString& ss)
size_t nbr = strtoul16(mychar); size_t nbr = strtoul16(mychar);
it += 3; it += 3;
*out++ = (char)(nbr & 0xFF); *out++ = (char)(nbr & 0xFF);
} else }
else
{ {
*out++ = *it++; *out++ = *it++;
} }
@ -1901,7 +1934,8 @@ std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode)
{ {
if (!pNode->mName.empty()) { if (!pNode->mName.empty()) {
return pNode->mName; return pNode->mName;
} else { }
else {
return format() << "$ColladaAutoName$_" << mNodeNameCounter++; return format() << "$ColladaAutoName$_" << mNodeNameCounter++;
} }
} }

View File

@ -94,20 +94,20 @@ public:
public: public:
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */ * See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override;
protected: protected:
/** Return importer meta information. /** Return importer meta information.
* See #BaseImporter::GetInfo for the details * See #BaseImporter::GetInfo for the details
*/ */
const aiImporterDesc* GetInfo () const; const aiImporterDesc* GetInfo () const override;
void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp) override;
/** Imports the given file into the given scene structure. /** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details * See BaseImporter::InternReadFile() for details
*/ */
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) override;
/** Recursively constructs a scene node for the given parser node and returns it. */ /** Recursively constructs a scene node for the given parser node and returns it. */
aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode); aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode);

View File

@ -57,6 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/light.h> #include <assimp/light.h>
#include <assimp/TinyFormatter.h> #include <assimp/TinyFormatter.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <memory> #include <memory>
@ -90,21 +91,49 @@ ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
throw DeadlyImportError("IOSystem is NULL."); throw DeadlyImportError("IOSystem is NULL.");
} }
// open the file std::unique_ptr<IOStream> daefile;
std::unique_ptr<IOStream> file( pIOHandler->Open(pFile ) ); std::unique_ptr<ZipArchiveIOSystem> zip_archive;
if (file.get() == nullptr) {
throw DeadlyImportError( "Failed to open file " + pFile + "." ); // Determine type
std::string extension = BaseImporter::GetExtension(pFile);
if (extension != "dae") {
zip_archive.reset(new ZipArchiveIOSystem(pIOHandler, pFile));
}
if (zip_archive && zip_archive->isOpen()) {
std::string dae_filename = ReadZaeManifest(*zip_archive);
if (dae_filename.empty()) {
ThrowException(std::string("Invalid ZAE"));
}
daefile.reset(zip_archive->Open(dae_filename.c_str()));
if (daefile == nullptr) {
ThrowException(std::string("Invalid ZAE manifest: '") + std::string(dae_filename) + std::string("' is missing"));
}
}
else {
// attempt to open the file directly
daefile.reset(pIOHandler->Open(pFile));
if (daefile.get() == nullptr) {
throw DeadlyImportError("Failed to open file '" + pFile + "'.");
}
} }
// generate a XML reader for it // generate a XML reader for it
std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(file.get())); std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(daefile.get()));
mReader = irr::io::createIrrXMLReader(mIOWrapper.get()); mReader = irr::io::createIrrXMLReader(mIOWrapper.get());
if (!mReader) { if (!mReader) {
ThrowException("Collada: Unable to open file."); ThrowException("Unable to read file, malformed XML");
} }
// start reading // start reading
ReadContents(); ReadContents();
// read embedded textures
if (zip_archive && zip_archive->isOpen()) {
ReadEmbeddedTextures(*zip_archive);
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -118,6 +147,49 @@ ColladaParser::~ColladaParser()
delete it->second; delete it->second;
} }
// ------------------------------------------------------------------------------------------------
// Read a ZAE manifest and return the filename to attempt to open
std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) {
// Open the manifest
std::unique_ptr<IOStream> manifestfile(zip_archive.Open("manifest.xml"));
if (manifestfile == nullptr)
{
// No manifest, hope there is only one .DAE inside
std::vector<std::string> file_list;
zip_archive.getFileListExtension(file_list, "dae");
if (file_list.empty())
return std::string();
return file_list.front();
}
std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(manifestfile.get()));
std::unique_ptr<irr::io::IrrXMLReader> manifest_reader(irr::io::createIrrXMLReader(mIOWrapper.get()));
while (manifest_reader->read())
{
// find the manifest "dae_root" element
if (manifest_reader->getNodeType() == irr::io::EXN_ELEMENT)
{
if (::strcmp(manifest_reader->getNodeName(), "dae_root") == 0)
{
if (!manifest_reader->read())
return std::string();
if (manifest_reader->getNodeType() != irr::io::EXN_TEXT && manifest_reader->getNodeType() != irr::io::EXN_CDATA)
return std::string();
const char* filepath = manifest_reader->getNodeData();
if (filepath == nullptr)
return std::string();
return std::string(filepath);
}
}
}
return std::string();
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Read bool from text contents of current element // Read bool from text contents of current element
bool ColladaParser::ReadBoolFromTextContent() bool ColladaParser::ReadBoolFromTextContent()
@ -165,12 +237,14 @@ void ColladaParser::ReadContents()
} }
ReadStructure(); ReadStructure();
} else }
else
{ {
ASSIMP_LOG_DEBUG_F("Ignoring global element <", mReader->getNodeName(), ">."); ASSIMP_LOG_DEBUG_F("Ignoring global element <", mReader->getNodeName(), ">.");
SkipElement(); SkipElement();
} }
} else }
else
{ {
// skip everything else silently // skip everything else silently
} }
@ -506,7 +580,8 @@ void ColladaParser::ReadAnimationLibrary()
{ {
// delegate the reading. Depending on the inner elements it will be a container or a anim channel // delegate the reading. Depending on the inner elements it will be a container or a anim channel
ReadAnimation(&mAnims); ReadAnimation(&mAnims);
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -722,7 +797,8 @@ void ColladaParser::ReadControllerLibrary()
// read on from there // read on from there
ReadController(mControllerLibrary[id]); ReadController(mControllerLibrary[id]);
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -816,7 +892,8 @@ void ColladaParser::ReadController( Collada::Controller& pController)
pController.mMorphWeight = source + 1; pController.mMorphWeight = source + 1;
} }
} }
} else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { }
else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
if (strcmp(mReader->getNodeName(), "targets") == 0) if (strcmp(mReader->getNodeName(), "targets") == 0)
break; break;
else else
@ -1008,7 +1085,8 @@ void ColladaParser::ReadImageLibrary()
// read on from there // read on from there
ReadImage(mImageLibrary[id]); ReadImage(mImageLibrary[id]);
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -1158,7 +1236,8 @@ void ColladaParser::ReadMaterialLibrary()
} }
ReadMaterial(mMaterialLibrary[id]); ReadMaterial(mMaterialLibrary[id]);
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -1193,7 +1272,8 @@ void ColladaParser::ReadLightLibrary()
// create an entry and store it in the library under its ID // create an entry and store it in the library under its ID
ReadLight(mLightLibrary[id] = Light()); ReadLight(mLightLibrary[id] = Light());
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -1232,7 +1312,8 @@ void ColladaParser::ReadCameraLibrary()
ReadCamera(cam); ReadCamera(cam);
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -1268,7 +1349,8 @@ void ColladaParser::ReadMaterial( Collada::Material& pMaterial)
pMaterial.mEffect = url + 1; pMaterial.mEffect = url + 1;
SkipElement(); SkipElement();
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -1439,7 +1521,8 @@ void ColladaParser::ReadEffectLibrary()
mEffectLibrary[id] = Effect(); mEffectLibrary[id] = Effect();
// read on from there // read on from there
ReadEffect(mEffectLibrary[id]); ReadEffect(mEffectLibrary[id]);
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -1779,7 +1862,8 @@ void ColladaParser::ReadEffectFloat( ai_real& pFloat)
SkipSpacesAndLineEnd(&content); SkipSpacesAndLineEnd(&content);
TestClosing("float"); TestClosing("float");
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -1834,7 +1918,8 @@ void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam)
pParam.mType = Param_Sampler; pParam.mType = Param_Sampler;
pParam.mReference = url; pParam.mReference = url;
SkipElement("sampler2D"); SkipElement("sampler2D");
} else }
else
{ {
// ignore unknown element // ignore unknown element
SkipElement(); SkipElement();
@ -1879,7 +1964,8 @@ void ColladaParser::ReadGeometryLibrary()
// read on from there // read on from there
ReadGeometry(mesh); ReadGeometry(mesh);
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -1910,7 +1996,8 @@ void ColladaParser::ReadGeometry( Collada::Mesh* pMesh)
{ {
// read on from there // read on from there
ReadMesh(pMesh); ReadMesh(pMesh);
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -1952,7 +2039,8 @@ void ColladaParser::ReadMesh( Mesh* pMesh)
{ {
// read per-index mesh data and faces setup // read per-index mesh data and faces setup
ReadIndexData(pMesh); ReadIndexData(pMesh);
} else }
else
{ {
// ignore the restf // ignore the restf
SkipElement(); SkipElement();
@ -1968,7 +2056,8 @@ void ColladaParser::ReadMesh( Mesh* pMesh)
{ {
// end of <mesh> element - we're done here // end of <mesh> element - we're done here
break; break;
} else }
else
{ {
// everything else should be punished // everything else should be punished
ThrowException("Expected end of <mesh> element."); ThrowException("Expected end of <mesh> element.");
@ -1999,7 +2088,8 @@ void ColladaParser::ReadSource()
else if (IsElement("accessor")) else if (IsElement("accessor"))
{ {
ReadAccessor(sourceID); ReadAccessor(sourceID);
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -2015,7 +2105,8 @@ void ColladaParser::ReadSource()
else if (strcmp(mReader->getNodeName(), "technique_common") == 0) else if (strcmp(mReader->getNodeName(), "technique_common") == 0)
{ {
// end of another meaningless element - read over it // end of another meaningless element - read over it
} else }
else
{ {
// everything else should be punished // everything else should be punished
ThrowException("Expected end of <source> element."); ThrowException("Expected end of <source> element.");
@ -2064,7 +2155,8 @@ void ColladaParser::ReadDataArray()
SkipSpacesAndLineEnd(&content); SkipSpacesAndLineEnd(&content);
} }
} else }
else
{ {
data.mValues.reserve(count); data.mValues.reserve(count);
@ -2176,7 +2268,8 @@ void ColladaParser::ReadAccessor( const std::string& pID)
// skip remaining stuff of this element, if any // skip remaining stuff of this element, if any
SkipElement(); SkipElement();
} else }
else
{ {
ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <accessor>"); ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <accessor>");
} }
@ -2206,7 +2299,8 @@ void ColladaParser::ReadVertexData( Mesh* pMesh)
if (IsElement("input")) if (IsElement("input"))
{ {
ReadInputChannel(pMesh->mPerVertexData); ReadInputChannel(pMesh->mPerVertexData);
} else }
else
{ {
ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <vertices>"); ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <vertices>");
} }
@ -2304,9 +2398,11 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
else if (IsElement("extra")) else if (IsElement("extra"))
{ {
SkipElement("extra"); SkipElement("extra");
} else if ( IsElement("ph")) { }
else if (IsElement("ph")) {
SkipElement("ph"); SkipElement("ph");
} else { }
else {
ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <" << elementName << ">"); ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <" << elementName << ">");
} }
} }
@ -2436,10 +2532,12 @@ size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pP
// HACK: We just fix this number since SketchUp 15.3.331 writes the wrong 'count' for 'lines' // HACK: We just fix this number since SketchUp 15.3.331 writes the wrong 'count' for 'lines'
ReportWarning("Expected different index count in <p> element, %zu instead of %zu.", indices.size(), expectedPointCount * numOffsets); ReportWarning("Expected different index count in <p> element, %zu instead of %zu.", indices.size(), expectedPointCount * numOffsets);
pNumPrimitives = (indices.size() / numOffsets) / 2; pNumPrimitives = (indices.size() / numOffsets) / 2;
} else }
else
ThrowException("Expected different index count in <p> element."); ThrowException("Expected different index count in <p> element.");
} else if( expectedPointCount == 0 && (indices.size() % numOffsets) != 0) }
else if (expectedPointCount == 0 && (indices.size() % numOffsets) != 0)
ThrowException("Expected different index count in <p> element."); ThrowException("Expected different index count in <p> element.");
// find the data for all sources // find the data for all sources
@ -2660,7 +2758,8 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
pMesh->mTexCoords[pInput.mIndex].push_back(aiVector3D(obj[0], obj[1], obj[2])); pMesh->mTexCoords[pInput.mIndex].push_back(aiVector3D(obj[0], obj[1], obj[2]));
if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) /* hack ... consider cleaner solution */ if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) /* hack ... consider cleaner solution */
pMesh->mNumUVComponents[pInput.mIndex] = 3; pMesh->mNumUVComponents[pInput.mIndex] = 3;
} else }
else
{ {
ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping."); ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping.");
} }
@ -2680,7 +2779,8 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
result[static_cast<unsigned int>(i)] = obj[pInput.mResolved->mSubOffset[i]]; result[static_cast<unsigned int>(i)] = obj[pInput.mResolved->mSubOffset[i]];
} }
pMesh->mColors[pInput.mIndex].push_back(result); pMesh->mColors[pInput.mIndex].push_back(result);
} else }
else
{ {
ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping."); ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping.");
} }
@ -2723,7 +2823,8 @@ void ColladaParser::ReadSceneLibrary()
mNodeLibrary[node->mID] = node; mNodeLibrary[node->mID] = node;
ReadSceneNode(node); ReadSceneNode(node);
} else }
else
{ {
// ignore the rest // ignore the rest
SkipElement(); SkipElement();
@ -2955,6 +3056,26 @@ void ColladaParser::ReadMaterialVertexInputBinding( Collada::SemanticMappingTabl
} }
} }
void Assimp::ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem& zip_archive)
{
// Attempt to load any undefined Collada::Image in ImageLibrary
for (ImageLibrary::iterator it = mImageLibrary.begin(); it != mImageLibrary.end(); ++it) {
Collada::Image &image = (*it).second;
if (image.mImageData.empty()) {
std::unique_ptr<IOStream> image_file(zip_archive.Open(image.mFileName.c_str()));
if (image_file) {
image.mImageData.resize(image_file->FileSize());
image_file->Read(image.mImageData.data(), image_file->FileSize(), 1);
image.mEmbeddedFormat = BaseImporter::GetExtension(image.mFileName);
if (image.mEmbeddedFormat == "jpeg") {
image.mEmbeddedFormat = "jpg";
}
}
}
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads a mesh reference in a node and adds it to the node's mesh list // Reads a mesh reference in a node and adds it to the node's mesh list
void ColladaParser::ReadNodeGeometry(Node* pNode) void ColladaParser::ReadNodeGeometry(Node* pNode)
@ -3036,7 +3157,8 @@ void ColladaParser::ReadScene()
if (sit == mNodeLibrary.end()) if (sit == mNodeLibrary.end())
ThrowException("Unable to resolve visual_scene reference \"" + std::string(url) + "\" in <instance_visual_scene> element."); ThrowException("Unable to resolve visual_scene reference \"" + std::string(url) + "\" in <instance_visual_scene> element.");
mRootNode = sit->second; mRootNode = sit->second;
} else { }
else {
SkipElement(); SkipElement();
} }
} }

View File

@ -54,6 +54,7 @@
namespace Assimp namespace Assimp
{ {
class ZipArchiveIOSystem;
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
/** Parser helper class for the Collada loader. /** Parser helper class for the Collada loader.
@ -75,6 +76,9 @@ namespace Assimp
/** Destructor */ /** Destructor */
~ColladaParser(); ~ColladaParser();
/** Attempts to read the ZAE manifest and returns the DAE to open */
static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive);
/** Reads the contents of the file */ /** Reads the contents of the file */
void ReadContents(); void ReadContents();
@ -235,6 +239,9 @@ namespace Assimp
// Processes bind_vertex_input and bind elements // Processes bind_vertex_input and bind elements
void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl); void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl);
/** Reads embedded textures from a ZAE archive*/
void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
protected: protected:
/** Aborts the file reading with an exception */ /** Aborts the file reading with an exception */
AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX;

View File

@ -0,0 +1,539 @@
/*
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.
----------------------------------------------------------------------
*/
/** @file ZipArchiveIOSystem.cpp
* @brief Zip File I/O implementation for #Importer
*/
#include <assimp/ZipArchiveIOSystem.h>
#include <assimp/BaseImporter.h>
#include <assimp/ai_assert.h>
#include <map>
#include <memory>
#ifdef ASSIMP_USE_HUNTER
# include <minizip/unzip.h>
#else
# include <unzip.h>
#endif
namespace Assimp {
// ----------------------------------------------------------------
// Wraps an existing Assimp::IOSystem for unzip
class IOSystem2Unzip {
public:
static voidpf open(voidpf opaque, const char* filename, int mode);
static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size);
static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size);
static long tell(voidpf opaque, voidpf stream);
static long seek(voidpf opaque, voidpf stream, uLong offset, int origin);
static int close(voidpf opaque, voidpf stream);
static int testerror(voidpf opaque, voidpf stream);
static zlib_filefunc_def get(IOSystem* pIOHandler);
};
voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
IOSystem* io_system = reinterpret_cast<IOSystem*>(opaque);
const char* mode_fopen = nullptr;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) {
mode_fopen = "rb";
}
else {
if (mode & ZLIB_FILEFUNC_MODE_EXISTING) {
mode_fopen = "r+b";
}
else {
if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
mode_fopen = "wb";
}
}
}
return (voidpf)io_system->Open(filename, mode_fopen);
}
uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) {
IOStream* io_stream = (IOStream*)stream;
return static_cast<uLong>(io_stream->Read(buf, 1, size));
}
uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) {
IOStream* io_stream = (IOStream*)stream;
return static_cast<uLong>(io_stream->Write(buf, 1, size));
}
long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) {
IOStream* io_stream = (IOStream*)stream;
return static_cast<long>(io_stream->Tell());
}
long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) {
IOStream* io_stream = (IOStream*)stream;
aiOrigin assimp_origin;
switch (origin) {
default:
case ZLIB_FILEFUNC_SEEK_CUR:
assimp_origin = aiOrigin_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END:
assimp_origin = aiOrigin_END;
break;
case ZLIB_FILEFUNC_SEEK_SET:
assimp_origin = aiOrigin_SET;
break;
}
return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1);
}
int IOSystem2Unzip::close(voidpf opaque, voidpf stream) {
IOSystem* io_system = (IOSystem*)opaque;
IOStream* io_stream = (IOStream*)stream;
io_system->Close(io_stream);
return 0;
}
int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) {
return 0;
}
zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
zlib_filefunc_def mapping;
#ifdef ASSIMP_USE_HUNTER
mapping.zopen_file = (open_file_func)open;
mapping.zread_file = (read_file_func)read;
mapping.zwrite_file = (write_file_func)write;
mapping.ztell_file = (tell_file_func)tell;
mapping.zseek_file = (seek_file_func)seek;
mapping.zclose_file = (close_file_func)close;
mapping.zerror_file = (error_file_func)testerror;
#else
mapping.zopen_file = open;
mapping.zread_file = read;
mapping.zwrite_file = write;
mapping.ztell_file = tell;
mapping.zseek_file = seek;
mapping.zclose_file = close;
mapping.zerror_file = testerror;
#endif
mapping.opaque = reinterpret_cast<voidpf>(pIOHandler);
return mapping;
}
// ----------------------------------------------------------------
// A read-only file inside a ZIP
class ZipFile : public IOStream {
friend class ZipFileInfo;
explicit ZipFile(size_t size);
public:
virtual ~ZipFile();
// IOStream interface
size_t Read(void* pvBuffer, size_t pSize, size_t pCount) override;
size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) override { return 0; }
size_t FileSize() const override;
aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override;
size_t Tell() const override;
void Flush() override {}
private:
size_t m_Size = 0;
size_t m_SeekPtr = 0;
std::unique_ptr<uint8_t[]> m_Buffer;
};
// ----------------------------------------------------------------
// Info about a read-only file inside a ZIP
class ZipFileInfo
{
public:
explicit ZipFileInfo(unzFile zip_handle, size_t size);
// Allocate and Extract data from the ZIP
ZipFile * Extract(unzFile zip_handle) const;
private:
size_t m_Size = 0;
unz_file_pos_s m_ZipFilePos;
};
ZipFileInfo::ZipFileInfo(unzFile zip_handle, size_t size)
: m_Size(size) {
ai_assert(m_Size != 0);
// Workaround for MSVC 2013 - C2797
m_ZipFilePos.num_of_file = 0;
m_ZipFilePos.pos_in_zip_directory = 0;
unzGetFilePos(zip_handle, &(m_ZipFilePos));
}
ZipFile * ZipFileInfo::Extract(unzFile zip_handle) const {
// Find in the ZIP. This cannot fail
unz_file_pos_s *filepos = const_cast<unz_file_pos_s*>(&(m_ZipFilePos));
if (unzGoToFilePos(zip_handle, filepos) != UNZ_OK)
return nullptr;
if (unzOpenCurrentFile(zip_handle) != UNZ_OK)
return nullptr;
ZipFile *zip_file = new ZipFile(m_Size);
if (unzReadCurrentFile(zip_handle, zip_file->m_Buffer.get(), static_cast<unsigned int>(m_Size)) != static_cast<int>(m_Size))
{
// Failed, release the memory
delete zip_file;
zip_file = nullptr;
}
ai_assert(unzCloseCurrentFile(zip_handle) == UNZ_OK);
return zip_file;
}
ZipFile::ZipFile(size_t size)
: m_Size(size) {
ai_assert(m_Size != 0);
m_Buffer = std::unique_ptr<uint8_t[]>(new uint8_t[m_Size]);
}
ZipFile::~ZipFile() {
}
size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) {
// Should be impossible
ai_assert(m_Buffer != nullptr);
ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
// Clip down to file size
size_t byteSize = pSize * pCount;
if ((byteSize + m_SeekPtr) > m_Size)
{
pCount = (m_Size - m_SeekPtr) / pSize;
byteSize = pSize * pCount;
if (byteSize == 0)
return 0;
}
std::memcpy(pvBuffer, m_Buffer.get() + m_SeekPtr, byteSize);
m_SeekPtr += byteSize;
return pCount;
}
size_t ZipFile::FileSize() const {
return m_Size;
}
aiReturn ZipFile::Seek(size_t pOffset, aiOrigin pOrigin) {
switch (pOrigin)
{
case aiOrigin_SET: {
if (pOffset > m_Size) return aiReturn_FAILURE;
m_SeekPtr = pOffset;
return aiReturn_SUCCESS;
}
case aiOrigin_CUR: {
if ((pOffset + m_SeekPtr) > m_Size) return aiReturn_FAILURE;
m_SeekPtr += pOffset;
return aiReturn_SUCCESS;
}
case aiOrigin_END: {
if (pOffset > m_Size) return aiReturn_FAILURE;
m_SeekPtr = m_Size - pOffset;
return aiReturn_SUCCESS;
}
default:;
}
return aiReturn_FAILURE;
}
size_t ZipFile::Tell() const {
return m_SeekPtr;
}
// ----------------------------------------------------------------
// pImpl of the Zip Archive IO
class ZipArchiveIOSystem::Implement {
public:
static const unsigned int FileNameSize = 256;
Implement(IOSystem* pIOHandler, const char* pFilename, const char* pMode);
~Implement();
bool isOpen() const;
void getFileList(std::vector<std::string>& rFileList);
void getFileListExtension(std::vector<std::string>& rFileList, const std::string& extension);
bool Exists(std::string& filename);
IOStream* OpenFile(std::string& filename);
static void SimplifyFilename(std::string& filename);
private:
void MapArchive();
private:
typedef std::map<std::string, ZipFileInfo> ZipFileInfoMap;
unzFile m_ZipFileHandle = nullptr;
ZipFileInfoMap m_ArchiveMap;
};
ZipArchiveIOSystem::Implement::Implement(IOSystem* pIOHandler, const char* pFilename, const char* pMode) {
ai_assert(strcmp(pMode, "r") == 0);
ai_assert(pFilename != nullptr);
if (pFilename[0] == 0)
return;
zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
m_ZipFileHandle = unzOpen2(pFilename, &mapping);
}
ZipArchiveIOSystem::Implement::~Implement() {
m_ArchiveMap.clear();
if (m_ZipFileHandle != nullptr) {
unzClose(m_ZipFileHandle);
m_ZipFileHandle = nullptr;
}
}
void ZipArchiveIOSystem::Implement::MapArchive() {
if (m_ZipFileHandle == nullptr)
return;
if (!m_ArchiveMap.empty())
return;
// At first ensure file is already open
if (unzGoToFirstFile(m_ZipFileHandle) != UNZ_OK)
return;
// Loop over all files
do {
char filename[FileNameSize];
unz_file_info fileInfo;
if (unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, nullptr, 0, nullptr, 0) == UNZ_OK) {
if (fileInfo.uncompressed_size != 0) {
std::string filename_string(filename, fileInfo.size_filename);
SimplifyFilename(filename_string);
m_ArchiveMap.emplace(filename_string, ZipFileInfo(m_ZipFileHandle, fileInfo.uncompressed_size));
}
}
} while (unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE);
}
bool ZipArchiveIOSystem::Implement::isOpen() const {
return (m_ZipFileHandle != nullptr);
}
void ZipArchiveIOSystem::Implement::getFileList(std::vector<std::string>& rFileList) {
MapArchive();
rFileList.clear();
for (const auto &file : m_ArchiveMap) {
rFileList.push_back(file.first);
}
}
void ZipArchiveIOSystem::Implement::getFileListExtension(std::vector<std::string>& rFileList, const std::string& extension) {
MapArchive();
rFileList.clear();
for (const auto &file : m_ArchiveMap) {
if (extension == BaseImporter::GetExtension(file.first))
rFileList.push_back(file.first);
}
}
bool ZipArchiveIOSystem::Implement::Exists(std::string& filename) {
MapArchive();
ZipFileInfoMap::const_iterator it = m_ArchiveMap.find(filename);
return (it != m_ArchiveMap.end());
}
IOStream * ZipArchiveIOSystem::Implement::OpenFile(std::string& filename) {
MapArchive();
SimplifyFilename(filename);
// Find in the map
ZipFileInfoMap::const_iterator zip_it = m_ArchiveMap.find(filename);
if (zip_it == m_ArchiveMap.cend())
return nullptr;
const ZipFileInfo &zip_file = (*zip_it).second;
return zip_file.Extract(m_ZipFileHandle);
}
inline void ReplaceAll(std::string& data, const std::string& before, const std::string& after) {
size_t pos = data.find(before);
while (pos != std::string::npos)
{
data.replace(pos, before.size(), after);
pos = data.find(before, pos + after.size());
}
}
inline void ReplaceAllChar(std::string& data, const char before, const char after) {
size_t pos = data.find(before);
while (pos != std::string::npos)
{
data[pos] = after;
pos = data.find(before, pos + 1);
}
}
void ZipArchiveIOSystem::Implement::SimplifyFilename(std::string& filename)
{
ReplaceAllChar(filename, '\\', '/');
// Remove all . and / from the beginning of the path
size_t pos = filename.find_first_not_of("./");
if (pos != 0)
filename.erase(0, pos);
// Simplify "my/folder/../file.png" constructions, if any
static const std::string relative("/../");
const size_t relsize = relative.size() - 1;
pos = filename.find(relative);
while (pos != std::string::npos)
{
// Previous slash
size_t prevpos = filename.rfind('/', pos - 1);
if (prevpos == pos)
filename.erase(0, pos + relative.size());
else
filename.erase(prevpos, pos + relsize - prevpos);
pos = filename.find(relative);
}
}
ZipArchiveIOSystem::ZipArchiveIOSystem(IOSystem* pIOHandler, const char* pFilename, const char* pMode)
: pImpl(new Implement(pIOHandler, pFilename, pMode)) {
}
// ----------------------------------------------------------------
// The ZipArchiveIO
ZipArchiveIOSystem::ZipArchiveIOSystem(IOSystem* pIOHandler, const std::string& rFilename, const char* pMode)
: pImpl(new Implement(pIOHandler, rFilename.c_str(), pMode))
{
}
ZipArchiveIOSystem::~ZipArchiveIOSystem() {
delete pImpl;
}
bool ZipArchiveIOSystem::Exists(const char* pFilename) const {
ai_assert(pFilename != nullptr);
if (pFilename == nullptr) {
return false;
}
std::string filename(pFilename);
return pImpl->Exists(filename);
}
// This is always '/' in a ZIP
char ZipArchiveIOSystem::getOsSeparator() const {
return '/';
}
// Only supports Reading
IOStream * ZipArchiveIOSystem::Open(const char* pFilename, const char* pMode) {
ai_assert(pFilename != nullptr);
for (size_t i = 0; pMode[i] != 0; ++i)
{
ai_assert(pMode[i] != 'w');
if (pMode[i] == 'w')
return nullptr;
}
std::string filename(pFilename);
return pImpl->OpenFile(filename);
}
void ZipArchiveIOSystem::Close(IOStream* pFile) {
delete pFile;
}
bool ZipArchiveIOSystem::isOpen() const {
return (pImpl->isOpen());
}
void ZipArchiveIOSystem::getFileList(std::vector<std::string>& rFileList) const {
return pImpl->getFileList(rFileList);
}
void ZipArchiveIOSystem::getFileListExtension(std::vector<std::string>& rFileList, const std::string& extension) const {
return pImpl->getFileListExtension(rFileList, extension);
}
bool ZipArchiveIOSystem::isZipArchive(IOSystem* pIOHandler, const char* pFilename) {
Implement tmp(pIOHandler, pFilename, "r");
return tmp.isOpen();
}
bool ZipArchiveIOSystem::isZipArchive(IOSystem* pIOHandler, const std::string& rFilename) {
return isZipArchive(pIOHandler, rFilename.c_str());
}
}

View File

@ -90,7 +90,6 @@ namespace Assimp {
, anim_fps() , anim_fps()
, out(out) , out(out)
, doc(doc) , doc(doc)
, mRemoveEmptyBones( removeEmptyBones )
, mCurrentUnit(FbxUnit::cm) { , mCurrentUnit(FbxUnit::cm) {
// animations need to be converted first since this will // animations need to be converted first since this will
// populate the node_anim_chain_bits map, which is needed // populate the node_anim_chain_bits map, which is needed
@ -1462,14 +1461,8 @@ namespace Assimp {
const WeightIndexArray& indices = cluster->GetIndices(); const WeightIndexArray& indices = cluster->GetIndices();
if (indices.empty() && mRemoveEmptyBones ) {
continue;
}
const MatIndexArray& mats = geo.GetMaterialIndices(); const MatIndexArray& mats = geo.GetMaterialIndices();
bool ok = false;
const size_t no_index_sentinel = std::numeric_limits<size_t>::max(); const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
count_out_indices.clear(); count_out_indices.clear();
@ -1510,7 +1503,6 @@ namespace Assimp {
} }
++count_out_indices.back(); ++count_out_indices.back();
ok = true;
} }
} }
} }
@ -1518,12 +1510,10 @@ namespace Assimp {
// if we found at least one, generate the output bones // if we found at least one, generate the output bones
// XXX this could be heavily simplified by collecting the bone // XXX this could be heavily simplified by collecting the bone
// data in a single step. // data in a single step.
if (ok && mRemoveEmptyBones) {
ConvertCluster(bones, model, *cluster, out_indices, index_out_indices, ConvertCluster(bones, model, *cluster, out_indices, index_out_indices,
count_out_indices, node_global_transform); count_out_indices, node_global_transform);
} }
} }
}
catch (std::exception&) { catch (std::exception&) {
std::for_each(bones.begin(), bones.end(), Util::delete_fun<aiBone>()); std::for_each(bones.begin(), bones.end(), Util::delete_fun<aiBone>());
throw; throw;

View File

@ -470,9 +470,6 @@ private:
aiScene* const out; aiScene* const out;
const FBX::Document& doc; const FBX::Document& doc;
bool mRemoveEmptyBones;
FbxUnit mCurrentUnit; FbxUnit mCurrentUnit;
}; };

View File

@ -90,14 +90,6 @@ const Object* LazyObject::Get(bool dieOnError)
return object.get(); return object.get();
} }
// if this is the root object, we return a dummy since there
// is no root object int he fbx file - it is just referenced
// with id 0.
if(id == 0L) {
object.reset(new Object(id, element, "Model::RootNode"));
return object.get();
}
const Token& key = element.KeyToken(); const Token& key = element.KeyToken();
const TokenList& tokens = element.Tokens(); const TokenList& tokens = element.Tokens();

View File

@ -1706,8 +1706,7 @@ void FBXExporter::WriteObjects ()
} }
if (end) { break; } if (end) { break; }
} }
limbnodes.insert(parent);
skeleton.insert(parent);
// if it was the skeleton root we can finish here // if it was the skeleton root we can finish here
if (end) { break; } if (end) { break; }
} }
@ -1848,44 +1847,10 @@ void FBXExporter::WriteObjects ()
inverse_bone_xform.Inverse(); inverse_bone_xform.Inverse();
aiMatrix4x4 tr = inverse_bone_xform * mesh_xform; aiMatrix4x4 tr = inverse_bone_xform * mesh_xform;
// this should be the same as the bone's mOffsetMatrix.
// if it's not the same, the skeleton isn't in the bind pose.
float epsilon = 1e-4f; // some error is to be expected
float epsilon_custom = mProperties->GetPropertyFloat("BINDPOSE_EPSILON", -1);
if(epsilon_custom > 0)
epsilon = epsilon_custom;
bool bone_xform_okay = true;
if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) {
not_in_bind_pose.insert(b);
bone_xform_okay = false;
}
// if we have a bone we should use the mOffsetMatrix,
// otherwise try to just use the calculated transform.
if (b) {
sdnode.AddChild("Transform", b->mOffsetMatrix);
} else {
sdnode.AddChild("Transform", tr); sdnode.AddChild("Transform", tr);
}
// note: it doesn't matter if we mix these,
// because if they disagree we'll throw an exception later.
// it could be that the skeleton is not in the bone pose
// but all bones are still defined,
// in which case this would use the mOffsetMatrix for everything
// and a correct skeleton would still be output.
// transformlink should be the position of the bone in world space.
// if the bone is in the bind pose (or nonexistent),
// we can just use the matrix we already calculated
if (bone_xform_okay) {
sdnode.AddChild("TransformLink", bone_xform); sdnode.AddChild("TransformLink", bone_xform);
// otherwise we can only work it out using the mesh position.
} else {
aiMatrix4x4 trl = b->mOffsetMatrix;
trl.Inverse();
trl *= mesh_xform;
sdnode.AddChild("TransformLink", trl);
}
// note: this means we ALWAYS rely on the mesh node transform // note: this means we ALWAYS rely on the mesh node transform
// being unchanged from the time the skeleton was bound. // being unchanged from the time the skeleton was bound.
// there's not really any way around this at the moment. // there's not really any way around this at the moment.

View File

@ -115,7 +115,6 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
if(tempVerts.empty()) { if(tempVerts.empty()) {
FBXImporter::LogWarn("encountered mesh with no vertices"); FBXImporter::LogWarn("encountered mesh with no vertices");
return;
} }
std::vector<int> tempFaces; std::vector<int> tempFaces;
@ -123,7 +122,6 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
if(tempFaces.empty()) { if(tempFaces.empty()) {
FBXImporter::LogWarn("encountered mesh with no faces"); FBXImporter::LogWarn("encountered mesh with no faces");
return;
} }
m_vertices.reserve(tempFaces.size()); m_vertices.reserve(tempFaces.size());

View File

@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER #ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER
#include "Q3BSPFileImporter.h" #include "Q3BSPFileImporter.h"
#include "Q3BSPZipArchive.h"
#include "Q3BSPFileParser.h" #include "Q3BSPFileParser.h"
#include "Q3BSPFileData.h" #include "Q3BSPFileData.h"
@ -60,6 +59,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/DefaultIOSystem.h> #include <assimp/DefaultIOSystem.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <vector> #include <vector>
#include <sstream> #include <sstream>
@ -181,7 +181,7 @@ const aiImporterDesc* Q3BSPFileImporter::GetInfo () const {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Import method. // Import method.
void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene* scene, IOSystem* ioHandler) { void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene* scene, IOSystem* ioHandler) {
Q3BSPZipArchive Archive( ioHandler, rFile ); ZipArchiveIOSystem Archive( ioHandler, rFile );
if ( !Archive.isOpen() ) { if ( !Archive.isOpen() ) {
throw DeadlyImportError( "Failed to open file " + rFile + "." ); throw DeadlyImportError( "Failed to open file " + rFile + "." );
} }
@ -223,10 +223,10 @@ void Q3BSPFileImporter::separateMapName( const std::string &importName, std::str
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns the first map in the map archive. // Returns the first map in the map archive.
bool Q3BSPFileImporter::findFirstMapInArchive( Q3BSPZipArchive &bspArchive, std::string &mapName ) { bool Q3BSPFileImporter::findFirstMapInArchive(ZipArchiveIOSystem &bspArchive, std::string &mapName ) {
mapName = ""; mapName = "";
std::vector<std::string> fileList; std::vector<std::string> fileList;
bspArchive.getFileList( fileList ); bspArchive.getFileListExtension( fileList, "bsp" );
if (fileList.empty()) { if (fileList.empty()) {
return false; return false;
} }
@ -249,7 +249,7 @@ bool Q3BSPFileImporter::findFirstMapInArchive( Q3BSPZipArchive &bspArchive, std:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Creates the assimp specific data. // Creates the assimp specific data.
void Q3BSPFileImporter::CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, void Q3BSPFileImporter::CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene,
Q3BSPZipArchive *pArchive ) { ZipArchiveIOSystem *pArchive ) {
if (nullptr == pModel || nullptr == pScene) { if (nullptr == pModel || nullptr == pScene) {
return; return;
} }
@ -418,7 +418,7 @@ void Q3BSPFileImporter::createTriangleTopology( const Q3BSP::Q3BSPModel *pModel,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Creates all referenced materials. // Creates all referenced materials.
void Q3BSPFileImporter::createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, void Q3BSPFileImporter::createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene,
Q3BSPZipArchive *pArchive ) { ZipArchiveIOSystem *pArchive ) {
if ( m_MaterialLookupMap.empty() ) { if ( m_MaterialLookupMap.empty() ) {
return; return;
} }
@ -564,7 +564,7 @@ aiFace *Q3BSPFileImporter::getNextFace( aiMesh *mesh, unsigned int &faceIdx ) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports a texture file. // Imports a texture file.
bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *model, bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *model,
Q3BSP::Q3BSPZipArchive *archive, aiScene*, ZipArchiveIOSystem *archive, aiScene*,
aiMaterial *pMatHelper, int textureId ) { aiMaterial *pMatHelper, int textureId ) {
if (nullptr == archive || nullptr == pMatHelper ) { if (nullptr == archive || nullptr == pMatHelper ) {
return false; return false;
@ -669,7 +669,7 @@ bool Q3BSPFileImporter::importLightmap( const Q3BSP::Q3BSPModel *pModel, aiScene
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Will search for a supported extension. // Will search for a supported extension.
bool Q3BSPFileImporter::expandFile( Q3BSP::Q3BSPZipArchive *pArchive, const std::string &rFilename, bool Q3BSPFileImporter::expandFile(ZipArchiveIOSystem *pArchive, const std::string &rFilename,
const std::vector<std::string> &rExtList, std::string &rFile, const std::vector<std::string> &rExtList, std::string &rFile,
std::string &rExt ) std::string &rExt )
{ {

View File

@ -54,9 +54,9 @@ struct aiMaterial;
struct aiTexture; struct aiTexture;
namespace Assimp { namespace Assimp {
class ZipArchiveIOSystem;
namespace Q3BSP { namespace Q3BSP {
class Q3BSPZipArchive;
struct Q3BSPModel; struct Q3BSPModel;
struct sQ3BSPFace; struct sQ3BSPFace;
} }
@ -85,24 +85,24 @@ protected:
const aiImporterDesc* GetInfo () const; const aiImporterDesc* GetInfo () const;
void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
void separateMapName( const std::string &rImportName, std::string &rArchiveName, std::string &rMapName ); void separateMapName( const std::string &rImportName, std::string &rArchiveName, std::string &rMapName );
bool findFirstMapInArchive( Q3BSP::Q3BSPZipArchive &rArchive, std::string &rMapName ); bool findFirstMapInArchive(ZipArchiveIOSystem &rArchive, std::string &rMapName );
void CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, Q3BSP::Q3BSPZipArchive *pArchive ); void CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, ZipArchiveIOSystem *pArchive );
void CreateNodes( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, aiNode *pParent ); void CreateNodes( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, aiNode *pParent );
aiNode *CreateTopology( const Q3BSP::Q3BSPModel *pModel, unsigned int materialIdx, aiNode *CreateTopology( const Q3BSP::Q3BSPModel *pModel, unsigned int materialIdx,
std::vector<Q3BSP::sQ3BSPFace*> &rArray, aiMesh **pMesh ); std::vector<Q3BSP::sQ3BSPFace*> &rArray, aiMesh **pMesh );
void createTriangleTopology( const Q3BSP::Q3BSPModel *pModel, Q3BSP::sQ3BSPFace *pQ3BSPFace, aiMesh* pMesh, unsigned int &rFaceIdx, void createTriangleTopology( const Q3BSP::Q3BSPModel *pModel, Q3BSP::sQ3BSPFace *pQ3BSPFace, aiMesh* pMesh, unsigned int &rFaceIdx,
unsigned int &rVertIdx ); unsigned int &rVertIdx );
void createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, Q3BSP::Q3BSPZipArchive *pArchive ); void createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, ZipArchiveIOSystem *pArchive );
size_t countData( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const; size_t countData( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const;
size_t countFaces( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const; size_t countFaces( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const;
size_t countTriangles( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const; size_t countTriangles( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const;
void createMaterialMap( const Q3BSP::Q3BSPModel *pModel); void createMaterialMap( const Q3BSP::Q3BSPModel *pModel);
aiFace *getNextFace( aiMesh *pMesh, unsigned int &rFaceIdx ); aiFace *getNextFace( aiMesh *pMesh, unsigned int &rFaceIdx );
bool importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel, Q3BSP::Q3BSPZipArchive *pArchive, aiScene* pScene, bool importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel, ZipArchiveIOSystem *pArchive, aiScene* pScene,
aiMaterial *pMatHelper, int textureId ); aiMaterial *pMatHelper, int textureId );
bool importLightmap( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, aiMaterial *pMatHelper, int lightmapId ); bool importLightmap( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, aiMaterial *pMatHelper, int lightmapId );
bool importEntities( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene ); bool importEntities( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene );
bool expandFile( Q3BSP::Q3BSPZipArchive *pArchive, const std::string &rFilename, const std::vector<std::string> &rExtList, bool expandFile(ZipArchiveIOSystem *pArchive, const std::string &rFilename, const std::vector<std::string> &rExtList,
std::string &rFile, std::string &rExt ); std::string &rFile, std::string &rExt );
private: private:

View File

@ -45,9 +45,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Q3BSPFileParser.h" #include "Q3BSPFileParser.h"
#include "Q3BSPFileData.h" #include "Q3BSPFileData.h"
#include "Q3BSPZipArchive.h"
#include <vector> #include <vector>
#include <assimp/DefaultIOSystem.h> #include <assimp/DefaultIOSystem.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
namespace Assimp { namespace Assimp {
@ -55,7 +55,7 @@ namespace Assimp {
using namespace Q3BSP; using namespace Q3BSP;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Q3BSPFileParser::Q3BSPFileParser( const std::string &mapName, Q3BSPZipArchive *pZipArchive ) : Q3BSPFileParser::Q3BSPFileParser( const std::string &mapName, ZipArchiveIOSystem *pZipArchive ) :
m_sOffset( 0 ), m_sOffset( 0 ),
m_Data(), m_Data(),
m_pModel(nullptr), m_pModel(nullptr),
@ -101,6 +101,7 @@ bool Q3BSPFileParser::readData( const std::string &rMapName ) {
const size_t readSize = pMapFile->Read( &m_Data[0], sizeof( char ), size ); const size_t readSize = pMapFile->Read( &m_Data[0], sizeof( char ), size );
if ( readSize != size ) { if ( readSize != size ) {
m_Data.clear(); m_Data.clear();
m_pZipArchive->Close(pMapFile);
return false; return false;
} }
m_pZipArchive->Close( pMapFile ); m_pZipArchive->Close( pMapFile );

View File

@ -48,13 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp namespace Assimp
{ {
class ZipArchiveIOSystem;
namespace Q3BSP namespace Q3BSP
{ {
class Q3BSPZipArchive;
struct Q3BSPModel; struct Q3BSPModel;
class ZipFile; class ZipFile;
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -62,7 +61,7 @@ class ZipFile;
class Q3BSPFileParser class Q3BSPFileParser
{ {
public: public:
Q3BSPFileParser( const std::string &rMapName, Q3BSP::Q3BSPZipArchive *pZipArchive ); Q3BSPFileParser( const std::string &rMapName, ZipArchiveIOSystem *pZipArchive );
~Q3BSPFileParser(); ~Q3BSPFileParser();
Q3BSP::Q3BSPModel *getModel() const; Q3BSP::Q3BSPModel *getModel() const;
@ -83,7 +82,7 @@ private:
size_t m_sOffset; size_t m_sOffset;
std::vector<char> m_Data; std::vector<char> m_Data;
Q3BSP::Q3BSPModel *m_pModel; Q3BSP::Q3BSPModel *m_pModel;
Q3BSP::Q3BSPZipArchive *m_pZipArchive; ZipArchiveIOSystem *m_pZipArchive;
}; };
} // Namespace Assimp } // Namespace Assimp

View File

@ -1,325 +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.
----------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER
#include "Q3BSPZipArchive.h"
#include <cassert>
#include <cstdlib>
#include <assimp/ai_assert.h>
namespace Assimp {
namespace Q3BSP {
voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
IOSystem* io_system = (IOSystem*) opaque;
const char* mode_fopen = NULL;
if((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) {
mode_fopen = "rb";
} else {
if(mode & ZLIB_FILEFUNC_MODE_EXISTING) {
mode_fopen = "r+b";
} else {
if(mode & ZLIB_FILEFUNC_MODE_CREATE) {
mode_fopen = "wb";
}
}
}
return (voidpf) io_system->Open(filename, mode_fopen);
}
uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) {
IOStream* io_stream = (IOStream*) stream;
return static_cast<uLong>(io_stream->Read(buf, 1, size));
}
uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) {
IOStream* io_stream = (IOStream*) stream;
return static_cast<uLong>(io_stream->Write(buf, 1, size));
}
long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) {
IOStream* io_stream = (IOStream*) stream;
return static_cast<long>(io_stream->Tell());
}
long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) {
IOStream* io_stream = (IOStream*) stream;
aiOrigin assimp_origin;
switch (origin) {
default:
case ZLIB_FILEFUNC_SEEK_CUR:
assimp_origin = aiOrigin_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END:
assimp_origin = aiOrigin_END;
break;
case ZLIB_FILEFUNC_SEEK_SET:
assimp_origin = aiOrigin_SET;
break;
}
return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1);
}
int IOSystem2Unzip::close(voidpf opaque, voidpf stream) {
IOSystem* io_system = (IOSystem*) opaque;
IOStream* io_stream = (IOStream*) stream;
io_system->Close(io_stream);
return 0;
}
int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) {
return 0;
}
zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
zlib_filefunc_def mapping;
#ifdef ASSIMP_USE_HUNTER
mapping.zopen_file = (open_file_func)open;
mapping.zread_file = (read_file_func)read;
mapping.zwrite_file = (write_file_func)write;
mapping.ztell_file = (tell_file_func)tell;
mapping.zseek_file = (seek_file_func)seek;
mapping.zclose_file = (close_file_func)close;
mapping.zerror_file = (error_file_func)testerror;
#else
mapping.zopen_file = open;
mapping.zread_file = read;
mapping.zwrite_file = write;
mapping.ztell_file = tell;
mapping.zseek_file = seek;
mapping.zclose_file = close;
mapping.zerror_file = testerror;
#endif
mapping.opaque = (voidpf) pIOHandler;
return mapping;
}
ZipFile::ZipFile(size_t size) : m_Size(size) {
ai_assert(m_Size != 0);
m_Buffer = malloc(m_Size);
}
ZipFile::~ZipFile() {
free(m_Buffer);
m_Buffer = NULL;
}
size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) {
const size_t size = pSize * pCount;
assert(size <= m_Size);
std::memcpy(pvBuffer, m_Buffer, size);
return size;
}
size_t ZipFile::Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) {
return 0;
}
size_t ZipFile::FileSize() const {
return m_Size;
}
aiReturn ZipFile::Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
return aiReturn_FAILURE;
}
size_t ZipFile::Tell() const {
return 0;
}
void ZipFile::Flush() {
// empty
}
// ------------------------------------------------------------------------------------------------
// Constructor.
Q3BSPZipArchive::Q3BSPZipArchive(IOSystem* pIOHandler, const std::string& rFile) : m_ZipFileHandle(NULL), m_ArchiveMap() {
if (! rFile.empty()) {
zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
if(m_ZipFileHandle != nullptr) {
mapArchive();
}
}
}
// ------------------------------------------------------------------------------------------------
// Destructor.
Q3BSPZipArchive::~Q3BSPZipArchive() {
for(auto &file : m_ArchiveMap) {
delete file.second;
}
m_ArchiveMap.clear();
if(m_ZipFileHandle != nullptr) {
unzClose(m_ZipFileHandle);
m_ZipFileHandle = nullptr;
}
}
// ------------------------------------------------------------------------------------------------
// Returns true, if the archive is already open.
bool Q3BSPZipArchive::isOpen() const {
return (m_ZipFileHandle != nullptr);
}
// ------------------------------------------------------------------------------------------------
// Returns true, if the filename is part of the archive.
bool Q3BSPZipArchive::Exists(const char* pFile) const {
bool exist = false;
if (pFile != nullptr) {
std::string rFile(pFile);
std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(rFile);
if(it != m_ArchiveMap.end()) {
exist = true;
}
}
return exist;
}
// ------------------------------------------------------------------------------------------------
// Returns the separator delimiter.
char Q3BSPZipArchive::getOsSeparator() const {
#ifndef _WIN32
return '/';
#else
return '\\';
#endif
}
// ------------------------------------------------------------------------------------------------
// Opens a file, which is part of the archive.
IOStream *Q3BSPZipArchive::Open(const char* pFile, const char* /*pMode*/) {
ai_assert(pFile != nullptr);
IOStream* result = nullptr;
std::map<std::string, ZipFile*>::iterator it = m_ArchiveMap.find(pFile);
if(it != m_ArchiveMap.end()) {
result = (IOStream*) it->second;
}
return result;
}
// ------------------------------------------------------------------------------------------------
// Close a filestream.
void Q3BSPZipArchive::Close(IOStream *pFile) {
(void)(pFile);
ai_assert(pFile != nullptr);
// We don't do anything in case the file would be opened again in the future
}
// ------------------------------------------------------------------------------------------------
// Returns the file-list of the archive.
void Q3BSPZipArchive::getFileList(std::vector<std::string> &rFileList) {
rFileList.clear();
for(auto &file : m_ArchiveMap) {
rFileList.push_back(file.first);
}
}
// ------------------------------------------------------------------------------------------------
// Maps the archive content.
bool Q3BSPZipArchive::mapArchive() {
bool success = false;
if(m_ZipFileHandle != nullptr) {
if(m_ArchiveMap.empty()) {
// At first ensure file is already open
if(unzGoToFirstFile(m_ZipFileHandle) == UNZ_OK) {
// Loop over all files
do {
char filename[FileNameSize];
unz_file_info fileInfo;
if(unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, NULL, 0, NULL, 0) == UNZ_OK) {
// The file has EXACTLY the size of uncompressed_size. In C
// you need to mark the last character with '\0', so add
// another character
if(fileInfo.uncompressed_size != 0 && unzOpenCurrentFile(m_ZipFileHandle) == UNZ_OK) {
std::pair<std::map<std::string, ZipFile*>::iterator, bool> result = m_ArchiveMap.insert(std::make_pair(filename, new ZipFile(fileInfo.uncompressed_size)));
if(unzReadCurrentFile(m_ZipFileHandle, result.first->second->m_Buffer, fileInfo.uncompressed_size) == (long int) fileInfo.uncompressed_size) {
if(unzCloseCurrentFile(m_ZipFileHandle) == UNZ_OK) {
// Nothing to do anymore...
}
}
}
}
} while(unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE);
}
}
success = true;
}
return success;
}
// ------------------------------------------------------------------------------------------------
} // Namespace Q3BSP
} // Namespace Assimp
#endif // ASSIMP_BUILD_NO_Q3BSP_IMPORTER

View File

@ -1,135 +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.
----------------------------------------------------------------------
*/
#ifndef AI_Q3BSP_ZIPARCHIVE_H_INC
#define AI_Q3BSP_ZIPARCHIVE_H_INC
#ifdef ASSIMP_USE_HUNTER
# include <minizip/unzip.h>
#else
# include <unzip.h>
#endif
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include <vector>
#include <map>
#include <cassert>
namespace Assimp {
namespace Q3BSP {
// ------------------------------------------------------------------------------------------------
/// \class IOSystem2Unzip
/// \ingroup Assimp::Q3BSP
///
/// \brief
// ------------------------------------------------------------------------------------------------
class IOSystem2Unzip {
public:
static voidpf open(voidpf opaque, const char* filename, int mode);
static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size);
static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size);
static long tell(voidpf opaque, voidpf stream);
static long seek(voidpf opaque, voidpf stream, uLong offset, int origin);
static int close(voidpf opaque, voidpf stream);
static int testerror(voidpf opaque, voidpf stream);
static zlib_filefunc_def get(IOSystem* pIOHandler);
};
// ------------------------------------------------------------------------------------------------
/// \class ZipFile
/// \ingroup Assimp::Q3BSP
///
/// \brief
// ------------------------------------------------------------------------------------------------
class ZipFile : public IOStream {
friend class Q3BSPZipArchive;
public:
explicit ZipFile(size_t size);
~ZipFile();
size_t Read(void* pvBuffer, size_t pSize, size_t pCount );
size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/);
size_t FileSize() const;
aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/);
size_t Tell() const;
void Flush();
private:
void* m_Buffer;
size_t m_Size;
};
// ------------------------------------------------------------------------------------------------
/// \class Q3BSPZipArchive
/// \ingroup Assimp::Q3BSP
///
/// \brief IMplements a zip archive like the WinZip archives. Will be also used to import data
/// from a P3K archive ( Quake level format ).
// ------------------------------------------------------------------------------------------------
class Q3BSPZipArchive : public Assimp::IOSystem {
public:
static const unsigned int FileNameSize = 256;
public:
Q3BSPZipArchive(IOSystem* pIOHandler, const std::string & rFile);
~Q3BSPZipArchive();
bool Exists(const char* pFile) const;
char getOsSeparator() const;
IOStream* Open(const char* pFile, const char* pMode = "rb");
void Close(IOStream* pFile);
bool isOpen() const;
void getFileList(std::vector<std::string> &rFileList);
private:
bool mapArchive();
private:
unzFile m_ZipFileHandle;
std::map<std::string, ZipFile*> m_ArchiveMap;
};
// ------------------------------------------------------------------------------------------------
} // Namespace Q3BSP
} // Namespace Assimp
#endif // AI_Q3BSP_ZIPARCHIVE_H_INC

View File

@ -80,7 +80,13 @@ const aiImporterDesc X3DImporter::Description = {
//const std::regex X3DImporter::pattern_nws(R"([^, \t\r\n]+)"); //const std::regex X3DImporter::pattern_nws(R"([^, \t\r\n]+)");
//const std::regex X3DImporter::pattern_true(R"(^\s*(?:true|1)\s*$)", std::regex::icase); //const std::regex X3DImporter::pattern_true(R"(^\s*(?:true|1)\s*$)", std::regex::icase);
struct WordIterator: public std::iterator<std::input_iterator_tag, const char*> { struct WordIterator {
using iterator_category = std::input_iterator_tag;
using value_type = const char*;
using difference_type = ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
static const char *whitespace; static const char *whitespace;
const char *start_, *end_; const char *start_, *end_;
WordIterator(const char *start, const char *end): start_(start), end_(end) { WordIterator(const char *start, const char *end): start_(start), end_(end) {

View File

@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* glTF Extensions Support: * glTF Extensions Support:
* KHR_materials_pbrSpecularGlossiness full * KHR_materials_pbrSpecularGlossiness full
* KHR_materials_unlit full * KHR_materials_unlit full
* KHR_lights_punctual full
*/ */
#ifndef GLTF2ASSET_H_INC #ifndef GLTF2ASSET_H_INC
#define GLTF2ASSET_H_INC #define GLTF2ASSET_H_INC
@ -668,6 +669,28 @@ namespace glTF2
void Read(Value& obj, Asset& r); void Read(Value& obj, Asset& r);
}; };
//! A light (from KHR_lights_punctual extension)
struct Light : public Object
{
enum Type
{
Directional,
Point,
Spot
};
Type type;
vec3 color;
float intensity;
Nullable<float> range;
float innerConeAngle;
float outerConeAngle;
Light() {}
void Read(Value& obj, Asset& r);
};
//! Image data used to create a texture. //! Image data used to create a texture.
struct Image : public Object struct Image : public Object
@ -819,6 +842,7 @@ namespace glTF2
Nullable<vec3> scale; Nullable<vec3> scale;
Ref<Camera> camera; Ref<Camera> camera;
Ref<Light> light;
std::vector< Ref<Node> > skeletons; //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy. std::vector< Ref<Node> > skeletons; //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy.
Ref<Skin> skin; //!< The ID of the skin referenced by this node. Ref<Skin> skin; //!< The ID of the skin referenced by this node.
@ -1050,6 +1074,7 @@ namespace glTF2
{ {
bool KHR_materials_pbrSpecularGlossiness; bool KHR_materials_pbrSpecularGlossiness;
bool KHR_materials_unlit; bool KHR_materials_unlit;
bool KHR_lights_punctual;
} extensionsUsed; } extensionsUsed;
@ -1063,6 +1088,7 @@ namespace glTF2
LazyDict<Buffer> buffers; LazyDict<Buffer> buffers;
LazyDict<BufferView> bufferViews; LazyDict<BufferView> bufferViews;
LazyDict<Camera> cameras; LazyDict<Camera> cameras;
LazyDict<Light> lights;
LazyDict<Image> images; LazyDict<Image> images;
LazyDict<Material> materials; LazyDict<Material> materials;
LazyDict<Mesh> meshes; LazyDict<Mesh> meshes;
@ -1083,6 +1109,7 @@ namespace glTF2
, buffers (*this, "buffers") , buffers (*this, "buffers")
, bufferViews (*this, "bufferViews") , bufferViews (*this, "bufferViews")
, cameras (*this, "cameras") , cameras (*this, "cameras")
, lights (*this, "lights", "KHR_lights_punctual")
, images (*this, "images") , images (*this, "images")
, materials (*this, "materials") , materials (*this, "materials")
, meshes (*this, "meshes") , meshes (*this, "meshes")

View File

@ -1067,6 +1067,39 @@ inline void Camera::Read(Value& obj, Asset& /*r*/)
} }
} }
inline void Light::Read(Value& obj, Asset& /*r*/)
{
#ifndef M_PI
const float M_PI = 3.14159265358979323846f;
#endif
std::string type_string;
ReadMember(obj, "type", type_string);
if (type_string == "directional")
type = Light::Directional;
else if (type_string == "point")
type = Light::Point;
else
type = Light::Spot;
name = MemberOrDefault(obj, "name", "");
SetVector(color, vec3{ 1.0f, 1.0f, 1.0f });
ReadMember(obj, "color", color);
intensity = MemberOrDefault(obj, "intensity", 1.0f);
ReadMember(obj, "range", range);
if (type == Light::Spot)
{
Value* spot = FindObject(obj, "spot");
if (!spot) throw DeadlyImportError("GLTF: Light missing its spot parameters");
innerConeAngle = MemberOrDefault(*spot, "innerConeAngle", 0.0f);
outerConeAngle = MemberOrDefault(*spot, "outerConeAngle", M_PI / 4.0f);
}
}
inline void Node::Read(Value& obj, Asset& r) inline void Node::Read(Value& obj, Asset& r)
{ {
@ -1110,6 +1143,19 @@ inline void Node::Read(Value& obj, Asset& r)
if (this->camera) if (this->camera)
this->camera->id = this->id; this->camera->id = this->id;
} }
if (Value* extensions = FindObject(obj, "extensions")) {
if (r.extensionsUsed.KHR_lights_punctual) {
if (Value* ext = FindObject(*extensions, "KHR_lights_punctual")) {
if (Value* light = FindUInt(*ext, "light")) {
this->light = r.lights.Retrieve(light->GetUint());
if (this->light)
this->light->id = this->id;
}
}
}
}
} }
inline void Scene::Read(Value& obj, Asset& r) inline void Scene::Read(Value& obj, Asset& r)
@ -1421,6 +1467,7 @@ inline void Asset::ReadExtensionsUsed(Document& doc)
CHECK_EXT(KHR_materials_pbrSpecularGlossiness); CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
CHECK_EXT(KHR_materials_unlit); CHECK_EXT(KHR_materials_unlit);
CHECK_EXT(KHR_lights_punctual);
#undef CHECK_EXT #undef CHECK_EXT
} }

View File

@ -202,6 +202,11 @@ namespace glTF2 {
} }
inline void Write(Value& /*obj*/, Light& /*c*/, AssetWriter& /*w*/)
{
}
inline void Write(Value& obj, Image& img, AssetWriter& w) inline void Write(Value& obj, Image& img, AssetWriter& w)
{ {
if (img.bufferView) { if (img.bufferView) {

View File

@ -140,10 +140,10 @@ 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]; out.r = v[0]; out.g = v[1]; out.b = v[2];
//} }
static void CopyValue(const glTF2::vec4& v, aiColor4D& out) static void CopyValue(const glTF2::vec4& v, aiColor4D& out)
{ {
@ -710,6 +710,69 @@ void glTF2Importer::ImportCameras(glTF2::Asset& r)
} }
} }
void glTF2Importer::ImportLights(glTF2::Asset& r)
{
if (!r.lights.Size())
return;
mScene->mNumLights = r.lights.Size();
mScene->mLights = new aiLight*[r.lights.Size()];
for (size_t i = 0; i < r.lights.Size(); ++i) {
Light& light = r.lights[i];
aiLight* ail = mScene->mLights[i] = new aiLight();
switch (light.type)
{
case Light::Directional:
ail->mType = aiLightSource_DIRECTIONAL; break;
case Light::Point:
ail->mType = aiLightSource_POINT; break;
case Light::Spot:
ail->mType = aiLightSource_SPOT; break;
}
if (ail->mType != aiLightSource_POINT)
{
ail->mDirection = aiVector3D(0.0f, 0.0f, -1.0f);
ail->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
}
vec3 colorWithIntensity = { light.color[0] * light.intensity, light.color[1] * light.intensity, light.color[2] * light.intensity };
CopyValue(colorWithIntensity, ail->mColorAmbient);
CopyValue(colorWithIntensity, ail->mColorDiffuse);
CopyValue(colorWithIntensity, ail->mColorSpecular);
if (ail->mType == aiLightSource_DIRECTIONAL)
{
ail->mAttenuationConstant = 1.0;
ail->mAttenuationLinear = 0.0;
ail->mAttenuationQuadratic = 0.0;
}
else
{
//in PBR attenuation is calculated using inverse square law which can be expressed
//using assimps equation: 1/(att0 + att1 * d + att2 * d*d) with the following parameters
//this is correct equation for the case when range (see
//https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual)
//is not present. When range is not present it is assumed that it is infinite and so numerator is 1.
//When range is present then numerator might be any value in range [0,1] and then assimps equation
//will not suffice. In this case range is added into metadata in ImportNode function
//and its up to implementation to read it when it wants to
ail->mAttenuationConstant = 0.0;
ail->mAttenuationLinear = 0.0;
ail->mAttenuationQuadratic = 1.0;
}
if (ail->mType == aiLightSource_SPOT)
{
ail->mAngleInnerCone = light.innerConeAngle;
ail->mAngleOuterCone = light.outerConeAngle;
}
}
}
static void GetNodeTransform(aiMatrix4x4& matrix, const glTF2::Node& node) { static void GetNodeTransform(aiMatrix4x4& matrix, const glTF2::Node& node) {
if (node.matrix.isPresent) { if (node.matrix.isPresent) {
CopyValue(node.matrix.value, matrix); CopyValue(node.matrix.value, matrix);
@ -881,6 +944,18 @@ aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector<unsigned int>&
pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
} }
if (node.light) {
pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
//range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
//it is added to meta data of parent node, because there is no other place to put it
if (node.light->range.isPresent)
{
ainode->mMetaData = aiMetadata::Alloc(1);
ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value);
}
}
return ainode; return ainode;
} }
@ -1150,6 +1225,7 @@ void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IO
ImportMeshes(asset); ImportMeshes(asset);
ImportCameras(asset); ImportCameras(asset);
ImportLights(asset);
ImportNodes(asset); ImportNodes(asset);

View File

@ -0,0 +1,87 @@
/*
---------------------------------------------------------------------------
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.
---------------------------------------------------------------------------
*/
/** @file ZipArchiveIOSystem.h
* @brief Implementation of IOSystem to read a ZIP file from another IOSystem
*/
#ifndef AI_ZIPARCHIVEIOSYSTEM_H_INC
#define AI_ZIPARCHIVEIOSYSTEM_H_INC
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
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;
//! Get the list of all files with their simplified paths
//! Intended for use within Assimp library boundaries
void getFileList(std::vector<std::string>& rFileList) const;
//! Get the list of all files with extension (must be lowercase)
//! Intended for use within Assimp library boundaries
void getFileListExtension(std::vector<std::string>& 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;
};
} // Namespace Assimp
#endif // AI_ZIPARCHIVEIOSYSTEM_H_INC

View File

@ -142,7 +142,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @brief Specifies the maximum angle that may be between two vertex tangents /** @brief Specifies the maximum angle that may be between two vertex tangents
* that their tangents and bi-tangents are smoothed. * that their tangents and bi-tangents are smoothed.
* *
* This applies to the CalcTangentSpace-Step. TFvhe angle is specified * This applies to the CalcTangentSpace-Step. The angle is specified
* in degrees. The maximum value is 175. * in degrees. The maximum value is 175.
* Property type: float. Default value: 45 degrees * Property type: float. Default value: 45 degrees
*/ */

Binary file not shown.

Binary file not shown.

View File

@ -60,3 +60,16 @@ public:
TEST_F(utColladaImportExport, importBlenFromFileTest) { TEST_F(utColladaImportExport, importBlenFromFileTest) {
EXPECT_TRUE(importerTest()); EXPECT_TRUE(importerTest());
} }
class utColladaZaeImportExport : public AbstractImportExportBase {
public:
virtual bool importerTest() {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.zae", aiProcess_ValidateDataStructure);
return nullptr != scene;
}
};
TEST_F(utColladaZaeImportExport, importBlenFromFileTest) {
EXPECT_TRUE(importerTest());
}