Merge branch 'master' into topic/fbxNodeChainFix

pull/2589/head
Kim Kulling 2019-08-16 08:47:02 +02:00 committed by GitHub
commit 84e9d9ddf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 2680 additions and 2527 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)
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")
ELSE()
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/StringComparison.h>
#include <assimp/StringUtils.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <string>
#include <vector>
@ -58,11 +59,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory>
#include "D3MFOpcPackage.h"
#ifdef ASSIMP_USE_HUNTER
# include <minizip/unzip.h>
#else
# include <unzip.h>
#endif
#include <assimp/irrXMLWrapper.h>
#include "3MFXmlTags.h"
#include <assimp/fast_atof.h>
@ -453,7 +449,7 @@ bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bo
if ( nullptr == pIOHandler ) {
return false;
}
if ( !D3MF::D3MFOpcPackage::isZipArchive( pIOHandler, filename ) ) {
if ( !ZipArchiveIOSystem::isZipArchive( pIOHandler, filename ) ) {
return false;
}
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/DefaultLogger.hpp>
#include <assimp/ai_assert.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <cstdlib>
#include <memory>
@ -56,344 +57,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <map>
#include <algorithm>
#include <cassert>
#ifdef ASSIMP_USE_HUNTER
# include <minizip/unzip.h>
#else
# include <unzip.h>
#endif
#include "3MFXmlTags.h"
namespace Assimp {
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;
@ -453,7 +121,7 @@ public:
D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
: mRootStream(nullptr)
, mZipArchive() {
mZipArchive.reset( new D3MF::D3MFZipArchive( pIOHandler, rFile ) );
mZipArchive.reset( new ZipArchiveIOSystem( pIOHandler, rFile ) );
if(!mZipArchive->isOpen()) {
throw DeadlyImportError("Failed to open file " + rFile+ ".");
}
@ -481,14 +149,14 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
ASSIMP_LOG_DEBUG(rootFile);
mZipArchive->Close(fileStream);
mRootStream = mZipArchive->Open(rootFile.c_str());
ai_assert( mRootStream != nullptr );
if ( nullptr == mRootStream ) {
throw DeadlyExportError( "Cannot open root-file in archive : " + rootFile );
}
mZipArchive->Close( fileStream );
} else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES",file);
} else {
@ -499,7 +167,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
}
D3MFOpcPackage::~D3MFOpcPackage() {
// empty
mZipArchive->Close(mRootStream);
}
IOStream* D3MFOpcPackage::RootStream() const {
@ -516,15 +184,6 @@ bool D3MFOpcPackage::validate() {
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::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream));
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>
namespace Assimp {
class ZipArchiveIOSystem;
namespace D3MF {
using XmlReader = irr::io::IrrXMLReader ;
@ -60,22 +62,19 @@ struct OpcPackageRelationship {
std::string target;
};
class D3MFZipArchive;
class D3MFOpcPackage {
public:
D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile );
~D3MFOpcPackage();
IOStream* RootStream() const;
bool validate();
static bool isZipArchive( IOSystem* pIOHandler, const std::string& rFile );
protected:
std::string ReadPackageRootRelationship(IOStream* stream);
private:
IOStream* mRootStream;
std::unique_ptr<D3MFZipArchive> mZipArchive;
std::unique_ptr<ZipArchiveIOSystem> mZipArchive;
};
} // Namespace D3MF

View File

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

View File

@ -580,15 +580,11 @@ struct Image
{
std::string mFileName;
/** If image file name is zero, embedded image data
*/
/** Embedded image data */
std::vector<uint8_t> mImageData;
/** If image file name is zero, file format of
* embedded image data.
*/
/** File format hint ofembedded image data */
std::string mEmbeddedFormat;
};
/** 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/SkeletonMeshBuilder.h>
#include <assimp/CreateAnimMesh.h>
#include <assimp/ZipArchiveIOSystem.h>
#include "time.h"
#include "math.h"
@ -73,12 +74,12 @@ static const aiImporterDesc desc = {
"",
"",
"http://collada.org",
aiImporterFlags_SupportTextFlavour,
aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportCompressedFlavour,
1,
3,
1,
5,
"dae"
"dae zae"
};
// ------------------------------------------------------------------------------------------------
@ -112,9 +113,20 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
// check file extension
const std::string extension = GetExtension(pFile);
if (extension == "dae") {
bool readSig = checkSig && (pIOHandler != nullptr);
if (!readSig) {
if (extension == "dae" || extension == "zae") {
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
if (extension == "xml" || !extension.length() || checkSig) {
@ -164,6 +176,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
// parse the input file
ColladaParser parser(pIOHandler, pFile);
if( !parser.mRootNode) {
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);
// Apply unit-size scale calculation
pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0,
0, parser.mUnitSize, 0, 0,
0, 0, parser.mUnitSize, 0,
@ -222,6 +236,9 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
// store all materials
StoreSceneMaterials(pScene);
// store all textures
StoreSceneTextures(pScene);
// store all lights
StoreSceneLights(pScene);
@ -315,6 +332,7 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co
// ------------------------------------------------------------------------------------------------
// Resolve UV channels
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
const Collada::SemanticMappingTable& table) {
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
if (it != table.mMap.end()) {
@ -354,7 +372,8 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
if (out->mType == aiLightSource_AMBIENT) {
out->mColorDiffuse = out->mColorSpecular = aiColor3D(0, 0, 0);
out->mColorAmbient = srcLight->mColor*srcLight->mIntensity;
} else {
}
else {
// collada doesn't differentiate between these color types
out->mColorDiffuse = out->mColorSpecular = srcLight->mColor*srcLight->mIntensity;
out->mColorAmbient = aiColor3D(0, 0, 0);
@ -372,12 +391,14 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
// epsilon chosen to be 0.1
out->mAngleOuterCone = std::acos(std::pow(0.1f, 1.f / srcLight->mFalloffExponent)) +
out->mAngleInnerCone;
} else {
}
else {
out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle);
if (out->mAngleOuterCone < out->mAngleInnerCone)
std::swap(out->mAngleInnerCone, out->mAngleOuterCone);
}
} else {
}
else {
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)) /
std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov));
}
} else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) {
out->mHorizontalFOV = 2.0f * AI_RAD_TO_DEG(std::atan(srcCamera->mAspect *
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) {
ASSIMP_LOG_WARN_F( "Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping." );
continue;
}
} else {
}
else {
// ID found in the mesh library -> direct reference to an unskinned mesh
srcMesh = srcMeshIt->second;
}
@ -491,7 +515,8 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
if (meshMatIt != mid.mMaterials.end()) {
table = &meshMatIt->second;
meshMaterial = table->mMatName;
} else {
}
else {
ASSIMP_LOG_WARN_F("Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <",
mid.mMeshOrController, ">.");
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);
if (dstMeshIt != mMeshIndexByID.end()) {
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
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];
size_t pairCount = pSrcController->mWeightCounts[orgIndex];
for( size_t b = 0; b < pairCount; ++b, ++iit) {
const size_t jointIndex = iit->first;
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);
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;
val.mTime = time;
@ -1150,7 +1178,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
entry.mSubElement = 2;
else
ASSIMP_LOG_WARN_F("Unknown anim subelement <", subElement, ">. Ignoring");
} else {
}
else {
// no subelement following, transformId is remaining string
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1);
}
@ -1208,7 +1237,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
{
entry.mTargetId = entry.mTransformId;
entry.mTransformId = "";
} else
}
else
continue;
}
@ -1377,7 +1407,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
}
anims.push_back(dstAnim);
} else
}
else
{
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;
mat.AddProperty(&effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
} else {
}
else {
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 (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();
// 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
if (imIt->second.mEmbeddedFormat.length() > 3) {
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];
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
mTextures.push_back(tex);
}
else
{
if (imIt->second.mFileName.empty()) {
throw DeadlyImportError("Collada: Invalid texture, no data or file reference given");
}
result.Set(imIt->second.mFileName);
ConvertPath(result);
}
@ -1813,7 +1845,8 @@ void ColladaLoader::ConvertPath (aiString& ss)
size_t nbr = strtoul16(mychar);
it += 3;
*out++ = (char)(nbr & 0xFF);
} else
}
else
{
*out++ = *it++;
}
@ -1901,7 +1934,8 @@ std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode)
{
if (!pNode->mName.empty()) {
return pNode->mName;
} else {
}
else {
return format() << "$ColladaAutoName$_" << mNodeNameCounter++;
}
}

View File

@ -94,20 +94,20 @@ public:
public:
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override;
protected:
/** Return importer meta information.
* 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.
* 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. */
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/light.h>
#include <assimp/TinyFormatter.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <memory>
@ -90,21 +91,49 @@ ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
throw DeadlyImportError("IOSystem is NULL.");
}
// open the file
std::unique_ptr<IOStream> file( pIOHandler->Open(pFile ) );
if (file.get() == nullptr) {
throw DeadlyImportError( "Failed to open file " + pFile + "." );
std::unique_ptr<IOStream> daefile;
std::unique_ptr<ZipArchiveIOSystem> zip_archive;
// 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
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());
if (!mReader) {
ThrowException("Collada: Unable to open file.");
ThrowException("Unable to read file, malformed XML");
}
// start reading
ReadContents();
// read embedded textures
if (zip_archive && zip_archive->isOpen()) {
ReadEmbeddedTextures(*zip_archive);
}
}
// ------------------------------------------------------------------------------------------------
@ -118,6 +147,49 @@ ColladaParser::~ColladaParser()
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
bool ColladaParser::ReadBoolFromTextContent()
@ -165,12 +237,14 @@ void ColladaParser::ReadContents()
}
ReadStructure();
} else
}
else
{
ASSIMP_LOG_DEBUG_F("Ignoring global element <", mReader->getNodeName(), ">.");
SkipElement();
}
} else
}
else
{
// 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
ReadAnimation(&mAnims);
} else
}
else
{
// ignore the rest
SkipElement();
@ -722,7 +797,8 @@ void ColladaParser::ReadControllerLibrary()
// read on from there
ReadController(mControllerLibrary[id]);
} else
}
else
{
// ignore the rest
SkipElement();
@ -816,7 +892,8 @@ void ColladaParser::ReadController( Collada::Controller& pController)
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)
break;
else
@ -1008,7 +1085,8 @@ void ColladaParser::ReadImageLibrary()
// read on from there
ReadImage(mImageLibrary[id]);
} else
}
else
{
// ignore the rest
SkipElement();
@ -1158,7 +1236,8 @@ void ColladaParser::ReadMaterialLibrary()
}
ReadMaterial(mMaterialLibrary[id]);
} else
}
else
{
// ignore the rest
SkipElement();
@ -1193,7 +1272,8 @@ void ColladaParser::ReadLightLibrary()
// create an entry and store it in the library under its ID
ReadLight(mLightLibrary[id] = Light());
} else
}
else
{
// ignore the rest
SkipElement();
@ -1232,7 +1312,8 @@ void ColladaParser::ReadCameraLibrary()
ReadCamera(cam);
} else
}
else
{
// ignore the rest
SkipElement();
@ -1268,7 +1349,8 @@ void ColladaParser::ReadMaterial( Collada::Material& pMaterial)
pMaterial.mEffect = url + 1;
SkipElement();
} else
}
else
{
// ignore the rest
SkipElement();
@ -1439,7 +1521,8 @@ void ColladaParser::ReadEffectLibrary()
mEffectLibrary[id] = Effect();
// read on from there
ReadEffect(mEffectLibrary[id]);
} else
}
else
{
// ignore the rest
SkipElement();
@ -1779,7 +1862,8 @@ void ColladaParser::ReadEffectFloat( ai_real& pFloat)
SkipSpacesAndLineEnd(&content);
TestClosing("float");
} else
}
else
{
// ignore the rest
SkipElement();
@ -1834,7 +1918,8 @@ void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam)
pParam.mType = Param_Sampler;
pParam.mReference = url;
SkipElement("sampler2D");
} else
}
else
{
// ignore unknown element
SkipElement();
@ -1879,7 +1964,8 @@ void ColladaParser::ReadGeometryLibrary()
// read on from there
ReadGeometry(mesh);
} else
}
else
{
// ignore the rest
SkipElement();
@ -1910,7 +1996,8 @@ void ColladaParser::ReadGeometry( Collada::Mesh* pMesh)
{
// read on from there
ReadMesh(pMesh);
} else
}
else
{
// ignore the rest
SkipElement();
@ -1952,7 +2039,8 @@ void ColladaParser::ReadMesh( Mesh* pMesh)
{
// read per-index mesh data and faces setup
ReadIndexData(pMesh);
} else
}
else
{
// ignore the restf
SkipElement();
@ -1968,7 +2056,8 @@ void ColladaParser::ReadMesh( Mesh* pMesh)
{
// end of <mesh> element - we're done here
break;
} else
}
else
{
// everything else should be punished
ThrowException("Expected end of <mesh> element.");
@ -1999,7 +2088,8 @@ void ColladaParser::ReadSource()
else if (IsElement("accessor"))
{
ReadAccessor(sourceID);
} else
}
else
{
// ignore the rest
SkipElement();
@ -2015,7 +2105,8 @@ void ColladaParser::ReadSource()
else if (strcmp(mReader->getNodeName(), "technique_common") == 0)
{
// end of another meaningless element - read over it
} else
}
else
{
// everything else should be punished
ThrowException("Expected end of <source> element.");
@ -2064,7 +2155,8 @@ void ColladaParser::ReadDataArray()
SkipSpacesAndLineEnd(&content);
}
} else
}
else
{
data.mValues.reserve(count);
@ -2176,7 +2268,8 @@ void ColladaParser::ReadAccessor( const std::string& pID)
// skip remaining stuff of this element, if any
SkipElement();
} else
}
else
{
ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <accessor>");
}
@ -2206,7 +2299,8 @@ void ColladaParser::ReadVertexData( Mesh* pMesh)
if (IsElement("input"))
{
ReadInputChannel(pMesh->mPerVertexData);
} else
}
else
{
ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <vertices>");
}
@ -2304,9 +2398,11 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
else if (IsElement("extra"))
{
SkipElement("extra");
} else if ( IsElement("ph")) {
}
else if (IsElement("ph")) {
SkipElement("ph");
} else {
}
else {
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'
ReportWarning("Expected different index count in <p> element, %zu instead of %zu.", indices.size(), expectedPointCount * numOffsets);
pNumPrimitives = (indices.size() / numOffsets) / 2;
} else
}
else
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.");
// 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]));
if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) /* hack ... consider cleaner solution */
pMesh->mNumUVComponents[pInput.mIndex] = 3;
} else
}
else
{
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]];
}
pMesh->mColors[pInput.mIndex].push_back(result);
} else
}
else
{
ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping.");
}
@ -2723,7 +2823,8 @@ void ColladaParser::ReadSceneLibrary()
mNodeLibrary[node->mID] = node;
ReadSceneNode(node);
} else
}
else
{
// ignore the rest
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
void ColladaParser::ReadNodeGeometry(Node* pNode)
@ -3036,7 +3157,8 @@ void ColladaParser::ReadScene()
if (sit == mNodeLibrary.end())
ThrowException("Unable to resolve visual_scene reference \"" + std::string(url) + "\" in <instance_visual_scene> element.");
mRootNode = sit->second;
} else {
}
else {
SkipElement();
}
}

View File

@ -54,6 +54,7 @@
namespace Assimp
{
class ZipArchiveIOSystem;
// ------------------------------------------------------------------------------------------
/** Parser helper class for the Collada loader.
@ -75,6 +76,9 @@ namespace Assimp
/** Destructor */
~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 */
void ReadContents();
@ -235,6 +239,9 @@ namespace Assimp
// Processes bind_vertex_input and bind elements
void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl);
/** Reads embedded textures from a ZAE archive*/
void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
protected:
/** Aborts the file reading with an exception */
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

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

View File

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

View File

@ -45,9 +45,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Q3BSPFileParser.h"
#include "Q3BSPFileData.h"
#include "Q3BSPZipArchive.h"
#include <vector>
#include <assimp/DefaultIOSystem.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <assimp/ai_assert.h>
namespace Assimp {
@ -55,7 +55,7 @@ namespace Assimp {
using namespace Q3BSP;
// ------------------------------------------------------------------------------------------------
Q3BSPFileParser::Q3BSPFileParser( const std::string &mapName, Q3BSPZipArchive *pZipArchive ) :
Q3BSPFileParser::Q3BSPFileParser( const std::string &mapName, ZipArchiveIOSystem *pZipArchive ) :
m_sOffset( 0 ),
m_Data(),
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 );
if ( readSize != size ) {
m_Data.clear();
m_pZipArchive->Close(pMapFile);
return false;
}
m_pZipArchive->Close( pMapFile );

View File

@ -48,13 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp
{
class ZipArchiveIOSystem;
namespace Q3BSP
{
class Q3BSPZipArchive;
struct Q3BSPModel;
class ZipFile;
}
// -------------------------------------------------------------------
@ -62,7 +61,7 @@ class ZipFile;
class Q3BSPFileParser
{
public:
Q3BSPFileParser( const std::string &rMapName, Q3BSP::Q3BSPZipArchive *pZipArchive );
Q3BSPFileParser( const std::string &rMapName, ZipArchiveIOSystem *pZipArchive );
~Q3BSPFileParser();
Q3BSP::Q3BSPModel *getModel() const;
@ -83,7 +82,7 @@ private:
size_t m_sOffset;
std::vector<char> m_Data;
Q3BSP::Q3BSPModel *m_pModel;
Q3BSP::Q3BSPZipArchive *m_pZipArchive;
ZipArchiveIOSystem *m_pZipArchive;
};
} // 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_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;
const char *start_, *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:
* KHR_materials_pbrSpecularGlossiness full
* KHR_materials_unlit full
* KHR_lights_punctual full
*/
#ifndef GLTF2ASSET_H_INC
#define GLTF2ASSET_H_INC
@ -668,6 +669,28 @@ namespace glTF2
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.
struct Image : public Object
@ -819,6 +842,7 @@ namespace glTF2
Nullable<vec3> scale;
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.
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_unlit;
bool KHR_lights_punctual;
} extensionsUsed;
@ -1063,6 +1088,7 @@ namespace glTF2
LazyDict<Buffer> buffers;
LazyDict<BufferView> bufferViews;
LazyDict<Camera> cameras;
LazyDict<Light> lights;
LazyDict<Image> images;
LazyDict<Material> materials;
LazyDict<Mesh> meshes;
@ -1083,6 +1109,7 @@ namespace glTF2
, buffers (*this, "buffers")
, bufferViews (*this, "bufferViews")
, cameras (*this, "cameras")
, lights (*this, "lights", "KHR_lights_punctual")
, images (*this, "images")
, materials (*this, "materials")
, 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)
{
@ -1110,6 +1143,19 @@ inline void Node::Read(Value& obj, Asset& r)
if (this->camera)
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)
@ -1421,6 +1467,7 @@ inline void Asset::ReadExtensionsUsed(Document& doc)
CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
CHECK_EXT(KHR_materials_unlit);
CHECK_EXT(KHR_lights_punctual);
#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)
{
if (img.bufferView) {

View File

@ -140,10 +140,10 @@ static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode)
}
}
//static void CopyValue(const glTF2::vec3& v, aiColor3D& out)
//{
// out.r = v[0]; out.g = v[1]; out.b = v[2];
//}
static void CopyValue(const glTF2::vec3& v, aiColor3D& out)
{
out.r = v[0]; out.g = v[1]; out.b = v[2];
}
static void CopyValue(const glTF2::vec4& v, aiColor4D& out)
{
@ -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) {
if (node.matrix.isPresent) {
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;
}
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;
}
@ -1150,6 +1225,7 @@ void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IO
ImportMeshes(asset);
ImportCameras(asset);
ImportLights(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
* 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.
* 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) {
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());
}