Build Assimp from source
This commit is contained in:
695
thirdparty/assimp/code/Common/Assimp.cpp
vendored
Normal file
695
thirdparty/assimp/code/Common/Assimp.cpp
vendored
Normal file
@@ -0,0 +1,695 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 Assimp.cpp
|
||||
* @brief Implementation of the Plain-C API
|
||||
*/
|
||||
|
||||
#include <assimp/cimport.h>
|
||||
#include <assimp/LogStream.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/GenericProperty.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/BaseImporter.h>
|
||||
|
||||
#include "CApi/CInterfaceIOWrapper.h"
|
||||
#include "Importer.h"
|
||||
#include "ScenePrivate.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
# include <thread>
|
||||
# include <mutex>
|
||||
#endif
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
using namespace Assimp;
|
||||
|
||||
namespace Assimp {
|
||||
// underlying structure for aiPropertyStore
|
||||
typedef BatchLoader::PropertyMap PropertyMap;
|
||||
|
||||
/** Stores the LogStream objects for all active C log streams */
|
||||
struct mpred {
|
||||
bool operator () (const aiLogStream& s0, const aiLogStream& s1) const {
|
||||
return s0.callback<s1.callback&&s0.user<s1.user;
|
||||
}
|
||||
};
|
||||
typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap;
|
||||
|
||||
/** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */
|
||||
typedef std::list<Assimp::LogStream*> PredefLogStreamMap;
|
||||
|
||||
/** Local storage of all active log streams */
|
||||
static LogStreamMap gActiveLogStreams;
|
||||
|
||||
/** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */
|
||||
static PredefLogStreamMap gPredefinedStreams;
|
||||
|
||||
/** Error message of the last failed import process */
|
||||
static std::string gLastErrorString;
|
||||
|
||||
/** Verbose logging active or not? */
|
||||
static aiBool gVerboseLogging = false;
|
||||
|
||||
/** will return all registered importers. */
|
||||
void GetImporterInstanceList(std::vector< BaseImporter* >& out);
|
||||
|
||||
/** will delete all registered importers. */
|
||||
void DeleteImporterInstanceList(std::vector< BaseImporter* >& out);
|
||||
} // namespace assimp
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
/** Global mutex to manage the access to the log-stream map */
|
||||
static std::mutex gLogStreamMutex;
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Custom LogStream implementation for the C-API
|
||||
class LogToCallbackRedirector : public LogStream {
|
||||
public:
|
||||
explicit LogToCallbackRedirector(const aiLogStream& s)
|
||||
: stream (s) {
|
||||
ai_assert(NULL != s.callback);
|
||||
}
|
||||
|
||||
~LogToCallbackRedirector() {
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
std::lock_guard<std::mutex> lock(gLogStreamMutex);
|
||||
#endif
|
||||
// (HACK) Check whether the 'stream.user' pointer points to a
|
||||
// custom LogStream allocated by #aiGetPredefinedLogStream.
|
||||
// In this case, we need to delete it, too. Of course, this
|
||||
// might cause strange problems, but the chance is quite low.
|
||||
|
||||
PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(),
|
||||
gPredefinedStreams.end(), (Assimp::LogStream*)stream.user);
|
||||
|
||||
if (it != gPredefinedStreams.end()) {
|
||||
delete *it;
|
||||
gPredefinedStreams.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
/** @copydoc LogStream::write */
|
||||
void write(const char* message) {
|
||||
stream.callback(message,stream.user);
|
||||
}
|
||||
|
||||
private:
|
||||
aiLogStream stream;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ReportSceneNotFoundError() {
|
||||
ASSIMP_LOG_ERROR("Unable to find the Assimp::Importer for this aiScene. "
|
||||
"The C-API does not accept scenes produced by the C++ API and vice versa");
|
||||
|
||||
ai_assert(false);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the given file and returns its content.
|
||||
const aiScene* aiImportFile( const char* pFile, unsigned int pFlags) {
|
||||
return aiImportFileEx(pFile,pFlags,NULL);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, aiFileIO* pFS) {
|
||||
return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags,
|
||||
aiFileIO* pFS, const aiPropertyStore* props) {
|
||||
ai_assert(NULL != pFile);
|
||||
|
||||
const aiScene* scene = NULL;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// create an Importer for this file
|
||||
Assimp::Importer* imp = new Assimp::Importer();
|
||||
|
||||
// copy properties
|
||||
if(props) {
|
||||
const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
|
||||
ImporterPimpl* pimpl = imp->Pimpl();
|
||||
pimpl->mIntProperties = pp->ints;
|
||||
pimpl->mFloatProperties = pp->floats;
|
||||
pimpl->mStringProperties = pp->strings;
|
||||
pimpl->mMatrixProperties = pp->matrices;
|
||||
}
|
||||
// setup a custom IO system if necessary
|
||||
if (pFS) {
|
||||
imp->SetIOHandler( new CIOSystemWrapper (pFS) );
|
||||
}
|
||||
|
||||
// and have it read the file
|
||||
scene = imp->ReadFile( pFile, pFlags);
|
||||
|
||||
// if succeeded, store the importer in the scene and keep it alive
|
||||
if( scene) {
|
||||
ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
|
||||
priv->mOrigImporter = imp;
|
||||
} else {
|
||||
// if failed, extract error code and destroy the import
|
||||
gLastErrorString = imp->GetErrorString();
|
||||
delete imp;
|
||||
}
|
||||
|
||||
// return imported data. If the import failed the pointer is NULL anyways
|
||||
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiScene* aiImportFileFromMemory(
|
||||
const char* pBuffer,
|
||||
unsigned int pLength,
|
||||
unsigned int pFlags,
|
||||
const char* pHint)
|
||||
{
|
||||
return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiScene* aiImportFileFromMemoryWithProperties(
|
||||
const char* pBuffer,
|
||||
unsigned int pLength,
|
||||
unsigned int pFlags,
|
||||
const char* pHint,
|
||||
const aiPropertyStore* props)
|
||||
{
|
||||
ai_assert( NULL != pBuffer );
|
||||
ai_assert( 0 != pLength );
|
||||
|
||||
const aiScene* scene = NULL;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// create an Importer for this file
|
||||
Assimp::Importer* imp = new Assimp::Importer();
|
||||
|
||||
// copy properties
|
||||
if(props) {
|
||||
const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
|
||||
ImporterPimpl* pimpl = imp->Pimpl();
|
||||
pimpl->mIntProperties = pp->ints;
|
||||
pimpl->mFloatProperties = pp->floats;
|
||||
pimpl->mStringProperties = pp->strings;
|
||||
pimpl->mMatrixProperties = pp->matrices;
|
||||
}
|
||||
|
||||
// and have it read the file from the memory buffer
|
||||
scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint);
|
||||
|
||||
// if succeeded, store the importer in the scene and keep it alive
|
||||
if( scene) {
|
||||
ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
|
||||
priv->mOrigImporter = imp;
|
||||
}
|
||||
else {
|
||||
// if failed, extract error code and destroy the import
|
||||
gLastErrorString = imp->GetErrorString();
|
||||
delete imp;
|
||||
}
|
||||
// return imported data. If the import failed the pointer is NULL anyways
|
||||
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
|
||||
return scene;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Releases all resources associated with the given import process.
|
||||
void aiReleaseImport( const aiScene* pScene)
|
||||
{
|
||||
if (!pScene) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// find the importer associated with this data
|
||||
const ScenePrivateData* priv = ScenePriv(pScene);
|
||||
if( !priv || !priv->mOrigImporter) {
|
||||
delete pScene;
|
||||
}
|
||||
else {
|
||||
// deleting the Importer also deletes the scene
|
||||
// Note: the reason that this is not written as 'delete priv->mOrigImporter'
|
||||
// is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339)
|
||||
Importer* importer = priv->mOrigImporter;
|
||||
delete importer;
|
||||
}
|
||||
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene,
|
||||
unsigned int pFlags)
|
||||
{
|
||||
const aiScene* sc = NULL;
|
||||
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// find the importer associated with this data
|
||||
const ScenePrivateData* priv = ScenePriv(pScene);
|
||||
if( !priv || !priv->mOrigImporter) {
|
||||
ReportSceneNotFoundError();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sc = priv->mOrigImporter->ApplyPostProcessing(pFlags);
|
||||
|
||||
if (!sc) {
|
||||
aiReleaseImport(pScene);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
|
||||
return sc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API const aiScene *aiApplyCustomizedPostProcessing( const aiScene *scene,
|
||||
BaseProcess* process,
|
||||
bool requestValidation ) {
|
||||
const aiScene* sc( NULL );
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// find the importer associated with this data
|
||||
const ScenePrivateData* priv = ScenePriv( scene );
|
||||
if ( NULL == priv || NULL == priv->mOrigImporter ) {
|
||||
ReportSceneNotFoundError();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sc = priv->mOrigImporter->ApplyCustomizedPostProcessing( process, requestValidation );
|
||||
|
||||
if ( !sc ) {
|
||||
aiReleaseImport( scene );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ASSIMP_END_EXCEPTION_REGION( const aiScene* );
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void CallbackToLogRedirector (const char* msg, char* dt)
|
||||
{
|
||||
ai_assert( NULL != msg );
|
||||
ai_assert( NULL != dt );
|
||||
LogStream* s = (LogStream*)dt;
|
||||
|
||||
s->write(msg);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file)
|
||||
{
|
||||
aiLogStream sout;
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
LogStream* stream = LogStream::createDefaultStream(pStream,file);
|
||||
if (!stream) {
|
||||
sout.callback = NULL;
|
||||
sout.user = NULL;
|
||||
}
|
||||
else {
|
||||
sout.callback = &CallbackToLogRedirector;
|
||||
sout.user = (char*)stream;
|
||||
}
|
||||
gPredefinedStreams.push_back(stream);
|
||||
ASSIMP_END_EXCEPTION_REGION(aiLogStream);
|
||||
return sout;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiAttachLogStream( const aiLogStream* stream )
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
std::lock_guard<std::mutex> lock(gLogStreamMutex);
|
||||
#endif
|
||||
|
||||
LogStream* lg = new LogToCallbackRedirector(*stream);
|
||||
gActiveLogStreams[*stream] = lg;
|
||||
|
||||
if (DefaultLogger::isNullLogger()) {
|
||||
DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
|
||||
}
|
||||
DefaultLogger::get()->attachStream(lg);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
std::lock_guard<std::mutex> lock(gLogStreamMutex);
|
||||
#endif
|
||||
// find the log-stream associated with this data
|
||||
LogStreamMap::iterator it = gActiveLogStreams.find( *stream);
|
||||
// it should be there... else the user is playing fools with us
|
||||
if( it == gActiveLogStreams.end()) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
DefaultLogger::get()->detatchStream( it->second );
|
||||
delete it->second;
|
||||
|
||||
gActiveLogStreams.erase( it);
|
||||
|
||||
if (gActiveLogStreams.empty()) {
|
||||
DefaultLogger::kill();
|
||||
}
|
||||
ASSIMP_END_EXCEPTION_REGION(aiReturn);
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiDetachAllLogStreams(void)
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
std::lock_guard<std::mutex> lock(gLogStreamMutex);
|
||||
#endif
|
||||
Logger *logger( DefaultLogger::get() );
|
||||
if ( NULL == logger ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
|
||||
logger->detatchStream( it->second );
|
||||
delete it->second;
|
||||
}
|
||||
gActiveLogStreams.clear();
|
||||
DefaultLogger::kill();
|
||||
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiEnableVerboseLogging(aiBool d)
|
||||
{
|
||||
if (!DefaultLogger::isNullLogger()) {
|
||||
DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
|
||||
}
|
||||
gVerboseLogging = d;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns the error text of the last failed import process.
|
||||
const char* aiGetErrorString()
|
||||
{
|
||||
return gLastErrorString.c_str();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Return the description of a importer given its index
|
||||
const aiImporterDesc* aiGetImportFormatDescription( size_t pIndex)
|
||||
{
|
||||
return Importer().GetImporterInfo(pIndex);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Return the number of importers
|
||||
size_t aiGetImportFormatCount(void)
|
||||
{
|
||||
return Importer().GetImporterCount();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns the error text of the last failed import process.
|
||||
aiBool aiIsExtensionSupported(const char* szExtension)
|
||||
{
|
||||
ai_assert(NULL != szExtension);
|
||||
aiBool candoit=AI_FALSE;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// FIXME: no need to create a temporary Importer instance just for that ..
|
||||
Assimp::Importer tmp;
|
||||
candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE;
|
||||
|
||||
ASSIMP_END_EXCEPTION_REGION(aiBool);
|
||||
return candoit;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a list of all file extensions supported by ASSIMP
|
||||
void aiGetExtensionList(aiString* szOut)
|
||||
{
|
||||
ai_assert(NULL != szOut);
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// FIXME: no need to create a temporary Importer instance just for that ..
|
||||
Assimp::Importer tmp;
|
||||
tmp.GetExtensionList(*szOut);
|
||||
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get the memory requirements for a particular import.
|
||||
void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
|
||||
C_STRUCT aiMemoryInfo* in)
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// find the importer associated with this data
|
||||
const ScenePrivateData* priv = ScenePriv(pIn);
|
||||
if( !priv || !priv->mOrigImporter) {
|
||||
ReportSceneNotFoundError();
|
||||
return;
|
||||
}
|
||||
|
||||
return priv->mOrigImporter->GetMemoryRequirements(*in);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void)
|
||||
{
|
||||
return reinterpret_cast<aiPropertyStore*>( new PropertyMap() );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p)
|
||||
{
|
||||
delete reinterpret_cast<PropertyMap*>(p);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Importer::SetPropertyInteger
|
||||
ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value)
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
|
||||
SetGenericProperty<int>(pp->ints,szName,value);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Importer::SetPropertyFloat
|
||||
ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, ai_real value)
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
|
||||
SetGenericProperty<ai_real>(pp->floats,szName,value);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Importer::SetPropertyString
|
||||
ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName,
|
||||
const C_STRUCT aiString* st)
|
||||
{
|
||||
if (!st) {
|
||||
return;
|
||||
}
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
|
||||
SetGenericProperty<std::string>(pp->strings,szName,std::string(st->C_Str()));
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Importer::SetPropertyMatrix
|
||||
ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName,
|
||||
const C_STRUCT aiMatrix4x4* mat)
|
||||
{
|
||||
if (!mat) {
|
||||
return;
|
||||
}
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
|
||||
SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Rotation matrix to quaternion
|
||||
ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat)
|
||||
{
|
||||
ai_assert( NULL != quat );
|
||||
ai_assert( NULL != mat );
|
||||
*quat = aiQuaternion(*mat);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Matrix decomposition
|
||||
ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling,
|
||||
aiQuaternion* rotation,
|
||||
aiVector3D* position)
|
||||
{
|
||||
ai_assert( NULL != rotation );
|
||||
ai_assert( NULL != position );
|
||||
ai_assert( NULL != scaling );
|
||||
ai_assert( NULL != mat );
|
||||
mat->Decompose(*scaling,*rotation,*position);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Matrix transpose
|
||||
ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat)
|
||||
{
|
||||
ai_assert(NULL != mat);
|
||||
mat->Transpose();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat)
|
||||
{
|
||||
ai_assert(NULL != mat);
|
||||
mat->Transpose();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Vector transformation
|
||||
ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec,
|
||||
const aiMatrix3x3* mat)
|
||||
{
|
||||
ai_assert( NULL != mat );
|
||||
ai_assert( NULL != vec);
|
||||
*vec *= (*mat);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec,
|
||||
const aiMatrix4x4* mat)
|
||||
{
|
||||
ai_assert( NULL != mat );
|
||||
ai_assert( NULL != vec );
|
||||
|
||||
*vec *= (*mat);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Matrix multiplication
|
||||
ASSIMP_API void aiMultiplyMatrix4(
|
||||
aiMatrix4x4* dst,
|
||||
const aiMatrix4x4* src)
|
||||
{
|
||||
ai_assert( NULL != dst );
|
||||
ai_assert( NULL != src );
|
||||
*dst = (*dst) * (*src);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiMultiplyMatrix3(
|
||||
aiMatrix3x3* dst,
|
||||
const aiMatrix3x3* src)
|
||||
{
|
||||
ai_assert( NULL != dst );
|
||||
ai_assert( NULL != src );
|
||||
*dst = (*dst) * (*src);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Matrix identity
|
||||
ASSIMP_API void aiIdentityMatrix3(
|
||||
aiMatrix3x3* mat)
|
||||
{
|
||||
ai_assert(NULL != mat);
|
||||
*mat = aiMatrix3x3();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiIdentityMatrix4(
|
||||
aiMatrix4x4* mat)
|
||||
{
|
||||
ai_assert(NULL != mat);
|
||||
*mat = aiMatrix4x4();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API C_STRUCT const aiImporterDesc* aiGetImporterDesc( const char *extension ) {
|
||||
if( NULL == extension ) {
|
||||
return NULL;
|
||||
}
|
||||
const aiImporterDesc *desc( NULL );
|
||||
std::vector< BaseImporter* > out;
|
||||
GetImporterInstanceList( out );
|
||||
for( size_t i = 0; i < out.size(); ++i ) {
|
||||
if( 0 == strncmp( out[ i ]->GetInfo()->mFileExtensions, extension, strlen( extension ) ) ) {
|
||||
desc = out[ i ]->GetInfo();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DeleteImporterInstanceList(out);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
643
thirdparty/assimp/code/Common/BaseImporter.cpp
vendored
Normal file
643
thirdparty/assimp/code/Common/BaseImporter.cpp
vendored
Normal file
@@ -0,0 +1,643 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 BaseImporter.cpp
|
||||
* @brief Implementation of BaseImporter
|
||||
*/
|
||||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include "FileSystemFilter.h"
|
||||
#include "Importer.h"
|
||||
#include <assimp/ByteSwapper.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
|
||||
#include <ios>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <cctype>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
BaseImporter::BaseImporter() AI_NO_EXCEPT
|
||||
: m_progress() {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
BaseImporter::~BaseImporter() {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
void BaseImporter::UpdateImporterScale( Importer* pImp )
|
||||
{
|
||||
ai_assert(pImp != nullptr);
|
||||
ai_assert(importerScale != 0.0);
|
||||
ai_assert(fileScale != 0.0);
|
||||
|
||||
double activeScale = importerScale * fileScale;
|
||||
|
||||
// Set active scaling
|
||||
pImp->SetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, static_cast<float>( activeScale) );
|
||||
|
||||
ASSIMP_LOG_DEBUG_F("UpdateImporterScale scale set: %f", activeScale );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file and returns the imported data.
|
||||
aiScene* BaseImporter::ReadFile(Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) {
|
||||
|
||||
|
||||
m_progress = pImp->GetProgressHandler();
|
||||
if (nullptr == m_progress) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ai_assert(m_progress);
|
||||
|
||||
// Gather configuration properties for this run
|
||||
SetupProperties( pImp );
|
||||
|
||||
// Construct a file system filter to improve our success ratio at reading external files
|
||||
FileSystemFilter filter(pFile,pIOHandler);
|
||||
|
||||
// create a scene object to hold the data
|
||||
std::unique_ptr<aiScene> sc(new aiScene());
|
||||
|
||||
// dispatch importing
|
||||
try
|
||||
{
|
||||
InternReadFile( pFile, sc.get(), &filter);
|
||||
|
||||
// Calculate import scale hook - required because pImp not available anywhere else
|
||||
// passes scale into ScaleProcess
|
||||
UpdateImporterScale(pImp);
|
||||
|
||||
|
||||
} catch( const std::exception& err ) {
|
||||
// extract error description
|
||||
m_ErrorText = err.what();
|
||||
ASSIMP_LOG_ERROR(m_ErrorText);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// return what we gathered from the import.
|
||||
return sc.release();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseImporter::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
// the default implementation does nothing
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseImporter::GetExtensionList(std::set<std::string>& extensions) {
|
||||
const aiImporterDesc* desc = GetInfo();
|
||||
ai_assert(desc != nullptr);
|
||||
|
||||
const char* ext = desc->mFileExtensions;
|
||||
ai_assert(ext != nullptr );
|
||||
|
||||
const char* last = ext;
|
||||
do {
|
||||
if (!*ext || *ext == ' ') {
|
||||
extensions.insert(std::string(last,ext-last));
|
||||
ai_assert(ext-last > 0);
|
||||
last = ext;
|
||||
while(*last == ' ') {
|
||||
++last;
|
||||
}
|
||||
}
|
||||
}
|
||||
while(*ext++);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/*static*/ bool BaseImporter::SearchFileHeaderForToken( IOSystem* pIOHandler,
|
||||
const std::string& pFile,
|
||||
const char** tokens,
|
||||
unsigned int numTokens,
|
||||
unsigned int searchBytes /* = 200 */,
|
||||
bool tokensSol /* false */,
|
||||
bool noAlphaBeforeTokens /* false */)
|
||||
{
|
||||
ai_assert( nullptr != tokens );
|
||||
ai_assert( 0 != numTokens );
|
||||
ai_assert( 0 != searchBytes);
|
||||
|
||||
if ( nullptr == pIOHandler ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
|
||||
if (pStream.get() ) {
|
||||
// read 200 characters from the file
|
||||
std::unique_ptr<char[]> _buffer (new char[searchBytes+1 /* for the '\0' */]);
|
||||
char *buffer( _buffer.get() );
|
||||
const size_t read( pStream->Read(buffer,1,searchBytes) );
|
||||
if( 0 == read ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for( size_t i = 0; i < read; ++i ) {
|
||||
buffer[ i ] = static_cast<char>( ::tolower( buffer[ i ] ) );
|
||||
}
|
||||
|
||||
// It is not a proper handling of unicode files here ...
|
||||
// ehm ... but it works in most cases.
|
||||
char* cur = buffer,*cur2 = buffer,*end = &buffer[read];
|
||||
while (cur != end) {
|
||||
if( *cur ) {
|
||||
*cur2++ = *cur;
|
||||
}
|
||||
++cur;
|
||||
}
|
||||
*cur2 = '\0';
|
||||
|
||||
std::string token;
|
||||
for (unsigned int i = 0; i < numTokens; ++i ) {
|
||||
ai_assert( nullptr != tokens[i] );
|
||||
const size_t len( strlen( tokens[ i ] ) );
|
||||
token.clear();
|
||||
const char *ptr( tokens[ i ] );
|
||||
for ( size_t tokIdx = 0; tokIdx < len; ++tokIdx ) {
|
||||
token.push_back( static_cast<char>( tolower( *ptr ) ) );
|
||||
++ptr;
|
||||
}
|
||||
const char* r = strstr( buffer, token.c_str() );
|
||||
if( !r ) {
|
||||
continue;
|
||||
}
|
||||
// We need to make sure that we didn't accidentially identify the end of another token as our token,
|
||||
// e.g. in a previous version the "gltf " present in some gltf files was detected as "f "
|
||||
if (noAlphaBeforeTokens && (r != buffer && isalpha(r[-1]))) {
|
||||
continue;
|
||||
}
|
||||
// We got a match, either we don't care where it is, or it happens to
|
||||
// be in the beginning of the file / line
|
||||
if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') {
|
||||
ASSIMP_LOG_DEBUG_F( "Found positive match for header keyword: ", tokens[i] );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Simple check for file extension
|
||||
/*static*/ bool BaseImporter::SimpleExtensionCheck (const std::string& pFile,
|
||||
const char* ext0,
|
||||
const char* ext1,
|
||||
const char* ext2)
|
||||
{
|
||||
std::string::size_type pos = pFile.find_last_of('.');
|
||||
|
||||
// no file extension - can't read
|
||||
if( pos == std::string::npos)
|
||||
return false;
|
||||
|
||||
const char* ext_real = & pFile[ pos+1 ];
|
||||
if( !ASSIMP_stricmp(ext_real,ext0) )
|
||||
return true;
|
||||
|
||||
// check for other, optional, file extensions
|
||||
if (ext1 && !ASSIMP_stricmp(ext_real,ext1))
|
||||
return true;
|
||||
|
||||
if (ext2 && !ASSIMP_stricmp(ext_real,ext2))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get file extension from path
|
||||
std::string BaseImporter::GetExtension( const std::string& file ) {
|
||||
std::string::size_type pos = file.find_last_of('.');
|
||||
|
||||
// no file extension at all
|
||||
if (pos == std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
// thanks to Andy Maloney for the hint
|
||||
std::string ret = file.substr( pos + 1 );
|
||||
std::transform( ret.begin(), ret.end(), ret.begin(), ToLower<char>);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check for magic bytes at the beginning of the file.
|
||||
/* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile,
|
||||
const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
|
||||
{
|
||||
ai_assert( size <= 16 );
|
||||
ai_assert( _magic );
|
||||
|
||||
if (!pIOHandler) {
|
||||
return false;
|
||||
}
|
||||
union {
|
||||
const char* magic;
|
||||
const uint16_t* magic_u16;
|
||||
const uint32_t* magic_u32;
|
||||
};
|
||||
magic = reinterpret_cast<const char*>(_magic);
|
||||
std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
|
||||
if (pStream.get() ) {
|
||||
|
||||
// skip to offset
|
||||
pStream->Seek(offset,aiOrigin_SET);
|
||||
|
||||
// read 'size' characters from the file
|
||||
union {
|
||||
char data[16];
|
||||
uint16_t data_u16[8];
|
||||
uint32_t data_u32[4];
|
||||
};
|
||||
if(size != pStream->Read(data,1,size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < num; ++i) {
|
||||
// also check against big endian versions of tokens with size 2,4
|
||||
// that's just for convenience, the chance that we cause conflicts
|
||||
// is quite low and it can save some lines and prevent nasty bugs
|
||||
if (2 == size) {
|
||||
uint16_t rev = *magic_u16;
|
||||
ByteSwap::Swap(&rev);
|
||||
if (data_u16[0] == *magic_u16 || data_u16[0] == rev) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (4 == size) {
|
||||
uint32_t rev = *magic_u32;
|
||||
ByteSwap::Swap(&rev);
|
||||
if (data_u32[0] == *magic_u32 || data_u32[0] == rev) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// any length ... just compare
|
||||
if(!memcmp(magic,data,size)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
magic += size;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ASSIMP_USE_HUNTER
|
||||
# include <utf8/utf8.h>
|
||||
#else
|
||||
# include "../contrib/utf8cpp/source/utf8.h"
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert to UTF8 data
|
||||
void BaseImporter::ConvertToUTF8(std::vector<char>& data)
|
||||
{
|
||||
//ConversionResult result;
|
||||
if(data.size() < 8) {
|
||||
throw DeadlyImportError("File is too small");
|
||||
}
|
||||
|
||||
// UTF 8 with BOM
|
||||
if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) {
|
||||
ASSIMP_LOG_DEBUG("Found UTF-8 BOM ...");
|
||||
|
||||
std::copy(data.begin()+3,data.end(),data.begin());
|
||||
data.resize(data.size()-3);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// UTF 32 BE with BOM
|
||||
if(*((uint32_t*)&data.front()) == 0xFFFE0000) {
|
||||
|
||||
// swap the endianness ..
|
||||
for(uint32_t* p = (uint32_t*)&data.front(), *end = (uint32_t*)&data.back(); p <= end; ++p) {
|
||||
AI_SWAP4P(p);
|
||||
}
|
||||
}
|
||||
|
||||
// UTF 32 LE with BOM
|
||||
if(*((uint32_t*)&data.front()) == 0x0000FFFE) {
|
||||
ASSIMP_LOG_DEBUG("Found UTF-32 BOM ...");
|
||||
|
||||
std::vector<char> output;
|
||||
int *ptr = (int*)&data[ 0 ];
|
||||
int *end = ptr + ( data.size() / sizeof(int) ) +1;
|
||||
utf8::utf32to8( ptr, end, back_inserter(output));
|
||||
return;
|
||||
}
|
||||
|
||||
// UTF 16 BE with BOM
|
||||
if(*((uint16_t*)&data.front()) == 0xFFFE) {
|
||||
|
||||
// swap the endianness ..
|
||||
for(uint16_t* p = (uint16_t*)&data.front(), *end = (uint16_t*)&data.back(); p <= end; ++p) {
|
||||
ByteSwap::Swap2(p);
|
||||
}
|
||||
}
|
||||
|
||||
// UTF 16 LE with BOM
|
||||
if(*((uint16_t*)&data.front()) == 0xFEFF) {
|
||||
ASSIMP_LOG_DEBUG("Found UTF-16 BOM ...");
|
||||
|
||||
std::vector<unsigned char> output;
|
||||
utf8::utf16to8(data.begin(), data.end(), back_inserter(output));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert to UTF8 data to ISO-8859-1
|
||||
void BaseImporter::ConvertUTF8toISO8859_1(std::string& data)
|
||||
{
|
||||
size_t size = data.size();
|
||||
size_t i = 0, j = 0;
|
||||
|
||||
while(i < size) {
|
||||
if ((unsigned char) data[i] < (size_t) 0x80) {
|
||||
data[j] = data[i];
|
||||
} else if(i < size - 1) {
|
||||
if((unsigned char) data[i] == 0xC2) {
|
||||
data[j] = data[++i];
|
||||
} else if((unsigned char) data[i] == 0xC3) {
|
||||
data[j] = ((unsigned char) data[++i] + 0x40);
|
||||
} else {
|
||||
std::stringstream stream;
|
||||
stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1.";
|
||||
ASSIMP_LOG_ERROR( stream.str() );
|
||||
|
||||
data[j++] = data[i++];
|
||||
data[j] = data[i];
|
||||
}
|
||||
} else {
|
||||
ASSIMP_LOG_ERROR("UTF8 code but only one character remaining");
|
||||
|
||||
data[j] = data[i];
|
||||
}
|
||||
|
||||
i++; j++;
|
||||
}
|
||||
|
||||
data.resize(j);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseImporter::TextFileToBuffer(IOStream* stream,
|
||||
std::vector<char>& data,
|
||||
TextFileMode mode)
|
||||
{
|
||||
ai_assert(nullptr != stream);
|
||||
|
||||
const size_t fileSize = stream->FileSize();
|
||||
if (mode == FORBID_EMPTY) {
|
||||
if(!fileSize) {
|
||||
throw DeadlyImportError("File is empty");
|
||||
}
|
||||
}
|
||||
|
||||
data.reserve(fileSize+1);
|
||||
data.resize(fileSize);
|
||||
if(fileSize > 0) {
|
||||
if(fileSize != stream->Read( &data[0], 1, fileSize)) {
|
||||
throw DeadlyImportError("File read error");
|
||||
}
|
||||
|
||||
ConvertToUTF8(data);
|
||||
}
|
||||
|
||||
// append a binary zero to simplify string parsing
|
||||
data.push_back(0);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace Assimp {
|
||||
// Represents an import request
|
||||
struct LoadRequest {
|
||||
LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id)
|
||||
: file(_file)
|
||||
, flags(_flags)
|
||||
, refCnt(1)
|
||||
, scene(NULL)
|
||||
, loaded(false)
|
||||
, id(_id) {
|
||||
if ( _map ) {
|
||||
map = *_map;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator== ( const std::string& f ) const {
|
||||
return file == f;
|
||||
}
|
||||
|
||||
const std::string file;
|
||||
unsigned int flags;
|
||||
unsigned int refCnt;
|
||||
aiScene *scene;
|
||||
bool loaded;
|
||||
BatchLoader::PropertyMap map;
|
||||
unsigned int id;
|
||||
};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// BatchLoader::pimpl data structure
|
||||
struct Assimp::BatchData {
|
||||
BatchData( IOSystem* pIO, bool validate )
|
||||
: pIOSystem( pIO )
|
||||
, pImporter( nullptr )
|
||||
, next_id(0xffff)
|
||||
, validate( validate ) {
|
||||
ai_assert( nullptr != pIO );
|
||||
|
||||
pImporter = new Importer();
|
||||
pImporter->SetIOHandler( pIO );
|
||||
}
|
||||
|
||||
~BatchData() {
|
||||
pImporter->SetIOHandler( nullptr ); /* get pointer back into our possession */
|
||||
delete pImporter;
|
||||
}
|
||||
|
||||
// IO system to be used for all imports
|
||||
IOSystem* pIOSystem;
|
||||
|
||||
// Importer used to load all meshes
|
||||
Importer* pImporter;
|
||||
|
||||
// List of all imports
|
||||
std::list<LoadRequest> requests;
|
||||
|
||||
// Base path
|
||||
std::string pathBase;
|
||||
|
||||
// Id for next item
|
||||
unsigned int next_id;
|
||||
|
||||
// Validation enabled state
|
||||
bool validate;
|
||||
};
|
||||
|
||||
typedef std::list<LoadRequest>::iterator LoadReqIt;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BatchLoader::BatchLoader(IOSystem* pIO, bool validate ) {
|
||||
ai_assert(nullptr != pIO);
|
||||
|
||||
m_data = new BatchData( pIO, validate );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BatchLoader::~BatchLoader()
|
||||
{
|
||||
// delete all scenes what have not been polled by the user
|
||||
for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) {
|
||||
delete (*it).scene;
|
||||
}
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BatchLoader::setValidation( bool enabled ) {
|
||||
m_data->validate = enabled;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool BatchLoader::getValidation() const {
|
||||
return m_data->validate;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int BatchLoader::AddLoadRequest(const std::string& file,
|
||||
unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/)
|
||||
{
|
||||
ai_assert(!file.empty());
|
||||
|
||||
// check whether we have this loading request already
|
||||
for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) {
|
||||
// Call IOSystem's path comparison function here
|
||||
if ( m_data->pIOSystem->ComparePaths((*it).file,file)) {
|
||||
if (map) {
|
||||
if ( !( ( *it ).map == *map ) ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if ( !( *it ).map.empty() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(*it).refCnt++;
|
||||
return (*it).id;
|
||||
}
|
||||
}
|
||||
|
||||
// no, we don't have it. So add it to the queue ...
|
||||
m_data->requests.push_back(LoadRequest(file,steps,map, m_data->next_id));
|
||||
return m_data->next_id++;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiScene* BatchLoader::GetImport( unsigned int which )
|
||||
{
|
||||
for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) {
|
||||
if ((*it).id == which && (*it).loaded) {
|
||||
aiScene* sc = (*it).scene;
|
||||
if (!(--(*it).refCnt)) {
|
||||
m_data->requests.erase(it);
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BatchLoader::LoadAll()
|
||||
{
|
||||
// no threaded implementation for the moment
|
||||
for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) {
|
||||
// force validation in debug builds
|
||||
unsigned int pp = (*it).flags;
|
||||
if ( m_data->validate ) {
|
||||
pp |= aiProcess_ValidateDataStructure;
|
||||
}
|
||||
|
||||
// setup config properties if necessary
|
||||
ImporterPimpl* pimpl = m_data->pImporter->Pimpl();
|
||||
pimpl->mFloatProperties = (*it).map.floats;
|
||||
pimpl->mIntProperties = (*it).map.ints;
|
||||
pimpl->mStringProperties = (*it).map.strings;
|
||||
pimpl->mMatrixProperties = (*it).map.matrices;
|
||||
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
{
|
||||
ASSIMP_LOG_INFO("%%% BEGIN EXTERNAL FILE %%%");
|
||||
ASSIMP_LOG_INFO_F("File: ", (*it).file);
|
||||
}
|
||||
m_data->pImporter->ReadFile((*it).file,pp);
|
||||
(*it).scene = m_data->pImporter->GetOrphanedScene();
|
||||
(*it).loaded = true;
|
||||
|
||||
ASSIMP_LOG_INFO("%%% END EXTERNAL FILE %%%");
|
||||
}
|
||||
}
|
||||
107
thirdparty/assimp/code/Common/BaseProcess.cpp
vendored
Normal file
107
thirdparty/assimp/code/Common/BaseProcess.cpp
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 Implementation of BaseProcess */
|
||||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include "BaseProcess.h"
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include "Importer.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
BaseProcess::BaseProcess() AI_NO_EXCEPT
|
||||
: shared()
|
||||
, progress()
|
||||
{
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
BaseProcess::~BaseProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseProcess::ExecuteOnScene( Importer* pImp)
|
||||
{
|
||||
ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene);
|
||||
|
||||
progress = pImp->GetProgressHandler();
|
||||
ai_assert(progress);
|
||||
|
||||
SetupProperties( pImp );
|
||||
|
||||
// catch exceptions thrown inside the PostProcess-Step
|
||||
try
|
||||
{
|
||||
Execute(pImp->Pimpl()->mScene);
|
||||
|
||||
} catch( const std::exception& err ) {
|
||||
|
||||
// extract error description
|
||||
pImp->Pimpl()->mErrorString = err.what();
|
||||
ASSIMP_LOG_ERROR(pImp->Pimpl()->mErrorString);
|
||||
|
||||
// and kill the partially imported data
|
||||
delete pImp->Pimpl()->mScene;
|
||||
pImp->Pimpl()->mScene = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseProcess::SetupProperties(const Importer* /*pImp*/)
|
||||
{
|
||||
// the default implementation does nothing
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool BaseProcess::RequireVerboseFormat() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
290
thirdparty/assimp/code/Common/BaseProcess.h
vendored
Normal file
290
thirdparty/assimp/code/Common/BaseProcess.h
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
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 Base class of all import post processing steps */
|
||||
#ifndef INCLUDED_AI_BASEPROCESS_H
|
||||
#define INCLUDED_AI_BASEPROCESS_H
|
||||
|
||||
#include <map>
|
||||
#include <assimp/GenericProperty.h>
|
||||
|
||||
struct aiScene;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
class Importer;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper class to allow post-processing steps to interact with each other.
|
||||
*
|
||||
* The class maintains a simple property list that can be used by pp-steps
|
||||
* to provide additional information to other steps. This is primarily
|
||||
* intended for cross-step optimizations.
|
||||
*/
|
||||
class SharedPostProcessInfo
|
||||
{
|
||||
public:
|
||||
|
||||
struct Base
|
||||
{
|
||||
virtual ~Base()
|
||||
{}
|
||||
};
|
||||
|
||||
//! Represents data that is allocated on the heap, thus needs to be deleted
|
||||
template <typename T>
|
||||
struct THeapData : public Base
|
||||
{
|
||||
explicit THeapData(T* in)
|
||||
: data (in)
|
||||
{}
|
||||
|
||||
~THeapData()
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
T* data;
|
||||
};
|
||||
|
||||
//! Represents static, by-value data not allocated on the heap
|
||||
template <typename T>
|
||||
struct TStaticData : public Base
|
||||
{
|
||||
explicit TStaticData(T in)
|
||||
: data (in)
|
||||
{}
|
||||
|
||||
~TStaticData()
|
||||
{}
|
||||
|
||||
T data;
|
||||
};
|
||||
|
||||
// some typedefs for cleaner code
|
||||
typedef unsigned int KeyType;
|
||||
typedef std::map<KeyType, Base*> PropertyMap;
|
||||
|
||||
public:
|
||||
|
||||
//! Destructor
|
||||
~SharedPostProcessInfo()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
|
||||
//! Remove all stored properties from the table
|
||||
void Clean()
|
||||
{
|
||||
// invoke the virtual destructor for all stored properties
|
||||
for (PropertyMap::iterator it = pmap.begin(), end = pmap.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
delete (*it).second;
|
||||
}
|
||||
pmap.clear();
|
||||
}
|
||||
|
||||
//! Add a heap property to the list
|
||||
template <typename T>
|
||||
void AddProperty( const char* name, T* in ){
|
||||
AddProperty(name,(Base*)new THeapData<T>(in));
|
||||
}
|
||||
|
||||
//! Add a static by-value property to the list
|
||||
template <typename T>
|
||||
void AddProperty( const char* name, T in ){
|
||||
AddProperty(name,(Base*)new TStaticData<T>(in));
|
||||
}
|
||||
|
||||
|
||||
//! Get a heap property
|
||||
template <typename T>
|
||||
bool GetProperty( const char* name, T*& out ) const
|
||||
{
|
||||
THeapData<T>* t = (THeapData<T>*)GetPropertyInternal(name);
|
||||
if(!t)
|
||||
{
|
||||
out = NULL;
|
||||
return false;
|
||||
}
|
||||
out = t->data;
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Get a static, by-value property
|
||||
template <typename T>
|
||||
bool GetProperty( const char* name, T& out ) const
|
||||
{
|
||||
TStaticData<T>* t = (TStaticData<T>*)GetPropertyInternal(name);
|
||||
if(!t)return false;
|
||||
out = t->data;
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Remove a property of a specific type
|
||||
void RemoveProperty( const char* name) {
|
||||
SetGenericPropertyPtr<Base>(pmap,name,NULL);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void AddProperty( const char* name, Base* data) {
|
||||
SetGenericPropertyPtr<Base>(pmap,name,data);
|
||||
}
|
||||
|
||||
Base* GetPropertyInternal( const char* name) const {
|
||||
return GetGenericProperty<Base*>(pmap,name,NULL);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//! Map of all stored properties
|
||||
PropertyMap pmap;
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief Represents a dependency table for a postprocessing steps.
|
||||
*
|
||||
* For future use.
|
||||
*/
|
||||
struct PPDependencyTable
|
||||
{
|
||||
unsigned int execute_me_before_these;
|
||||
unsigned int execute_me_after_these;
|
||||
unsigned int only_if_these_are_not_specified;
|
||||
unsigned int mutually_exclusive_with;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define AI_SPP_SPATIAL_SORT "$Spat"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** The BaseProcess defines a common interface for all post processing steps.
|
||||
* A post processing step is run after a successful import if the caller
|
||||
* specified the corresponding flag when calling ReadFile().
|
||||
* Enum #aiPostProcessSteps defines which flags are available.
|
||||
* After a successful import the Importer iterates over its internal array
|
||||
* of processes and calls IsActive() on each process to evaluate if the step
|
||||
* should be executed. If the function returns true, the class' Execute()
|
||||
* function is called subsequently.
|
||||
*/
|
||||
class ASSIMP_API_WINONLY BaseProcess {
|
||||
friend class Importer;
|
||||
|
||||
public:
|
||||
/** Constructor to be privately used by Importer */
|
||||
BaseProcess() AI_NO_EXCEPT;
|
||||
|
||||
/** Destructor, private as well */
|
||||
virtual ~BaseProcess();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
* @param pFlags The processing flags the importer was called with. A
|
||||
* bitwise combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields,
|
||||
* false if not.
|
||||
*/
|
||||
virtual bool IsActive( unsigned int pFlags) const = 0;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Check whether this step expects its input vertex data to be
|
||||
* in verbose format. */
|
||||
virtual bool RequireVerboseFormat() const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* The function deletes the scene if the postprocess step fails (
|
||||
* the object pointer will be set to NULL).
|
||||
* @param pImp Importer instance (pImp->mScene must be valid)
|
||||
*/
|
||||
void ExecuteOnScene( Importer* pImp);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
virtual void SetupProperties(const Importer* pImp);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* A process should throw an ImportErrorException* if it fails.
|
||||
* This method must be implemented by deriving classes.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
virtual void Execute( aiScene* pScene) = 0;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Assign a new SharedPostProcessInfo to the step. This object
|
||||
* allows multiple postprocess steps to share data.
|
||||
* @param sh May be NULL
|
||||
*/
|
||||
inline void SetSharedData(SharedPostProcessInfo* sh) {
|
||||
shared = sh;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get the shared data that is assigned to the step.
|
||||
*/
|
||||
inline SharedPostProcessInfo* GetSharedData() {
|
||||
return shared;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/** See the doc of #SharedPostProcessInfo for more details */
|
||||
SharedPostProcessInfo* shared;
|
||||
|
||||
/** Currently active progress handler */
|
||||
ProgressHandler* progress;
|
||||
};
|
||||
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // AI_BASEPROCESS_H_INC
|
||||
155
thirdparty/assimp/code/Common/Bitmap.cpp
vendored
Normal file
155
thirdparty/assimp/code/Common/Bitmap.cpp
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 Bitmap.cpp
|
||||
* @brief Defines bitmap format helper for textures
|
||||
*
|
||||
* Used for file formats which embed their textures into the model file.
|
||||
*/
|
||||
|
||||
|
||||
#include <assimp/Bitmap.h>
|
||||
#include <assimp/texture.h>
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/ByteSwapper.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
void Bitmap::Save(aiTexture* texture, IOStream* file) {
|
||||
if(file != NULL) {
|
||||
Header header;
|
||||
DIB dib;
|
||||
|
||||
dib.size = DIB::dib_size;
|
||||
dib.width = texture->mWidth;
|
||||
dib.height = texture->mHeight;
|
||||
dib.planes = 1;
|
||||
dib.bits_per_pixel = 8 * mBytesPerPixel;
|
||||
dib.compression = 0;
|
||||
dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height;
|
||||
dib.x_resolution = 0;
|
||||
dib.y_resolution = 0;
|
||||
dib.nb_colors = 0;
|
||||
dib.nb_important_colors = 0;
|
||||
|
||||
header.type = 0x4D42; // 'BM'
|
||||
header.offset = Header::header_size + DIB::dib_size;
|
||||
header.size = header.offset + dib.image_size;
|
||||
header.reserved1 = 0;
|
||||
header.reserved2 = 0;
|
||||
|
||||
WriteHeader(header, file);
|
||||
WriteDIB(dib, file);
|
||||
WriteData(texture, file);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
std::size_t Copy(uint8_t* data, const T &field) {
|
||||
#ifdef AI_BUILD_BIG_ENDIAN
|
||||
T field_swapped=AI_BE(field);
|
||||
std::memcpy(data, &field_swapped, sizeof(field)); return sizeof(field);
|
||||
#else
|
||||
std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Bitmap::WriteHeader(Header& header, IOStream* file) {
|
||||
uint8_t data[Header::header_size];
|
||||
|
||||
std::size_t offset = 0;
|
||||
|
||||
offset += Copy(&data[offset], header.type);
|
||||
offset += Copy(&data[offset], header.size);
|
||||
offset += Copy(&data[offset], header.reserved1);
|
||||
offset += Copy(&data[offset], header.reserved2);
|
||||
Copy(&data[offset], header.offset);
|
||||
|
||||
file->Write(data, Header::header_size, 1);
|
||||
}
|
||||
|
||||
void Bitmap::WriteDIB(DIB& dib, IOStream* file) {
|
||||
uint8_t data[DIB::dib_size];
|
||||
|
||||
std::size_t offset = 0;
|
||||
|
||||
offset += Copy(&data[offset], dib.size);
|
||||
offset += Copy(&data[offset], dib.width);
|
||||
offset += Copy(&data[offset], dib.height);
|
||||
offset += Copy(&data[offset], dib.planes);
|
||||
offset += Copy(&data[offset], dib.bits_per_pixel);
|
||||
offset += Copy(&data[offset], dib.compression);
|
||||
offset += Copy(&data[offset], dib.image_size);
|
||||
offset += Copy(&data[offset], dib.x_resolution);
|
||||
offset += Copy(&data[offset], dib.y_resolution);
|
||||
offset += Copy(&data[offset], dib.nb_colors);
|
||||
Copy(&data[offset], dib.nb_important_colors);
|
||||
|
||||
file->Write(data, DIB::dib_size, 1);
|
||||
}
|
||||
|
||||
void Bitmap::WriteData(aiTexture* texture, IOStream* file) {
|
||||
static const std::size_t padding_offset = 4;
|
||||
static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0};
|
||||
|
||||
unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset;
|
||||
uint8_t pixel[mBytesPerPixel];
|
||||
|
||||
for(std::size_t i = 0; i < texture->mHeight; ++i) {
|
||||
for(std::size_t j = 0; j < texture->mWidth; ++j) {
|
||||
const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format
|
||||
|
||||
pixel[0] = texel.r;
|
||||
pixel[1] = texel.g;
|
||||
pixel[2] = texel.b;
|
||||
pixel[3] = texel.a;
|
||||
|
||||
file->Write(pixel, mBytesPerPixel, 1);
|
||||
}
|
||||
|
||||
file->Write(padding_data, padding, 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
88
thirdparty/assimp/code/Common/CreateAnimMesh.cpp
vendored
Normal file
88
thirdparty/assimp/code/Common/CreateAnimMesh.cpp
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2016 The Qt Company Ltd.
|
||||
Copyright (c) 2006-2012, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <assimp/CreateAnimMesh.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh)
|
||||
{
|
||||
aiAnimMesh *animesh = new aiAnimMesh;
|
||||
animesh->mNumVertices = mesh->mNumVertices;
|
||||
if (mesh->mVertices) {
|
||||
animesh->mVertices = new aiVector3D[animesh->mNumVertices];
|
||||
std::memcpy(animesh->mVertices, mesh->mVertices, mesh->mNumVertices * sizeof(aiVector3D));
|
||||
}
|
||||
if (mesh->mNormals) {
|
||||
animesh->mNormals = new aiVector3D[animesh->mNumVertices];
|
||||
std::memcpy(animesh->mNormals, mesh->mNormals, mesh->mNumVertices * sizeof(aiVector3D));
|
||||
}
|
||||
if (mesh->mTangents) {
|
||||
animesh->mTangents = new aiVector3D[animesh->mNumVertices];
|
||||
std::memcpy(animesh->mTangents, mesh->mTangents, mesh->mNumVertices * sizeof(aiVector3D));
|
||||
}
|
||||
if (mesh->mBitangents) {
|
||||
animesh->mBitangents = new aiVector3D[animesh->mNumVertices];
|
||||
std::memcpy(animesh->mBitangents, mesh->mBitangents, mesh->mNumVertices * sizeof(aiVector3D));
|
||||
}
|
||||
|
||||
for (int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
|
||||
if (mesh->mColors[i]) {
|
||||
animesh->mColors[i] = new aiColor4D[animesh->mNumVertices];
|
||||
std::memcpy(animesh->mColors[i], mesh->mColors[i], mesh->mNumVertices * sizeof(aiColor4D));
|
||||
} else {
|
||||
animesh->mColors[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
if (mesh->mTextureCoords[i]) {
|
||||
animesh->mTextureCoords[i] = new aiVector3D[animesh->mNumVertices];
|
||||
std::memcpy(animesh->mTextureCoords[i], mesh->mTextureCoords[i], mesh->mNumVertices * sizeof(aiVector3D));
|
||||
} else {
|
||||
animesh->mTextureCoords[i] = NULL;
|
||||
}
|
||||
}
|
||||
return animesh;
|
||||
}
|
||||
|
||||
} // end of namespace Assimp
|
||||
154
thirdparty/assimp/code/Common/DefaultIOStream.cpp
vendored
Normal file
154
thirdparty/assimp/code/Common/DefaultIOStream.cpp
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 DefaultIOStream.cpp
|
||||
* @brief Default File I/O implementation for #Importer
|
||||
*/
|
||||
|
||||
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/DefaultIOStream.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
DefaultIOStream::~DefaultIOStream()
|
||||
{
|
||||
if (mFile) {
|
||||
::fclose(mFile);
|
||||
mFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
size_t DefaultIOStream::Read(void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount)
|
||||
{
|
||||
ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
|
||||
return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
size_t DefaultIOStream::Write(const void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount)
|
||||
{
|
||||
ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
|
||||
return (mFile ? ::fwrite(pvBuffer, pSize, pCount, mFile) : 0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
aiReturn DefaultIOStream::Seek(size_t pOffset,
|
||||
aiOrigin pOrigin)
|
||||
{
|
||||
if (!mFile) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
// Just to check whether our enum maps one to one with the CRT constants
|
||||
static_assert(aiOrigin_CUR == SEEK_CUR &&
|
||||
aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET, "aiOrigin_CUR == SEEK_CUR && \
|
||||
aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET");
|
||||
|
||||
// do the seek
|
||||
return (0 == ::fseek(mFile, (long)pOffset,(int)pOrigin) ? AI_SUCCESS : AI_FAILURE);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
size_t DefaultIOStream::Tell() const
|
||||
{
|
||||
if (!mFile) {
|
||||
return 0;
|
||||
}
|
||||
return ::ftell(mFile);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
size_t DefaultIOStream::FileSize() const
|
||||
{
|
||||
if (! mFile || mFilename.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (SIZE_MAX == mCachedSize ) {
|
||||
|
||||
// Although fseek/ftell would allow us to reuse the existing file handle here,
|
||||
// it is generally unsafe because:
|
||||
// - For binary streams, it is not technically well-defined
|
||||
// - For text files the results are meaningless
|
||||
// That's why we use the safer variant fstat here.
|
||||
//
|
||||
// See here for details:
|
||||
// https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file
|
||||
#if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601)
|
||||
struct __stat64 fileStat;
|
||||
//using fileno + fstat avoids having to handle the filename
|
||||
int err = _fstat64( _fileno(mFile), &fileStat );
|
||||
if (0 != err)
|
||||
return 0;
|
||||
mCachedSize = (size_t) (fileStat.st_size);
|
||||
#elif defined __GNUC__ || defined __APPLE__ || defined __MACH__ || defined __FreeBSD__
|
||||
struct stat fileStat;
|
||||
int err = stat(mFilename.c_str(), &fileStat );
|
||||
if (0 != err)
|
||||
return 0;
|
||||
const unsigned long long cachedSize = fileStat.st_size;
|
||||
mCachedSize = static_cast< size_t >( cachedSize );
|
||||
#else
|
||||
# error "Unknown platform"
|
||||
#endif
|
||||
}
|
||||
return mCachedSize;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void DefaultIOStream::Flush()
|
||||
{
|
||||
if (mFile) {
|
||||
::fflush(mFile);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
216
thirdparty/assimp/code/Common/DefaultIOSystem.cpp
vendored
Normal file
216
thirdparty/assimp/code/Common/DefaultIOSystem.cpp
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 Default implementation of IOSystem using the standard C file functions */
|
||||
|
||||
#include <assimp/StringComparison.h>
|
||||
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
#include <assimp/DefaultIOStream.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __unix__
|
||||
#include <sys/param.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
#ifdef _WIN32
|
||||
static std::wstring Utf8ToWide(const char* in)
|
||||
{
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, in, -1, nullptr, 0);
|
||||
// size includes terminating null; std::wstring adds null automatically
|
||||
std::wstring out(static_cast<size_t>(size) - 1, L'\0');
|
||||
MultiByteToWideChar(CP_UTF8, 0, in, -1, &out[0], size);
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::string WideToUtf8(const wchar_t* in)
|
||||
{
|
||||
int size = WideCharToMultiByte(CP_UTF8, 0, in, -1, nullptr, 0, nullptr, nullptr);
|
||||
// size includes terminating null; std::string adds null automatically
|
||||
std::string out(static_cast<size_t>(size) - 1, '\0');
|
||||
WideCharToMultiByte(CP_UTF8, 0, in, -1, &out[0], size, nullptr, nullptr);
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Tests for the existence of a file at the given path.
|
||||
bool DefaultIOSystem::Exists(const char* pFile) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
struct __stat64 filestat;
|
||||
if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
FILE* file = ::fopen(pFile, "rb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
::fclose(file);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Open a new file with a given path.
|
||||
IOStream* DefaultIOSystem::Open(const char* strFile, const char* strMode)
|
||||
{
|
||||
ai_assert(strFile != nullptr);
|
||||
ai_assert(strMode != nullptr);
|
||||
FILE* file;
|
||||
#ifdef _WIN32
|
||||
file = ::_wfopen(Utf8ToWide(strFile).c_str(), Utf8ToWide(strMode).c_str());
|
||||
#else
|
||||
file = ::fopen(strFile, strMode);
|
||||
#endif
|
||||
if (!file)
|
||||
return nullptr;
|
||||
|
||||
return new DefaultIOStream(file, strFile);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Closes the given file and releases all resources associated with it.
|
||||
void DefaultIOSystem::Close(IOStream* pFile)
|
||||
{
|
||||
delete pFile;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns the operation specific directory separator
|
||||
char DefaultIOSystem::getOsSeparator() const
|
||||
{
|
||||
#ifndef _WIN32
|
||||
return '/';
|
||||
#else
|
||||
return '\\';
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// IOSystem default implementation (ComparePaths isn't a pure virtual function)
|
||||
bool IOSystem::ComparePaths(const char* one, const char* second) const
|
||||
{
|
||||
return !ASSIMP_stricmp(one, second);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a relative path into an absolute path
|
||||
inline static std::string MakeAbsolutePath(const char* in)
|
||||
{
|
||||
ai_assert(in);
|
||||
std::string out;
|
||||
#ifdef _WIN32
|
||||
wchar_t* ret = ::_wfullpath(nullptr, Utf8ToWide(in).c_str(), 0);
|
||||
if (ret) {
|
||||
out = WideToUtf8(ret);
|
||||
free(ret);
|
||||
}
|
||||
#else
|
||||
char* ret = realpath(in, nullptr);
|
||||
if (ret) {
|
||||
out = ret;
|
||||
free(ret);
|
||||
}
|
||||
#endif
|
||||
if (!ret) {
|
||||
// preserve the input path, maybe someone else is able to fix
|
||||
// the path before it is accessed (e.g. our file system filter)
|
||||
ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in));
|
||||
out = in;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// DefaultIOSystem's more specialized implementation
|
||||
bool DefaultIOSystem::ComparePaths(const char* one, const char* second) const
|
||||
{
|
||||
// chances are quite good both paths are formatted identically,
|
||||
// so we can hopefully return here already
|
||||
if (!ASSIMP_stricmp(one, second))
|
||||
return true;
|
||||
|
||||
std::string temp1 = MakeAbsolutePath(one);
|
||||
std::string temp2 = MakeAbsolutePath(second);
|
||||
|
||||
return !ASSIMP_stricmp(temp1, temp2);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string DefaultIOSystem::fileName(const std::string& path)
|
||||
{
|
||||
std::string ret = path;
|
||||
std::size_t last = ret.find_last_of("\\/");
|
||||
if (last != std::string::npos) ret = ret.substr(last + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string DefaultIOSystem::completeBaseName(const std::string& path)
|
||||
{
|
||||
std::string ret = fileName(path);
|
||||
std::size_t pos = ret.find_last_of('.');
|
||||
if (pos != std::string::npos) ret = ret.substr(0, pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string DefaultIOSystem::absolutePath(const std::string& path)
|
||||
{
|
||||
std::string ret = path;
|
||||
std::size_t last = ret.find_last_of("\\/");
|
||||
if (last != std::string::npos) ret = ret.substr(0, last);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
418
thirdparty/assimp/code/Common/DefaultLogger.cpp
vendored
Normal file
418
thirdparty/assimp/code/Common/DefaultLogger.cpp
vendored
Normal file
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 DefaultLogger.cpp
|
||||
* @brief Implementation of DefaultLogger (and Logger)
|
||||
*/
|
||||
|
||||
// Default log streams
|
||||
#include "Win32DebugLogStream.h"
|
||||
#include "StdOStreamLogStream.h"
|
||||
#include "FileLogStream.h"
|
||||
#include <assimp/StringUtils.h>
|
||||
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
#include <assimp/NullLogger.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
# include <thread>
|
||||
# include <mutex>
|
||||
std::mutex loggerMutex;
|
||||
#endif
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
NullLogger DefaultLogger::s_pNullLogger;
|
||||
Logger *DefaultLogger::m_pLogger = &DefaultLogger::s_pNullLogger;
|
||||
|
||||
static const unsigned int SeverityAll = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Represents a log-stream + its error severity
|
||||
struct LogStreamInfo {
|
||||
unsigned int m_uiErrorSeverity;
|
||||
LogStream *m_pStream;
|
||||
|
||||
// Constructor
|
||||
LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) :
|
||||
m_uiErrorSeverity( uiErrorSev ),
|
||||
m_pStream( pStream ) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// Destructor
|
||||
~LogStreamInfo() {
|
||||
delete m_pStream;
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Construct a default log stream
|
||||
LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
|
||||
const char* name /*= "AssimpLog.txt"*/,
|
||||
IOSystem* io /*= NULL*/)
|
||||
{
|
||||
switch (streams)
|
||||
{
|
||||
// This is a platform-specific feature
|
||||
case aiDefaultLogStream_DEBUGGER:
|
||||
#ifdef WIN32
|
||||
return new Win32DebugLogStream();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
// Platform-independent default streams
|
||||
case aiDefaultLogStream_STDERR:
|
||||
return new StdOStreamLogStream(std::cerr);
|
||||
case aiDefaultLogStream_STDOUT:
|
||||
return new StdOStreamLogStream(std::cout);
|
||||
case aiDefaultLogStream_FILE:
|
||||
return (name && *name ? new FileLogStream(name,io) : nullptr );
|
||||
default:
|
||||
// We don't know this default log stream, so raise an assertion
|
||||
ai_assert(false);
|
||||
|
||||
};
|
||||
|
||||
// For compilers without dead code path detection
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Creates the only singleton instance
|
||||
Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/,
|
||||
LogSeverity severity /*= NORMAL*/,
|
||||
unsigned int defStreams /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/,
|
||||
IOSystem* io /*= NULL*/) {
|
||||
// enter the mutex here to avoid concurrency problems
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
std::lock_guard<std::mutex> lock(loggerMutex);
|
||||
#endif
|
||||
|
||||
if ( m_pLogger && !isNullLogger() ) {
|
||||
delete m_pLogger;
|
||||
}
|
||||
|
||||
m_pLogger = new DefaultLogger( severity );
|
||||
|
||||
// Attach default log streams
|
||||
// Stream the log to the MSVC debugger?
|
||||
if ( defStreams & aiDefaultLogStream_DEBUGGER ) {
|
||||
m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_DEBUGGER ) );
|
||||
}
|
||||
|
||||
// Stream the log to COUT?
|
||||
if ( defStreams & aiDefaultLogStream_STDOUT ) {
|
||||
m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDOUT ) );
|
||||
}
|
||||
|
||||
// Stream the log to CERR?
|
||||
if ( defStreams & aiDefaultLogStream_STDERR ) {
|
||||
m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDERR ) );
|
||||
}
|
||||
|
||||
// Stream the log to a file
|
||||
if ( defStreams & aiDefaultLogStream_FILE && name && *name ) {
|
||||
m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_FILE, name, io ) );
|
||||
}
|
||||
|
||||
return m_pLogger;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void Logger::debug(const char* message) {
|
||||
|
||||
// SECURITY FIX: otherwise it's easy to produce overruns since
|
||||
// sometimes importers will include data from the input file
|
||||
// (i.e. node names) in their messages.
|
||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||
return;
|
||||
}
|
||||
return OnDebug(message);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void Logger::info(const char* message) {
|
||||
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||
return;
|
||||
}
|
||||
return OnInfo(message);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void Logger::warn(const char* message) {
|
||||
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||
return;
|
||||
}
|
||||
return OnWarn(message);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void Logger::error(const char* message) {
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||
return;
|
||||
}
|
||||
return OnError(message);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void DefaultLogger::set( Logger *logger ) {
|
||||
// enter the mutex here to avoid concurrency problems
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
std::lock_guard<std::mutex> lock(loggerMutex);
|
||||
#endif
|
||||
|
||||
if ( nullptr == logger ) {
|
||||
logger = &s_pNullLogger;
|
||||
}
|
||||
if ( nullptr != m_pLogger && !isNullLogger() ) {
|
||||
delete m_pLogger;
|
||||
}
|
||||
|
||||
DefaultLogger::m_pLogger = logger;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
bool DefaultLogger::isNullLogger() {
|
||||
return m_pLogger == &s_pNullLogger;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
Logger *DefaultLogger::get() {
|
||||
return m_pLogger;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Kills the only instance
|
||||
void DefaultLogger::kill() {
|
||||
// enter the mutex here to avoid concurrency problems
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
std::lock_guard<std::mutex> lock(loggerMutex);
|
||||
#endif
|
||||
|
||||
if ( m_pLogger == &s_pNullLogger ) {
|
||||
return;
|
||||
}
|
||||
delete m_pLogger;
|
||||
m_pLogger = &s_pNullLogger;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Debug message
|
||||
void DefaultLogger::OnDebug( const char* message ) {
|
||||
if ( m_Severity == Logger::NORMAL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
|
||||
char msg[Size];
|
||||
ai_snprintf(msg, Size, "Debug, T%u: %s", GetThreadID(), message);
|
||||
|
||||
WriteToStreams( msg, Logger::Debugging );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Logs an info
|
||||
void DefaultLogger::OnInfo( const char* message ){
|
||||
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
|
||||
char msg[Size];
|
||||
ai_snprintf(msg, Size, "Info, T%u: %s", GetThreadID(), message );
|
||||
|
||||
WriteToStreams( msg , Logger::Info );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Logs a warning
|
||||
void DefaultLogger::OnWarn( const char* message ) {
|
||||
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
|
||||
char msg[Size];
|
||||
ai_snprintf(msg, Size, "Warn, T%u: %s", GetThreadID(), message );
|
||||
|
||||
WriteToStreams( msg, Logger::Warn );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Logs an error
|
||||
void DefaultLogger::OnError( const char* message ) {
|
||||
static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
|
||||
char msg[ Size ];
|
||||
ai_snprintf(msg, Size, "Error, T%u: %s", GetThreadID(), message );
|
||||
|
||||
WriteToStreams( msg, Logger::Err );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Will attach a new stream
|
||||
bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity ) {
|
||||
if ( nullptr == pStream ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 == severity) {
|
||||
severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
|
||||
}
|
||||
|
||||
for ( StreamIt it = m_StreamArray.begin();
|
||||
it != m_StreamArray.end();
|
||||
++it )
|
||||
{
|
||||
if ( (*it)->m_pStream == pStream ) {
|
||||
(*it)->m_uiErrorSeverity |= severity;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
LogStreamInfo *pInfo = new LogStreamInfo( severity, pStream );
|
||||
m_StreamArray.push_back( pInfo );
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Detach a stream
|
||||
bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity ) {
|
||||
if ( nullptr == pStream ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 == severity) {
|
||||
severity = SeverityAll;
|
||||
}
|
||||
|
||||
bool res( false );
|
||||
for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
|
||||
if ( (*it)->m_pStream == pStream ) {
|
||||
(*it)->m_uiErrorSeverity &= ~severity;
|
||||
if ( (*it)->m_uiErrorSeverity == 0 ) {
|
||||
// don't delete the underlying stream 'cause the caller gains ownership again
|
||||
(**it).m_pStream = nullptr;
|
||||
delete *it;
|
||||
m_StreamArray.erase( it );
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Constructor
|
||||
DefaultLogger::DefaultLogger(LogSeverity severity)
|
||||
: Logger ( severity )
|
||||
, noRepeatMsg (false)
|
||||
, lastLen( 0 ) {
|
||||
lastMsg[0] = '\0';
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
DefaultLogger::~DefaultLogger() {
|
||||
for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
|
||||
// also frees the underlying stream, we are its owner.
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Writes message to stream
|
||||
void DefaultLogger::WriteToStreams(const char *message, ErrorSeverity ErrorSev ) {
|
||||
ai_assert(nullptr != message);
|
||||
|
||||
// Check whether this is a repeated message
|
||||
if (! ::strncmp( message,lastMsg, lastLen-1))
|
||||
{
|
||||
if (!noRepeatMsg)
|
||||
{
|
||||
noRepeatMsg = true;
|
||||
message = "Skipping one or more lines with the same contents\n";
|
||||
}
|
||||
else return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// append a new-line character to the message to be printed
|
||||
lastLen = ::strlen(message);
|
||||
::memcpy(lastMsg,message,lastLen+1);
|
||||
::strcat(lastMsg+lastLen,"\n");
|
||||
|
||||
message = lastMsg;
|
||||
noRepeatMsg = false;
|
||||
++lastLen;
|
||||
}
|
||||
for ( ConstStreamIt it = m_StreamArray.begin();
|
||||
it != m_StreamArray.end();
|
||||
++it)
|
||||
{
|
||||
if ( ErrorSev & (*it)->m_uiErrorSeverity )
|
||||
(*it)->m_pStream->write( message);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Returns thread id, if not supported only a zero will be returned.
|
||||
unsigned int DefaultLogger::GetThreadID()
|
||||
{
|
||||
// fixme: we can get this value via std::threads
|
||||
// std::this_thread::get_id().hash() returns a (big) size_t, not sure if this is useful in this case.
|
||||
#ifdef WIN32
|
||||
return (unsigned int)::GetCurrentThreadId();
|
||||
#else
|
||||
return 0; // not supported
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
} // !namespace Assimp
|
||||
65
thirdparty/assimp/code/Common/DefaultProgressHandler.h
vendored
Normal file
65
thirdparty/assimp/code/Common/DefaultProgressHandler.h
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
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 ProgressHandler.hpp
|
||||
* @brief Abstract base class 'ProgressHandler'.
|
||||
*/
|
||||
#ifndef INCLUDED_AI_DEFAULTPROGRESSHANDLER_H
|
||||
#define INCLUDED_AI_DEFAULTPROGRESSHANDLER_H
|
||||
|
||||
#include <assimp/ProgressHandler.hpp>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
/** @brief Internal default implementation of the #ProgressHandler interface. */
|
||||
class DefaultProgressHandler : public ProgressHandler {
|
||||
|
||||
virtual bool Update(float /*percentage*/) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}; // !class DefaultProgressHandler
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif
|
||||
629
thirdparty/assimp/code/Common/Exporter.cpp
vendored
Normal file
629
thirdparty/assimp/code/Common/Exporter.cpp
vendored
Normal file
@@ -0,0 +1,629 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 Exporter.cpp
|
||||
|
||||
Assimp export interface. While it's public interface bears many similarities
|
||||
to the import interface (in fact, it is largely symmetric), the internal
|
||||
implementations differs a lot. Exporters are considered stateless and are
|
||||
simple callbacks which we maintain in a global list along with their
|
||||
description strings.
|
||||
|
||||
Here we implement only the C++ interface (Assimp::Exporter).
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
|
||||
#include <assimp/BlobIOSystem.h>
|
||||
#include <assimp/SceneCombiner.h>
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
#include "Common/DefaultProgressHandler.h"
|
||||
#include "Common/BaseProcess.h"
|
||||
#include "Common/ScenePrivate.h"
|
||||
#include "PostProcessing/CalcTangentsProcess.h"
|
||||
#include "PostProcessing/MakeVerboseFormat.h"
|
||||
#include "PostProcessing/JoinVerticesProcess.h"
|
||||
#include "PostProcessing/ConvertToLHProcess.h"
|
||||
#include "PostProcessing/PretransformVertices.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// PostStepRegistry.cpp
|
||||
void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Exporter worker function prototypes. Should not be necessary to #ifndef them, it's just a prototype
|
||||
// do not use const, because some exporter need to convert the scene temporary
|
||||
void ExportSceneCollada(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneXFile(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneStep(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneObj(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneObjNoMtl(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneSTL(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneGLTF(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneGLB(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneGLTF2(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneGLB2(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
|
||||
void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// global array of all export formats which Assimp supports in its current build
|
||||
Exporter::ExportFormatEntry gExporters[] =
|
||||
{
|
||||
#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
|
||||
Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada ),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_X_EXPORTER
|
||||
Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile,
|
||||
aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs ),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
|
||||
Exporter::ExportFormatEntry( "stp", "Step Files", "stp", &ExportSceneStep, 0 ),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
|
||||
Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
|
||||
aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ),
|
||||
Exporter::ExportFormatEntry( "objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl,
|
||||
aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_STL_EXPORTER
|
||||
Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL,
|
||||
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
|
||||
),
|
||||
Exporter::ExportFormatEntry( "stlb", "Stereolithography (binary)", "stl" , &ExportSceneSTLBinary,
|
||||
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
|
||||
),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_PLY_EXPORTER
|
||||
Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly,
|
||||
aiProcess_PreTransformVertices
|
||||
),
|
||||
Exporter::ExportFormatEntry( "plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
|
||||
aiProcess_PreTransformVertices
|
||||
),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
|
||||
Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS,
|
||||
aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices ),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
|
||||
Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
|
||||
Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
|
||||
Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
|
||||
Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
|
||||
Exporter::ExportFormatEntry( "assbin", "Assimp Binary File", "assbin" , &ExportSceneAssbin, 0 ),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
|
||||
Exporter::ExportFormatEntry( "assxml", "Assimp XML Document", "assxml" , &ExportSceneAssxml, 0 ),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_X3D_EXPORTER
|
||||
Exporter::ExportFormatEntry( "x3d", "Extensible 3D", "x3d" , &ExportSceneX3D, 0 ),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
Exporter::ExportFormatEntry( "fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0 ),
|
||||
Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
|
||||
Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
||||
Exporter::ExportFormatEntry( "assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0)
|
||||
#endif
|
||||
};
|
||||
|
||||
#define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0]))
|
||||
|
||||
|
||||
class ExporterPimpl {
|
||||
public:
|
||||
ExporterPimpl()
|
||||
: blob()
|
||||
, mIOSystem(new Assimp::DefaultIOSystem())
|
||||
, mIsDefaultIOHandler(true)
|
||||
, mProgressHandler( nullptr )
|
||||
, mIsDefaultProgressHandler( true )
|
||||
, mPostProcessingSteps()
|
||||
, mError()
|
||||
, mExporters() {
|
||||
GetPostProcessingStepInstanceList(mPostProcessingSteps);
|
||||
|
||||
// grab all built-in exporters
|
||||
if ( 0 != ( ASSIMP_NUM_EXPORTERS ) ) {
|
||||
mExporters.resize( ASSIMP_NUM_EXPORTERS );
|
||||
std::copy( gExporters, gExporters + ASSIMP_NUM_EXPORTERS, mExporters.begin() );
|
||||
}
|
||||
}
|
||||
|
||||
~ExporterPimpl() {
|
||||
delete blob;
|
||||
|
||||
// Delete all post-processing plug-ins
|
||||
for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++) {
|
||||
delete mPostProcessingSteps[a];
|
||||
}
|
||||
delete mProgressHandler;
|
||||
}
|
||||
|
||||
public:
|
||||
aiExportDataBlob* blob;
|
||||
std::shared_ptr< Assimp::IOSystem > mIOSystem;
|
||||
bool mIsDefaultIOHandler;
|
||||
|
||||
/** The progress handler */
|
||||
ProgressHandler *mProgressHandler;
|
||||
bool mIsDefaultProgressHandler;
|
||||
|
||||
/** Post processing steps we can apply at the imported data. */
|
||||
std::vector< BaseProcess* > mPostProcessingSteps;
|
||||
|
||||
/** Last fatal export error */
|
||||
std::string mError;
|
||||
|
||||
/** Exporters, this includes those registered using #Assimp::Exporter::RegisterExporter */
|
||||
std::vector<Exporter::ExportFormatEntry> mExporters;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Exporter :: Exporter()
|
||||
: pimpl(new ExporterPimpl()) {
|
||||
pimpl->mProgressHandler = new DefaultProgressHandler();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Exporter::~Exporter() {
|
||||
FreeBlob();
|
||||
delete pimpl;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Exporter::SetIOHandler( IOSystem* pIOHandler) {
|
||||
pimpl->mIsDefaultIOHandler = !pIOHandler;
|
||||
pimpl->mIOSystem.reset(pIOHandler);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
IOSystem* Exporter::GetIOHandler() const {
|
||||
return pimpl->mIOSystem.get();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Exporter::IsDefaultIOHandler() const {
|
||||
return pimpl->mIsDefaultIOHandler;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Exporter::SetProgressHandler(ProgressHandler* pHandler) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
if ( nullptr == pHandler) {
|
||||
// Release pointer in the possession of the caller
|
||||
pimpl->mProgressHandler = new DefaultProgressHandler();
|
||||
pimpl->mIsDefaultProgressHandler = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pimpl->mProgressHandler == pHandler) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete pimpl->mProgressHandler;
|
||||
pimpl->mProgressHandler = pHandler;
|
||||
pimpl->mIsDefaultProgressHandler = false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId,
|
||||
unsigned int pPreprocessing, const ExportProperties* pProperties) {
|
||||
if (pimpl->blob) {
|
||||
delete pimpl->blob;
|
||||
pimpl->blob = nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<IOSystem> old = pimpl->mIOSystem;
|
||||
BlobIOSystem* blobio = new BlobIOSystem();
|
||||
pimpl->mIOSystem = std::shared_ptr<IOSystem>( blobio );
|
||||
|
||||
if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName(), pPreprocessing, pProperties)) {
|
||||
pimpl->mIOSystem = old;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pimpl->blob = blobio->GetBlobChain();
|
||||
pimpl->mIOSystem = old;
|
||||
|
||||
return pimpl->blob;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath,
|
||||
unsigned int pPreprocessing, const ExportProperties* pProperties) {
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// when they create scenes from scratch, users will likely create them not in verbose
|
||||
// format. They will likely not be aware that there is a flag in the scene to indicate
|
||||
// this, however. To avoid surprises and bug reports, we check for duplicates in
|
||||
// meshes upfront.
|
||||
const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || MakeVerboseFormatProcess::IsVerboseFormat(pScene);
|
||||
|
||||
pimpl->mProgressHandler->UpdateFileWrite(0, 4);
|
||||
|
||||
pimpl->mError = "";
|
||||
for (size_t i = 0; i < pimpl->mExporters.size(); ++i) {
|
||||
const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i];
|
||||
if (!strcmp(exp.mDescription.id,pFormatId)) {
|
||||
try {
|
||||
// Always create a full copy of the scene. We might optimize this one day,
|
||||
// but for now it is the most pragmatic way.
|
||||
aiScene* scenecopy_tmp = nullptr;
|
||||
SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
|
||||
|
||||
pimpl->mProgressHandler->UpdateFileWrite(1, 4);
|
||||
|
||||
std::unique_ptr<aiScene> scenecopy(scenecopy_tmp);
|
||||
const ScenePrivateData* const priv = ScenePriv(pScene);
|
||||
|
||||
// steps that are not idempotent, i.e. we might need to run them again, usually to get back to the
|
||||
// original state before the step was applied first. When checking which steps we don't need
|
||||
// to run, those are excluded.
|
||||
const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded;
|
||||
|
||||
// Erase all pp steps that were already applied to this scene
|
||||
const unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv && !priv->mIsCopy
|
||||
? (priv->mPPStepsApplied & ~nonIdempotentSteps)
|
||||
: 0u);
|
||||
|
||||
// If no extra post-processing was specified, and we obtained this scene from an
|
||||
// Assimp importer, apply the reverse steps automatically.
|
||||
// TODO: either drop this, or document it. Otherwise it is just a bad surprise.
|
||||
//if (!pPreprocessing && priv) {
|
||||
// pp |= (nonIdempotentSteps & priv->mPPStepsApplied);
|
||||
//}
|
||||
|
||||
// If the input scene is not in verbose format, but there is at least post-processing step that relies on it,
|
||||
// we need to run the MakeVerboseFormat step first.
|
||||
bool must_join_again = false;
|
||||
if (!is_verbose_format) {
|
||||
bool verbosify = false;
|
||||
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
|
||||
BaseProcess* const p = pimpl->mPostProcessingSteps[a];
|
||||
|
||||
if (p->IsActive(pp) && p->RequireVerboseFormat()) {
|
||||
verbosify = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
|
||||
ASSIMP_LOG_DEBUG("export: Scene data not in verbose format, applying MakeVerboseFormat step first");
|
||||
|
||||
MakeVerboseFormatProcess proc;
|
||||
proc.Execute(scenecopy.get());
|
||||
|
||||
if(!(exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
|
||||
must_join_again = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pimpl->mProgressHandler->UpdateFileWrite(2, 4);
|
||||
|
||||
if (pp) {
|
||||
// the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout
|
||||
{
|
||||
FlipWindingOrderProcess step;
|
||||
if (step.IsActive(pp)) {
|
||||
step.Execute(scenecopy.get());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FlipUVsProcess step;
|
||||
if (step.IsActive(pp)) {
|
||||
step.Execute(scenecopy.get());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
MakeLeftHandedProcess step;
|
||||
if (step.IsActive(pp)) {
|
||||
step.Execute(scenecopy.get());
|
||||
}
|
||||
}
|
||||
|
||||
bool exportPointCloud(false);
|
||||
if (nullptr != pProperties) {
|
||||
exportPointCloud = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS);
|
||||
}
|
||||
|
||||
// dispatch other processes
|
||||
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
|
||||
BaseProcess* const p = pimpl->mPostProcessingSteps[a];
|
||||
|
||||
if (p->IsActive(pp)
|
||||
&& !dynamic_cast<FlipUVsProcess*>(p)
|
||||
&& !dynamic_cast<FlipWindingOrderProcess*>(p)
|
||||
&& !dynamic_cast<MakeLeftHandedProcess*>(p)) {
|
||||
if (dynamic_cast<PretransformVertices*>(p) && exportPointCloud) {
|
||||
continue;
|
||||
}
|
||||
p->Execute(scenecopy.get());
|
||||
}
|
||||
}
|
||||
ScenePrivateData* const privOut = ScenePriv(scenecopy.get());
|
||||
ai_assert(nullptr != privOut);
|
||||
|
||||
privOut->mPPStepsApplied |= pp;
|
||||
}
|
||||
|
||||
pimpl->mProgressHandler->UpdateFileWrite(3, 4);
|
||||
|
||||
if(must_join_again) {
|
||||
JoinVerticesProcess proc;
|
||||
proc.Execute(scenecopy.get());
|
||||
}
|
||||
|
||||
ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry.
|
||||
ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties;
|
||||
pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again);
|
||||
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
|
||||
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
|
||||
|
||||
pimpl->mProgressHandler->UpdateFileWrite(4, 4);
|
||||
} catch (DeadlyExportError& err) {
|
||||
pimpl->mError = err.what();
|
||||
return AI_FAILURE;
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
|
||||
ASSIMP_END_EXCEPTION_REGION(aiReturn);
|
||||
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const char* Exporter::GetErrorString() const {
|
||||
return pimpl->mError.c_str();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Exporter::FreeBlob() {
|
||||
delete pimpl->blob;
|
||||
pimpl->blob = nullptr;
|
||||
|
||||
pimpl->mError = "";
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportDataBlob* Exporter::GetBlob() const {
|
||||
return pimpl->blob;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportDataBlob* Exporter::GetOrphanedBlob() const {
|
||||
const aiExportDataBlob* tmp = pimpl->blob;
|
||||
pimpl->blob = nullptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t Exporter::GetExportFormatCount() const {
|
||||
return pimpl->mExporters.size();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) const {
|
||||
if (index >= GetExportFormatCount()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Return from static storage if the requested index is built-in.
|
||||
if (index < sizeof(gExporters) / sizeof(gExporters[0])) {
|
||||
return &gExporters[index].mDescription;
|
||||
}
|
||||
|
||||
return &pimpl->mExporters[index].mDescription;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) {
|
||||
for(const ExportFormatEntry& e : pimpl->mExporters) {
|
||||
if (!strcmp(e.mDescription.id,desc.mDescription.id)) {
|
||||
return aiReturn_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
pimpl->mExporters.push_back(desc);
|
||||
return aiReturn_SUCCESS;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Exporter::UnregisterExporter(const char* id) {
|
||||
for(std::vector<ExportFormatEntry>::iterator it = pimpl->mExporters.begin();
|
||||
it != pimpl->mExporters.end(); ++it) {
|
||||
if (!strcmp((*it).mDescription.id,id)) {
|
||||
pimpl->mExporters.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ExportProperties::ExportProperties() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ExportProperties::ExportProperties(const ExportProperties &other)
|
||||
: mIntProperties(other.mIntProperties)
|
||||
, mFloatProperties(other.mFloatProperties)
|
||||
, mStringProperties(other.mStringProperties)
|
||||
, mMatrixProperties(other.mMatrixProperties) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
bool ExportProperties::SetPropertyInteger(const char* szName, int iValue) {
|
||||
return SetGenericProperty<int>(mIntProperties, szName,iValue);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
bool ExportProperties::SetPropertyFloat(const char* szName, ai_real iValue) {
|
||||
return SetGenericProperty<ai_real>(mFloatProperties, szName,iValue);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
bool ExportProperties::SetPropertyString(const char* szName, const std::string& value) {
|
||||
return SetGenericProperty<std::string>(mStringProperties, szName,value);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
bool ExportProperties::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
|
||||
return SetGenericProperty<aiMatrix4x4>(mMatrixProperties, szName,value);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
int ExportProperties::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
|
||||
return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
ai_real ExportProperties::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
|
||||
return GetGenericProperty<ai_real>(mFloatProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
const std::string ExportProperties::GetPropertyString(const char* szName,
|
||||
const std::string& iErrorReturn /*= ""*/) const {
|
||||
return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Has a configuration property
|
||||
const aiMatrix4x4 ExportProperties::GetPropertyMatrix(const char* szName,
|
||||
const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const {
|
||||
return GetGenericProperty<aiMatrix4x4>(mMatrixProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Has a configuration property
|
||||
bool ExportProperties::HasPropertyInteger(const char* szName) const {
|
||||
return HasGenericProperty<int>(mIntProperties, szName);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Has a configuration property
|
||||
bool ExportProperties::HasPropertyBool(const char* szName) const {
|
||||
return HasGenericProperty<int>(mIntProperties, szName);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Has a configuration property
|
||||
bool ExportProperties::HasPropertyFloat(const char* szName) const {
|
||||
return HasGenericProperty<ai_real>(mFloatProperties, szName);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Has a configuration property
|
||||
bool ExportProperties::HasPropertyString(const char* szName) const {
|
||||
return HasGenericProperty<std::string>(mStringProperties, szName);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Has a configuration property
|
||||
bool ExportProperties::HasPropertyMatrix(const char* szName) const {
|
||||
return HasGenericProperty<aiMatrix4x4>(mMatrixProperties, szName);
|
||||
}
|
||||
|
||||
|
||||
#endif // !ASSIMP_BUILD_NO_EXPORT
|
||||
107
thirdparty/assimp/code/Common/FileLogStream.h
vendored
Normal file
107
thirdparty/assimp/code/Common/FileLogStream.h
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
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 FileLofStream.h
|
||||
*/
|
||||
#ifndef ASSIMP_FILELOGSTREAM_H_INC
|
||||
#define ASSIMP_FILELOGSTREAM_H_INC
|
||||
|
||||
#include <assimp/LogStream.hpp>
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
/** @class FileLogStream
|
||||
* @brief Logstream to write into a file.
|
||||
*/
|
||||
class FileLogStream :
|
||||
public LogStream
|
||||
{
|
||||
public:
|
||||
FileLogStream( const char* file, IOSystem* io = NULL );
|
||||
~FileLogStream();
|
||||
void write( const char* message );
|
||||
|
||||
private:
|
||||
IOStream *m_pStream;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Constructor
|
||||
inline FileLogStream::FileLogStream( const char* file, IOSystem* io ) :
|
||||
m_pStream(NULL)
|
||||
{
|
||||
if ( !file || 0 == *file )
|
||||
return;
|
||||
|
||||
// If no IOSystem is specified: take a default one
|
||||
if (!io)
|
||||
{
|
||||
DefaultIOSystem FileSystem;
|
||||
m_pStream = FileSystem.Open( file, "wt");
|
||||
}
|
||||
else m_pStream = io->Open( file, "wt" );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
inline FileLogStream::~FileLogStream()
|
||||
{
|
||||
// The virtual d'tor should destroy the underlying file
|
||||
delete m_pStream;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Write method
|
||||
inline void FileLogStream::write( const char* message )
|
||||
{
|
||||
if (m_pStream != NULL)
|
||||
{
|
||||
m_pStream->Write(message, sizeof(char), ::strlen(message));
|
||||
m_pStream->Flush();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
} // !Namespace Assimp
|
||||
|
||||
#endif // !! ASSIMP_FILELOGSTREAM_H_INC
|
||||
345
thirdparty/assimp/code/Common/FileSystemFilter.h
vendored
Normal file
345
thirdparty/assimp/code/Common/FileSystemFilter.h
vendored
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2008, 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 FileSystemFilter.h
|
||||
* Implements a filter system to filter calls to Exists() and Open()
|
||||
* in order to improve the success rate of file opening ...
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef AI_FILESYSTEMFILTER_H_INC
|
||||
#define AI_FILESYSTEMFILTER_H_INC
|
||||
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
inline bool IsHex(char s) {
|
||||
return (s>='0' && s<='9') || (s>='a' && s<='f') || (s>='A' && s<='F');
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** File system filter
|
||||
*/
|
||||
class FileSystemFilter : public IOSystem
|
||||
{
|
||||
public:
|
||||
/** Constructor. */
|
||||
FileSystemFilter(const std::string& file, IOSystem* old)
|
||||
: mWrapped (old)
|
||||
, mSrc_file(file)
|
||||
, mSep(mWrapped->getOsSeparator()) {
|
||||
ai_assert(nullptr != mWrapped);
|
||||
|
||||
// Determine base directory
|
||||
mBase = mSrc_file;
|
||||
std::string::size_type ss2;
|
||||
if (std::string::npos != (ss2 = mBase.find_last_of("\\/"))) {
|
||||
mBase.erase(ss2,mBase.length()-ss2);
|
||||
} else {
|
||||
mBase = "";
|
||||
}
|
||||
|
||||
// make sure the directory is terminated properly
|
||||
char s;
|
||||
|
||||
if ( mBase.empty() ) {
|
||||
mBase = ".";
|
||||
mBase += getOsSeparator();
|
||||
} else if ((s = *(mBase.end()-1)) != '\\' && s != '/') {
|
||||
mBase += getOsSeparator();
|
||||
}
|
||||
|
||||
DefaultLogger::get()->info("Import root directory is \'" + mBase + "\'");
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
~FileSystemFilter() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Tests for the existence of a file at the given path. */
|
||||
bool Exists( const char* pFile) const {
|
||||
ai_assert( nullptr != mWrapped );
|
||||
|
||||
std::string tmp = pFile;
|
||||
|
||||
// Currently this IOSystem is also used to open THE ONE FILE.
|
||||
if (tmp != mSrc_file) {
|
||||
BuildPath(tmp);
|
||||
Cleanup(tmp);
|
||||
}
|
||||
|
||||
return mWrapped->Exists(tmp);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns the directory separator. */
|
||||
char getOsSeparator() const {
|
||||
return mSep;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Open a new file with a given path. */
|
||||
IOStream* Open( const char* pFile, const char* pMode = "rb") {
|
||||
ai_assert( nullptr != mWrapped );
|
||||
if ( nullptr == pFile || nullptr == pMode ) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ai_assert( nullptr != pFile );
|
||||
ai_assert( nullptr != pMode );
|
||||
|
||||
// First try the unchanged path
|
||||
IOStream* s = mWrapped->Open(pFile,pMode);
|
||||
|
||||
if (nullptr == s) {
|
||||
std::string tmp = pFile;
|
||||
|
||||
// Try to convert between absolute and relative paths
|
||||
BuildPath(tmp);
|
||||
s = mWrapped->Open(tmp,pMode);
|
||||
|
||||
if (nullptr == s) {
|
||||
// Finally, look for typical issues with paths
|
||||
// and try to correct them. This is our last
|
||||
// resort.
|
||||
tmp = pFile;
|
||||
Cleanup(tmp);
|
||||
BuildPath(tmp);
|
||||
s = mWrapped->Open(tmp,pMode);
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Closes the given file and releases all resources associated with it. */
|
||||
void Close( IOStream* pFile) {
|
||||
ai_assert( nullptr != mWrapped );
|
||||
return mWrapped->Close(pFile);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Compare two paths */
|
||||
bool ComparePaths (const char* one, const char* second) const {
|
||||
ai_assert( nullptr != mWrapped );
|
||||
return mWrapped->ComparePaths (one,second);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Pushes a new directory onto the directory stack. */
|
||||
bool PushDirectory(const std::string &path ) {
|
||||
ai_assert( nullptr != mWrapped );
|
||||
return mWrapped->PushDirectory(path);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns the top directory from the stack. */
|
||||
const std::string &CurrentDirectory() const {
|
||||
ai_assert( nullptr != mWrapped );
|
||||
return mWrapped->CurrentDirectory();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns the number of directories stored on the stack. */
|
||||
size_t StackSize() const {
|
||||
ai_assert( nullptr != mWrapped );
|
||||
return mWrapped->StackSize();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Pops the top directory from the stack. */
|
||||
bool PopDirectory() {
|
||||
ai_assert( nullptr != mWrapped );
|
||||
return mWrapped->PopDirectory();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Creates an new directory at the given path. */
|
||||
bool CreateDirectory(const std::string &path) {
|
||||
ai_assert( nullptr != mWrapped );
|
||||
return mWrapped->CreateDirectory(path);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Will change the current directory to the given path. */
|
||||
bool ChangeDirectory(const std::string &path) {
|
||||
ai_assert( nullptr != mWrapped );
|
||||
return mWrapped->ChangeDirectory(path);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Delete file. */
|
||||
bool DeleteFile(const std::string &file) {
|
||||
ai_assert( nullptr != mWrapped );
|
||||
return mWrapped->DeleteFile(file);
|
||||
}
|
||||
|
||||
private:
|
||||
// -------------------------------------------------------------------
|
||||
/** Build a valid path from a given relative or absolute path.
|
||||
*/
|
||||
void BuildPath (std::string& in) const {
|
||||
ai_assert( nullptr != mWrapped );
|
||||
// if we can already access the file, great.
|
||||
if (in.length() < 3 || mWrapped->Exists(in)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine whether this is a relative path (Windows-specific - most assets are packaged on Windows).
|
||||
if (in[1] != ':') {
|
||||
|
||||
// append base path and try
|
||||
const std::string tmp = mBase + in;
|
||||
if (mWrapped->Exists(tmp)) {
|
||||
in = tmp;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Chop of the file name and look in the model directory, if
|
||||
// this fails try all sub paths of the given path, i.e.
|
||||
// if the given path is foo/bar/something.lwo, try
|
||||
// <base>/something.lwo
|
||||
// <base>/bar/something.lwo
|
||||
// <base>/foo/bar/something.lwo
|
||||
std::string::size_type pos = in.rfind('/');
|
||||
if (std::string::npos == pos) {
|
||||
pos = in.rfind('\\');
|
||||
}
|
||||
|
||||
if (std::string::npos != pos) {
|
||||
std::string tmp;
|
||||
std::string::size_type last_dirsep = std::string::npos;
|
||||
|
||||
while(true) {
|
||||
tmp = mBase;
|
||||
tmp += mSep;
|
||||
|
||||
std::string::size_type dirsep = in.rfind('/', last_dirsep);
|
||||
if (std::string::npos == dirsep) {
|
||||
dirsep = in.rfind('\\', last_dirsep);
|
||||
}
|
||||
|
||||
if (std::string::npos == dirsep || dirsep == 0) {
|
||||
// we did try this already.
|
||||
break;
|
||||
}
|
||||
|
||||
last_dirsep = dirsep-1;
|
||||
|
||||
tmp += in.substr(dirsep+1, in.length()-pos);
|
||||
if (mWrapped->Exists(tmp)) {
|
||||
in = tmp;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hopefully the underlying file system has another few tricks to access this file ...
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Cleanup the given path
|
||||
*/
|
||||
void Cleanup (std::string& in) const {
|
||||
if(in.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove a very common issue when we're parsing file names: spaces at the
|
||||
// beginning of the path.
|
||||
char last = 0;
|
||||
std::string::iterator it = in.begin();
|
||||
while (IsSpaceOrNewLine( *it ))++it;
|
||||
if (it != in.begin()) {
|
||||
in.erase(in.begin(),it+1);
|
||||
}
|
||||
|
||||
const char separator = getOsSeparator();
|
||||
for (it = in.begin(); it != in.end(); ++it) {
|
||||
// Exclude :// and \\, which remain untouched.
|
||||
// https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632
|
||||
if ( !strncmp(&*it, "://", 3 )) {
|
||||
it += 3;
|
||||
continue;
|
||||
}
|
||||
if (it == in.begin() && !strncmp(&*it, "\\\\", 2)) {
|
||||
it += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cleanup path delimiters
|
||||
if (*it == '/' || (*it) == '\\') {
|
||||
*it = separator;
|
||||
|
||||
// And we're removing double delimiters, frequent issue with
|
||||
// incorrectly composited paths ...
|
||||
if (last == *it) {
|
||||
it = in.erase(it);
|
||||
--it;
|
||||
}
|
||||
} else if (*it == '%' && in.end() - it > 2) {
|
||||
// Hex sequence in URIs
|
||||
if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) {
|
||||
*it = HexOctetToDecimal(&*it);
|
||||
it = in.erase(it+1,it+2);
|
||||
--it;
|
||||
}
|
||||
}
|
||||
|
||||
last = *it;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
IOSystem *mWrapped;
|
||||
std::string mSrc_file, mBase;
|
||||
char mSep;
|
||||
};
|
||||
|
||||
} //!ns Assimp
|
||||
|
||||
#endif //AI_DEFAULTIOSYSTEM_H_INC
|
||||
102
thirdparty/assimp/code/Common/IFF.h
vendored
Normal file
102
thirdparty/assimp/code/Common/IFF.h
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
// Definitions for the Interchange File Format (IFF)
|
||||
// Alexander Gessler, 2006
|
||||
// Adapted to Assimp August 2008
|
||||
|
||||
#ifndef AI_IFF_H_INCLUDED
|
||||
#define AI_IFF_H_INCLUDED
|
||||
|
||||
#include <assimp/ByteSwapper.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace IFF {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Describes an IFF chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
struct ChunkHeader
|
||||
{
|
||||
//! Type of the chunk header - FourCC
|
||||
uint32_t type;
|
||||
|
||||
//! Length of the chunk data, in bytes
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Describes an IFF sub chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
struct SubChunkHeader
|
||||
{
|
||||
//! Type of the chunk header - FourCC
|
||||
uint32_t type;
|
||||
|
||||
//! Length of the chunk data, in bytes
|
||||
uint16_t length;
|
||||
};
|
||||
|
||||
|
||||
#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
|
||||
((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
|
||||
|
||||
|
||||
#define AI_IFF_FOURCC_FORM AI_IFF_FOURCC('F','O','R','M')
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Load a chunk header
|
||||
//! @param outFile Pointer to the file data - points to the chunk data afterwards
|
||||
//! @return Copy of the chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
inline ChunkHeader LoadChunk(uint8_t*& outFile)
|
||||
{
|
||||
ChunkHeader head;
|
||||
::memcpy(&head.type, outFile, 4);
|
||||
outFile += 4;
|
||||
::memcpy(&head.length, outFile, 4);
|
||||
outFile += 4;
|
||||
AI_LSWAP4(head.length);
|
||||
AI_LSWAP4(head.type);
|
||||
return head;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Load a sub chunk header
|
||||
//! @param outFile Pointer to the file data - points to the chunk data afterwards
|
||||
//! @return Copy of the sub chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
inline SubChunkHeader LoadSubChunk(uint8_t*& outFile)
|
||||
{
|
||||
SubChunkHeader head;
|
||||
::memcpy(&head.type, outFile, 4);
|
||||
outFile += 4;
|
||||
::memcpy(&head.length, outFile, 2);
|
||||
outFile += 2;
|
||||
AI_LSWAP2(head.length);
|
||||
AI_LSWAP4(head.type);
|
||||
return head;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Read the file header and return the type of the file and its size
|
||||
//! @param outFile Pointer to the file data. The buffer must at
|
||||
//! least be 12 bytes large.
|
||||
//! @param fileType Receives the type of the file
|
||||
//! @return 0 if everything was OK, otherwise an error message
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
inline const char* ReadHeader(uint8_t* outFile, uint32_t& fileType)
|
||||
{
|
||||
ChunkHeader head = LoadChunk(outFile);
|
||||
if(AI_IFF_FOURCC_FORM != head.type)
|
||||
{
|
||||
return "The file is not an IFF file: FORM chunk is missing";
|
||||
}
|
||||
::memcpy(&fileType, outFile, 4);
|
||||
AI_LSWAP4(fileType);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif // !! AI_IFF_H_INCLUDED
|
||||
1174
thirdparty/assimp/code/Common/Importer.cpp
vendored
Normal file
1174
thirdparty/assimp/code/Common/Importer.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
247
thirdparty/assimp/code/Common/Importer.h
vendored
Normal file
247
thirdparty/assimp/code/Common/Importer.h
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
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 Importer.h mostly internal stuff for use by #Assimp::Importer */
|
||||
#pragma once
|
||||
#ifndef INCLUDED_AI_IMPORTER_H
|
||||
#define INCLUDED_AI_IMPORTER_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <assimp/matrix4x4.h>
|
||||
|
||||
struct aiScene;
|
||||
|
||||
namespace Assimp {
|
||||
class ProgressHandler;
|
||||
class IOSystem;
|
||||
class BaseImporter;
|
||||
class BaseProcess;
|
||||
class SharedPostProcessInfo;
|
||||
|
||||
|
||||
//! @cond never
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief Internal PIMPL implementation for Assimp::Importer
|
||||
*
|
||||
* Using this idiom here allows us to drop the dependency from
|
||||
* std::vector and std::map in the public headers. Furthermore we are dropping
|
||||
* any STL interface problems caused by mismatching STL settings. All
|
||||
* size calculation are now done by us, not the app heap. */
|
||||
class ImporterPimpl {
|
||||
public:
|
||||
// Data type to store the key hash
|
||||
typedef unsigned int KeyType;
|
||||
|
||||
// typedefs for our four configuration maps.
|
||||
// We don't need more, so there is no need for a generic solution
|
||||
typedef std::map<KeyType, int> IntPropertyMap;
|
||||
typedef std::map<KeyType, ai_real> FloatPropertyMap;
|
||||
typedef std::map<KeyType, std::string> StringPropertyMap;
|
||||
typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap;
|
||||
|
||||
/** IO handler to use for all file accesses. */
|
||||
IOSystem* mIOHandler;
|
||||
bool mIsDefaultHandler;
|
||||
|
||||
/** Progress handler for feedback. */
|
||||
ProgressHandler* mProgressHandler;
|
||||
bool mIsDefaultProgressHandler;
|
||||
|
||||
/** Format-specific importer worker objects - one for each format we can read.*/
|
||||
std::vector< BaseImporter* > mImporter;
|
||||
|
||||
/** Post processing steps we can apply at the imported data. */
|
||||
std::vector< BaseProcess* > mPostProcessingSteps;
|
||||
|
||||
/** The imported data, if ReadFile() was successful, NULL otherwise. */
|
||||
aiScene* mScene;
|
||||
|
||||
/** The error description, if there was one. */
|
||||
std::string mErrorString;
|
||||
|
||||
/** List of integer properties */
|
||||
IntPropertyMap mIntProperties;
|
||||
|
||||
/** List of floating-point properties */
|
||||
FloatPropertyMap mFloatProperties;
|
||||
|
||||
/** List of string properties */
|
||||
StringPropertyMap mStringProperties;
|
||||
|
||||
/** List of Matrix properties */
|
||||
MatrixPropertyMap mMatrixProperties;
|
||||
|
||||
/** Used for testing - extra verbose mode causes the ValidateDataStructure-Step
|
||||
* to be executed before and after every single post-process step */
|
||||
bool bExtraVerbose;
|
||||
|
||||
/** Used by post-process steps to share data */
|
||||
SharedPostProcessInfo* mPPShared;
|
||||
|
||||
/// The default class constructor.
|
||||
ImporterPimpl() AI_NO_EXCEPT;
|
||||
};
|
||||
|
||||
inline
|
||||
ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT
|
||||
: mIOHandler( nullptr )
|
||||
, mIsDefaultHandler( false )
|
||||
, mProgressHandler( nullptr )
|
||||
, mIsDefaultProgressHandler( false )
|
||||
, mImporter()
|
||||
, mPostProcessingSteps()
|
||||
, mScene( nullptr )
|
||||
, mErrorString()
|
||||
, mIntProperties()
|
||||
, mFloatProperties()
|
||||
, mStringProperties()
|
||||
, mMatrixProperties()
|
||||
, bExtraVerbose( false )
|
||||
, mPPShared( nullptr ) {
|
||||
// empty
|
||||
}
|
||||
//! @endcond
|
||||
|
||||
|
||||
struct BatchData;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** FOR IMPORTER PLUGINS ONLY: A helper class to the pleasure of importers
|
||||
* that need to load many external meshes recursively.
|
||||
*
|
||||
* The class uses several threads to load these meshes (or at least it
|
||||
* could, this has not yet been implemented at the moment).
|
||||
*
|
||||
* @note The class may not be used by more than one thread*/
|
||||
class ASSIMP_API BatchLoader
|
||||
{
|
||||
// friend of Importer
|
||||
|
||||
public:
|
||||
//! @cond never
|
||||
// -------------------------------------------------------------------
|
||||
/** Wraps a full list of configuration properties for an importer.
|
||||
* Properties can be set using SetGenericProperty */
|
||||
struct PropertyMap
|
||||
{
|
||||
ImporterPimpl::IntPropertyMap ints;
|
||||
ImporterPimpl::FloatPropertyMap floats;
|
||||
ImporterPimpl::StringPropertyMap strings;
|
||||
ImporterPimpl::MatrixPropertyMap matrices;
|
||||
|
||||
bool operator == (const PropertyMap& prop) const {
|
||||
// fixme: really isocpp? gcc complains
|
||||
return ints == prop.ints && floats == prop.floats && strings == prop.strings && matrices == prop.matrices;
|
||||
}
|
||||
|
||||
bool empty () const {
|
||||
return ints.empty() && floats.empty() && strings.empty() && matrices.empty();
|
||||
}
|
||||
};
|
||||
//! @endcond
|
||||
|
||||
public:
|
||||
// -------------------------------------------------------------------
|
||||
/** Construct a batch loader from a given IO system to be used
|
||||
* to access external files
|
||||
*/
|
||||
explicit BatchLoader(IOSystem* pIO, bool validate = false );
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** The class destructor.
|
||||
*/
|
||||
~BatchLoader();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Sets the validation step. True for enable validation during postprocess.
|
||||
* @param enable True for validation.
|
||||
*/
|
||||
void setValidation( bool enabled );
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns the current validation step.
|
||||
* @return The current validation step.
|
||||
*/
|
||||
bool getValidation() const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Add a new file to the list of files to be loaded.
|
||||
* @param file File to be loaded
|
||||
* @param steps Post-processing steps to be executed on the file
|
||||
* @param map Optional configuration properties
|
||||
* @return 'Load request channel' - an unique ID that can later
|
||||
* be used to access the imported file data.
|
||||
* @see GetImport */
|
||||
unsigned int AddLoadRequest (
|
||||
const std::string& file,
|
||||
unsigned int steps = 0,
|
||||
const PropertyMap* map = NULL
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get an imported scene.
|
||||
* This polls the import from the internal request list.
|
||||
* If an import is requested several times, this function
|
||||
* can be called several times, too.
|
||||
*
|
||||
* @param which LRWC returned by AddLoadRequest().
|
||||
* @return NULL if there is no scene with this file name
|
||||
* in the queue of the scene hasn't been loaded yet. */
|
||||
aiScene* GetImport(
|
||||
unsigned int which
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Waits until all scenes have been loaded. This returns
|
||||
* immediately if no scenes are queued.*/
|
||||
void LoadAll();
|
||||
|
||||
private:
|
||||
// No need to have that in the public API ...
|
||||
BatchData *m_data;
|
||||
};
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // INCLUDED_AI_IMPORTER_H
|
||||
371
thirdparty/assimp/code/Common/ImporterRegistry.cpp
vendored
Normal file
371
thirdparty/assimp/code/Common/ImporterRegistry.cpp
vendored
Normal file
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 ImporterRegistry.cpp
|
||||
|
||||
Central registry for all importers available. Do not edit this file
|
||||
directly (unless you are adding new loaders), instead use the
|
||||
corresponding preprocessor flag to selectively disable formats.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <assimp/BaseImporter.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Importers
|
||||
// (include_new_importers_here)
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#ifndef ASSIMP_BUILD_NO_X_IMPORTER
|
||||
# include "X/XFileImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
|
||||
# include "AMF/AMFImporter.hpp"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
|
||||
# include "3DS/3DSLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MD3_IMPORTER
|
||||
# include "MD3/MD3Loader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MDL_IMPORTER
|
||||
# include "MDL/MDLLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MD2_IMPORTER
|
||||
# include "MD2/MD2Loader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_PLY_IMPORTER
|
||||
# include "Ply/PlyLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
|
||||
# include "ASE/ASELoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER
|
||||
# include "Obj/ObjFileImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_HMP_IMPORTER
|
||||
# include "HMP/HMPLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_SMD_IMPORTER
|
||||
# include "SMD/SMDLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MDC_IMPORTER
|
||||
# include "MDC/MDCLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MD5_IMPORTER
|
||||
# include "MD5/MD5Loader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_STL_IMPORTER
|
||||
# include "STL/STLLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_LWO_IMPORTER
|
||||
# include "LWO/LWOLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_DXF_IMPORTER
|
||||
# include "DXF/DXFLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_NFF_IMPORTER
|
||||
# include "NFF/NFFLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_RAW_IMPORTER
|
||||
# include "Raw/RawLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_SIB_IMPORTER
|
||||
# include "SIB/SIBImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_OFF_IMPORTER
|
||||
# include "OFF/OFFLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_AC_IMPORTER
|
||||
# include "AC/ACLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_BVH_IMPORTER
|
||||
# include "BVH/BVHLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER
|
||||
# include "Irr/IRRMeshLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_IRR_IMPORTER
|
||||
# include "Irr/IRRLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_Q3D_IMPORTER
|
||||
# include "Q3D/Q3DLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_B3D_IMPORTER
|
||||
# include "B3D/B3DImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER
|
||||
# include "Collada/ColladaLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_TERRAGEN_IMPORTER
|
||||
# include "Terragen/TerragenLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_CSM_IMPORTER
|
||||
# include "CSM/CSMLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_3D_IMPORTER
|
||||
# include "Unreal/UnrealLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_LWS_IMPORTER
|
||||
# include "LWS/LWSLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
# include "Ogre/OgreImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER
|
||||
# include "OpenGEX/OpenGEXImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER
|
||||
# include "MS3D/MS3DLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_COB_IMPORTER
|
||||
# include "COB/COBLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||
# include "Blender/BlenderLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER
|
||||
# include "Q3BSP/Q3BSPFileImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_NDO_IMPORTER
|
||||
# include "NDO/NDOLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
|
||||
# include "Importer/IFC/IFCLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_XGL_IMPORTER
|
||||
# include "XGL/XGLLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
# include "FBX/FBXImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
|
||||
# include "Assbin/AssbinLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
|
||||
# include "glTF/glTFImporter.h"
|
||||
# include "glTF2/glTF2Importer.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
|
||||
# include "C4D/C4DImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER
|
||||
# include "3MF/D3MFImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
|
||||
# include "X3D/X3DImporter.hpp"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
|
||||
# include "MMD/MMDImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER
|
||||
# include "Importer/StepFile/StepFileImporter.h"
|
||||
#endif
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void GetImporterInstanceList(std::vector< BaseImporter* >& out)
|
||||
{
|
||||
// ----------------------------------------------------------------------------
|
||||
// Add an instance of each worker class here
|
||||
// (register_new_importers_here)
|
||||
// ----------------------------------------------------------------------------
|
||||
out.reserve(64);
|
||||
#if (!defined ASSIMP_BUILD_NO_X_IMPORTER)
|
||||
out.push_back( new XFileImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_OBJ_IMPORTER)
|
||||
out.push_back( new ObjFileImporter());
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
|
||||
out.push_back( new AMFImporter() );
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER)
|
||||
out.push_back( new Discreet3DSImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_MD3_IMPORTER)
|
||||
out.push_back( new MD3Importer());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_MD2_IMPORTER)
|
||||
out.push_back( new MD2Importer());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_PLY_IMPORTER)
|
||||
out.push_back( new PLYImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_MDL_IMPORTER)
|
||||
out.push_back( new MDLImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_ASE_IMPORTER)
|
||||
#if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER)
|
||||
out.push_back( new ASEImporter());
|
||||
# endif
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_HMP_IMPORTER)
|
||||
out.push_back( new HMPImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_SMD_IMPORTER)
|
||||
out.push_back( new SMDImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_MDC_IMPORTER)
|
||||
out.push_back( new MDCImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_MD5_IMPORTER)
|
||||
out.push_back( new MD5Importer());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_STL_IMPORTER)
|
||||
out.push_back( new STLImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_LWO_IMPORTER)
|
||||
out.push_back( new LWOImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_DXF_IMPORTER)
|
||||
out.push_back( new DXFImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_NFF_IMPORTER)
|
||||
out.push_back( new NFFImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_RAW_IMPORTER)
|
||||
out.push_back( new RAWImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_SIB_IMPORTER)
|
||||
out.push_back( new SIBImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_OFF_IMPORTER)
|
||||
out.push_back( new OFFImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_AC_IMPORTER)
|
||||
out.push_back( new AC3DImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_BVH_IMPORTER)
|
||||
out.push_back( new BVHLoader());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_IRRMESH_IMPORTER)
|
||||
out.push_back( new IRRMeshImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_IRR_IMPORTER)
|
||||
out.push_back( new IRRImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_Q3D_IMPORTER)
|
||||
out.push_back( new Q3DImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_B3D_IMPORTER)
|
||||
out.push_back( new B3DImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_COLLADA_IMPORTER)
|
||||
out.push_back( new ColladaLoader());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_TERRAGEN_IMPORTER)
|
||||
out.push_back( new TerragenImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_CSM_IMPORTER)
|
||||
out.push_back( new CSMImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_3D_IMPORTER)
|
||||
out.push_back( new UnrealImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_LWS_IMPORTER)
|
||||
out.push_back( new LWSImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_OGRE_IMPORTER)
|
||||
out.push_back( new Ogre::OgreImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_OPENGEX_IMPORTER )
|
||||
out.push_back( new OpenGEX::OpenGEXImporter() );
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_MS3D_IMPORTER)
|
||||
out.push_back( new MS3DImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_COB_IMPORTER)
|
||||
out.push_back( new COBImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_BLEND_IMPORTER)
|
||||
out.push_back( new BlenderImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_Q3BSP_IMPORTER)
|
||||
out.push_back( new Q3BSPFileImporter() );
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_NDO_IMPORTER)
|
||||
out.push_back( new NDOImporter() );
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_IFC_IMPORTER)
|
||||
out.push_back( new IFCImporter() );
|
||||
#endif
|
||||
#if ( !defined ASSIMP_BUILD_NO_XGL_IMPORTER )
|
||||
out.push_back( new XGLImporter() );
|
||||
#endif
|
||||
#if ( !defined ASSIMP_BUILD_NO_FBX_IMPORTER )
|
||||
out.push_back( new FBXImporter() );
|
||||
#endif
|
||||
#if ( !defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER )
|
||||
out.push_back( new AssbinImporter() );
|
||||
#endif
|
||||
#if ( !defined ASSIMP_BUILD_NO_GLTF_IMPORTER )
|
||||
out.push_back( new glTFImporter() );
|
||||
out.push_back( new glTF2Importer() );
|
||||
#endif
|
||||
#if ( !defined ASSIMP_BUILD_NO_C4D_IMPORTER )
|
||||
out.push_back( new C4DImporter() );
|
||||
#endif
|
||||
#if ( !defined ASSIMP_BUILD_NO_3MF_IMPORTER )
|
||||
out.push_back( new D3MFImporter() );
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
|
||||
out.push_back( new X3DImporter() );
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
|
||||
out.push_back( new MMDImporter() );
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER
|
||||
out.push_back(new StepFile::StepFileImporter());
|
||||
#endif
|
||||
}
|
||||
|
||||
/** will delete all registered importers. */
|
||||
void DeleteImporterInstanceList(std::vector< BaseImporter* >& deleteList){
|
||||
for(size_t i= 0; i<deleteList.size();++i){
|
||||
delete deleteList[i];
|
||||
deleteList[i]=nullptr;
|
||||
}//for
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
||||
229
thirdparty/assimp/code/Common/PolyTools.h
vendored
Normal file
229
thirdparty/assimp/code/Common/PolyTools.h
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
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 PolyTools.h, various utilities for our dealings with arbitrary polygons */
|
||||
|
||||
#ifndef AI_POLYTOOLS_H_INCLUDED
|
||||
#define AI_POLYTOOLS_H_INCLUDED
|
||||
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Compute the signed area of a triangle.
|
||||
* The function accepts an unconstrained template parameter for use with
|
||||
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
||||
template <typename T>
|
||||
inline double GetArea2D(const T& v1, const T& v2, const T& v3)
|
||||
{
|
||||
return 0.5 * (v1.x * ((double)v3.y - v2.y) + v2.x * ((double)v1.y - v3.y) + v3.x * ((double)v2.y - v1.y));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Test if a given point p2 is on the left side of the line formed by p0-p1.
|
||||
* The function accepts an unconstrained template parameter for use with
|
||||
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
||||
template <typename T>
|
||||
inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2)
|
||||
{
|
||||
return GetArea2D(p0,p2,p1) > 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Test if a given point is inside a given triangle in R2.
|
||||
* The function accepts an unconstrained template parameter for use with
|
||||
* both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/
|
||||
template <typename T>
|
||||
inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp)
|
||||
{
|
||||
// Point in triangle test using baryzentric coordinates
|
||||
const aiVector2D v0 = p1 - p0;
|
||||
const aiVector2D v1 = p2 - p0;
|
||||
const aiVector2D v2 = pp - p0;
|
||||
|
||||
double dot00 = v0 * v0;
|
||||
double dot01 = v0 * v1;
|
||||
double dot02 = v0 * v2;
|
||||
double dot11 = v1 * v1;
|
||||
double dot12 = v1 * v2;
|
||||
|
||||
const double invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
|
||||
dot11 = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
||||
dot00 = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
||||
|
||||
return (dot11 > 0) && (dot00 > 0) && (dot11 + dot00 < 1);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Check whether the winding order of a given polygon is counter-clockwise.
|
||||
* The function accepts an unconstrained template parameter, but is intended
|
||||
* to be used only with aiVector2D and aiVector3D (z axis is ignored, only
|
||||
* x and y are taken into account).
|
||||
* @note Code taken from http://cgm.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Ian/applet1.html and translated to C++
|
||||
*/
|
||||
template <typename T>
|
||||
inline bool IsCCW(T* in, size_t npoints) {
|
||||
double aa, bb, cc, b, c, theta;
|
||||
double convex_turn;
|
||||
double convex_sum = 0;
|
||||
|
||||
ai_assert(npoints >= 3);
|
||||
|
||||
for (size_t i = 0; i < npoints - 2; i++) {
|
||||
aa = ((in[i+2].x - in[i].x) * (in[i+2].x - in[i].x)) +
|
||||
((-in[i+2].y + in[i].y) * (-in[i+2].y + in[i].y));
|
||||
|
||||
bb = ((in[i+1].x - in[i].x) * (in[i+1].x - in[i].x)) +
|
||||
((-in[i+1].y + in[i].y) * (-in[i+1].y + in[i].y));
|
||||
|
||||
cc = ((in[i+2].x - in[i+1].x) *
|
||||
(in[i+2].x - in[i+1].x)) +
|
||||
((-in[i+2].y + in[i+1].y) *
|
||||
(-in[i+2].y + in[i+1].y));
|
||||
|
||||
b = std::sqrt(bb);
|
||||
c = std::sqrt(cc);
|
||||
theta = std::acos((bb + cc - aa) / (2 * b * c));
|
||||
|
||||
if (OnLeftSideOfLine2D(in[i],in[i+2],in[i+1])) {
|
||||
// if (convex(in[i].x, in[i].y,
|
||||
// in[i+1].x, in[i+1].y,
|
||||
// in[i+2].x, in[i+2].y)) {
|
||||
convex_turn = AI_MATH_PI_F - theta;
|
||||
convex_sum += convex_turn;
|
||||
}
|
||||
else {
|
||||
convex_sum -= AI_MATH_PI_F - theta;
|
||||
}
|
||||
}
|
||||
aa = ((in[1].x - in[npoints-2].x) *
|
||||
(in[1].x - in[npoints-2].x)) +
|
||||
((-in[1].y + in[npoints-2].y) *
|
||||
(-in[1].y + in[npoints-2].y));
|
||||
|
||||
bb = ((in[0].x - in[npoints-2].x) *
|
||||
(in[0].x - in[npoints-2].x)) +
|
||||
((-in[0].y + in[npoints-2].y) *
|
||||
(-in[0].y + in[npoints-2].y));
|
||||
|
||||
cc = ((in[1].x - in[0].x) * (in[1].x - in[0].x)) +
|
||||
((-in[1].y + in[0].y) * (-in[1].y + in[0].y));
|
||||
|
||||
b = std::sqrt(bb);
|
||||
c = std::sqrt(cc);
|
||||
theta = std::acos((bb + cc - aa) / (2 * b * c));
|
||||
|
||||
//if (convex(in[npoints-2].x, in[npoints-2].y,
|
||||
// in[0].x, in[0].y,
|
||||
// in[1].x, in[1].y)) {
|
||||
if (OnLeftSideOfLine2D(in[npoints-2],in[1],in[0])) {
|
||||
convex_turn = AI_MATH_PI_F - theta;
|
||||
convex_sum += convex_turn;
|
||||
}
|
||||
else {
|
||||
convex_sum -= AI_MATH_PI_F - theta;
|
||||
}
|
||||
|
||||
return convex_sum >= (2 * AI_MATH_PI_F);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Compute the normal of an arbitrary polygon in R3.
|
||||
*
|
||||
* The code is based on Newell's formula, that is a polygons normal is the ratio
|
||||
* of its area when projected onto the three coordinate axes.
|
||||
*
|
||||
* @param out Receives the output normal
|
||||
* @param num Number of input vertices
|
||||
* @param x X data source. x[ofs_x*n] is the n'th element.
|
||||
* @param y Y data source. y[ofs_y*n] is the y'th element
|
||||
* @param z Z data source. z[ofs_z*n] is the z'th element
|
||||
*
|
||||
* @note The data arrays must have storage for at least num+2 elements. Using
|
||||
* this method is much faster than the 'other' NewellNormal()
|
||||
*/
|
||||
template <int ofs_x, int ofs_y, int ofs_z, typename TReal>
|
||||
inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, TReal* z)
|
||||
{
|
||||
// Duplicate the first two vertices at the end
|
||||
x[(num+0)*ofs_x] = x[0];
|
||||
x[(num+1)*ofs_x] = x[ofs_x];
|
||||
|
||||
y[(num+0)*ofs_y] = y[0];
|
||||
y[(num+1)*ofs_y] = y[ofs_y];
|
||||
|
||||
z[(num+0)*ofs_z] = z[0];
|
||||
z[(num+1)*ofs_z] = z[ofs_z];
|
||||
|
||||
TReal sum_xy = 0.0, sum_yz = 0.0, sum_zx = 0.0;
|
||||
|
||||
TReal *xptr = x +ofs_x, *xlow = x, *xhigh = x + ofs_x*2;
|
||||
TReal *yptr = y +ofs_y, *ylow = y, *yhigh = y + ofs_y*2;
|
||||
TReal *zptr = z +ofs_z, *zlow = z, *zhigh = z + ofs_z*2;
|
||||
|
||||
for (int tmp=0; tmp < num; tmp++) {
|
||||
sum_xy += (*xptr) * ( (*yhigh) - (*ylow) );
|
||||
sum_yz += (*yptr) * ( (*zhigh) - (*zlow) );
|
||||
sum_zx += (*zptr) * ( (*xhigh) - (*xlow) );
|
||||
|
||||
xptr += ofs_x;
|
||||
xlow += ofs_x;
|
||||
xhigh += ofs_x;
|
||||
|
||||
yptr += ofs_y;
|
||||
ylow += ofs_y;
|
||||
yhigh += ofs_y;
|
||||
|
||||
zptr += ofs_z;
|
||||
zlow += ofs_z;
|
||||
zhigh += ofs_z;
|
||||
}
|
||||
out = aiVector3t<TReal>(sum_yz,sum_zx,sum_xy);
|
||||
}
|
||||
|
||||
} // ! Assimp
|
||||
|
||||
#endif
|
||||
258
thirdparty/assimp/code/Common/PostStepRegistry.cpp
vendored
Normal file
258
thirdparty/assimp/code/Common/PostStepRegistry.cpp
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 ImporterRegistry.cpp
|
||||
|
||||
Central registry for all postprocessing steps available. Do not edit this file
|
||||
directly (unless you are adding new steps), instead use the
|
||||
corresponding preprocessor flag to selectively disable steps.
|
||||
*/
|
||||
|
||||
#include "PostProcessing/ProcessHelper.h"
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_CALCTANGENTS_PROCESS
|
||||
# include "PostProcessing/CalcTangentsProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_JOINVERTICES_PROCESS
|
||||
# include "PostProcessing/JoinVerticesProcess.h"
|
||||
#endif
|
||||
#if !(defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS && defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS && defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS)
|
||||
# include "PostProcessing/ConvertToLHProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
|
||||
# include "PostProcessing/TriangulateProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_DROPFACENORMALS_PROCESS
|
||||
# include "PostProcessing/DropFaceNormalsProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS
|
||||
# include "PostProcessing/GenFaceNormalsProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_GENVERTEXNORMALS_PROCESS
|
||||
# include "PostProcessing/GenVertexNormalsProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_REMOVEVC_PROCESS
|
||||
# include "PostProcessing/RemoveVCProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS
|
||||
# include "PostProcessing/SplitLargeMeshes.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS
|
||||
# include "PostProcessing/PretransformVertices.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS
|
||||
# include "PostProcessing/LimitBoneWeightsProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
|
||||
# include "PostProcessing/ValidateDataStructure.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS
|
||||
# include "PostProcessing/ImproveCacheLocality.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS
|
||||
# include "PostProcessing/FixNormalsStep.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS
|
||||
# include "PostProcessing/RemoveRedundantMaterials.h"
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_EMBEDTEXTURES_PROCESS)
|
||||
# include "PostProcessing/EmbedTexturesProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS
|
||||
# include "PostProcessing/FindInvalidDataProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS
|
||||
# include "PostProcessing/FindDegenerates.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_SORTBYPTYPE_PROCESS
|
||||
# include "PostProcessing/SortByPTypeProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_GENUVCOORDS_PROCESS
|
||||
# include "PostProcessing/ComputeUVMappingProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS
|
||||
# include "PostProcessing/TextureTransform.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_FINDINSTANCES_PROCESS
|
||||
# include "PostProcessing/FindInstancesProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
|
||||
# include "PostProcessing/OptimizeMeshes.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS
|
||||
# include "PostProcessing/OptimizeGraph.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS
|
||||
# include "Common/SplitByBoneCountProcess.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS
|
||||
# include "PostProcessing/DeboneProcess.h"
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
|
||||
# include "PostProcessing/ScaleProcess.h"
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS)
|
||||
# include "PostProcessing/GenBoundingBoxesProcess.h"
|
||||
#endif
|
||||
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
|
||||
{
|
||||
// ----------------------------------------------------------------------------
|
||||
// Add an instance of each post processing step here in the order
|
||||
// of sequence it is executed. Steps that are added here are not
|
||||
// validated - as RegisterPPStep() does - all dependencies must be given.
|
||||
// ----------------------------------------------------------------------------
|
||||
out.reserve(31);
|
||||
#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
|
||||
out.push_back( new MakeLeftHandedProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS)
|
||||
out.push_back( new FlipUVsProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS)
|
||||
out.push_back( new FlipWindingOrderProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_REMOVEVC_PROCESS)
|
||||
out.push_back( new RemoveVCProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
|
||||
out.push_back( new RemoveRedundantMatsProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_EMBEDTEXTURES_PROCESS)
|
||||
out.push_back( new EmbedTexturesProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_FINDINSTANCES_PROCESS)
|
||||
out.push_back( new FindInstancesProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
|
||||
out.push_back( new OptimizeGraphProcess());
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_GENUVCOORDS_PROCESS
|
||||
out.push_back( new ComputeUVMappingProcess());
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS
|
||||
out.push_back( new TextureTransformStep());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
|
||||
out.push_back( new ScaleProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
|
||||
out.push_back( new PretransformVertices());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_TRIANGULATE_PROCESS)
|
||||
out.push_back( new TriangulateProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS)
|
||||
//find degenerates should run after triangulation (to sort out small
|
||||
//generated triangles) but before sort by p types (in case there are lines
|
||||
//and points generated and inserted into a mesh)
|
||||
out.push_back( new FindDegeneratesProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_SORTBYPTYPE_PROCESS)
|
||||
out.push_back( new SortByPTypeProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS)
|
||||
out.push_back( new FindInvalidDataProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS)
|
||||
out.push_back( new OptimizeMeshesProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
|
||||
out.push_back( new FixInfacingNormalsProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS)
|
||||
out.push_back( new SplitByBoneCountProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
|
||||
out.push_back( new SplitLargeMeshesProcess_Triangle());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
|
||||
out.push_back( new DropFaceNormalsProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
|
||||
out.push_back( new GenFaceNormalsProcess());
|
||||
#endif
|
||||
// .........................................................................
|
||||
// DON'T change the order of these five ..
|
||||
// XXX this is actually a design weakness that dates back to the time
|
||||
// when Importer would maintain the postprocessing step list exclusively.
|
||||
// Now that others access it too, we need a better solution.
|
||||
out.push_back( new ComputeSpatialSortProcess());
|
||||
// .........................................................................
|
||||
|
||||
#if (!defined ASSIMP_BUILD_NO_GENVERTEXNORMALS_PROCESS)
|
||||
out.push_back( new GenVertexNormalsProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_CALCTANGENTS_PROCESS)
|
||||
out.push_back( new CalcTangentsProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_JOINVERTICES_PROCESS)
|
||||
out.push_back( new JoinVerticesProcess());
|
||||
#endif
|
||||
|
||||
// .........................................................................
|
||||
out.push_back( new DestroySpatialSortProcess());
|
||||
// .........................................................................
|
||||
|
||||
#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
|
||||
out.push_back( new SplitLargeMeshesProcess_Vertex());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_DEBONE_PROCESS)
|
||||
out.push_back( new DeboneProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS)
|
||||
out.push_back( new LimitBoneWeightsProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS)
|
||||
out.push_back( new ImproveCacheLocalityProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS)
|
||||
out.push_back(new GenBoundingBoxesProcess);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
113
thirdparty/assimp/code/Common/RemoveComments.cpp
vendored
Normal file
113
thirdparty/assimp/code/Common/RemoveComments.cpp
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
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 RemoveComments.cpp
|
||||
* @brief Defines the CommentRemover utility class
|
||||
*/
|
||||
|
||||
#include <assimp/RemoveComments.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Remove line comments from a file
|
||||
void CommentRemover::RemoveLineComments(const char* szComment,
|
||||
char* szBuffer, char chReplacement /* = ' ' */)
|
||||
{
|
||||
// validate parameters
|
||||
ai_assert(NULL != szComment && NULL != szBuffer && *szComment);
|
||||
|
||||
const size_t len = strlen(szComment);
|
||||
while (*szBuffer) {
|
||||
|
||||
// skip over quotes
|
||||
if (*szBuffer == '\"' || *szBuffer == '\'')
|
||||
while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\'');
|
||||
|
||||
if (!strncmp(szBuffer,szComment,len)) {
|
||||
while (!IsLineEnd(*szBuffer))
|
||||
*szBuffer++ = chReplacement;
|
||||
|
||||
if (!*szBuffer) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
++szBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Remove multi-line comments from a file
|
||||
void CommentRemover::RemoveMultiLineComments(const char* szCommentStart,
|
||||
const char* szCommentEnd,char* szBuffer,
|
||||
char chReplacement)
|
||||
{
|
||||
// validate parameters
|
||||
ai_assert(NULL != szCommentStart && NULL != szCommentEnd &&
|
||||
NULL != szBuffer && *szCommentStart && *szCommentEnd);
|
||||
|
||||
const size_t len = strlen(szCommentEnd);
|
||||
const size_t len2 = strlen(szCommentStart);
|
||||
|
||||
while (*szBuffer) {
|
||||
// skip over quotes
|
||||
if (*szBuffer == '\"' || *szBuffer == '\'')
|
||||
while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\'');
|
||||
|
||||
if (!strncmp(szBuffer,szCommentStart,len2)) {
|
||||
while (*szBuffer) {
|
||||
if (!::strncmp(szBuffer,szCommentEnd,len)) {
|
||||
for (unsigned int i = 0; i < len;++i)
|
||||
*szBuffer++ = chReplacement;
|
||||
|
||||
break;
|
||||
}
|
||||
*szBuffer++ = chReplacement;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
++szBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
} // !! Assimp
|
||||
168
thirdparty/assimp/code/Common/SGSpatialSort.cpp
vendored
Normal file
168
thirdparty/assimp/code/Common/SGSpatialSort.cpp
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 Implementation of the helper class to quickly find
|
||||
vertices close to a given position. Special implementation for
|
||||
the 3ds loader handling smooth groups correctly */
|
||||
|
||||
#include <assimp/SGSpatialSort.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SGSpatialSort::SGSpatialSort()
|
||||
{
|
||||
// define the reference plane. We choose some arbitrary vector away from all basic axises
|
||||
// in the hope that no model spreads all its vertices along this plane.
|
||||
mPlaneNormal.Set( 0.8523f, 0.34321f, 0.5736f);
|
||||
mPlaneNormal.Normalize();
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
SGSpatialSort::~SGSpatialSort()
|
||||
{
|
||||
// nothing to do here, everything destructs automatically
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SGSpatialSort::Add(const aiVector3D& vPosition, unsigned int index,
|
||||
unsigned int smoothingGroup)
|
||||
{
|
||||
// store position by index and distance
|
||||
float distance = vPosition * mPlaneNormal;
|
||||
mPositions.push_back( Entry( index, vPosition,
|
||||
distance, smoothingGroup));
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SGSpatialSort::Prepare()
|
||||
{
|
||||
// now sort the array ascending by distance.
|
||||
std::sort( this->mPositions.begin(), this->mPositions.end());
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns an iterator for all positions close to the given position.
|
||||
void SGSpatialSort::FindPositions( const aiVector3D& pPosition,
|
||||
uint32_t pSG,
|
||||
float pRadius,
|
||||
std::vector<unsigned int>& poResults,
|
||||
bool exactMatch /*= false*/) const
|
||||
{
|
||||
float dist = pPosition * mPlaneNormal;
|
||||
float minDist = dist - pRadius, maxDist = dist + pRadius;
|
||||
|
||||
// clear the array
|
||||
poResults.clear();
|
||||
|
||||
// quick check for positions outside the range
|
||||
if( mPositions.empty() )
|
||||
return;
|
||||
if( maxDist < mPositions.front().mDistance)
|
||||
return;
|
||||
if( minDist > mPositions.back().mDistance)
|
||||
return;
|
||||
|
||||
// do a binary search for the minimal distance to start the iteration there
|
||||
unsigned int index = (unsigned int)mPositions.size() / 2;
|
||||
unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4;
|
||||
while( binaryStepSize > 1)
|
||||
{
|
||||
if( mPositions[index].mDistance < minDist)
|
||||
index += binaryStepSize;
|
||||
else
|
||||
index -= binaryStepSize;
|
||||
|
||||
binaryStepSize /= 2;
|
||||
}
|
||||
|
||||
// depending on the direction of the last step we need to single step a bit back or forth
|
||||
// to find the actual beginning element of the range
|
||||
while( index > 0 && mPositions[index].mDistance > minDist)
|
||||
index--;
|
||||
while( index < (mPositions.size() - 1) && mPositions[index].mDistance < minDist)
|
||||
index++;
|
||||
|
||||
// Mow start iterating from there until the first position lays outside of the distance range.
|
||||
// Add all positions inside the distance range within the given radius to the result aray
|
||||
|
||||
float squareEpsilon = pRadius * pRadius;
|
||||
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
|
||||
std::vector<Entry>::const_iterator end = mPositions.end();
|
||||
|
||||
if (exactMatch)
|
||||
{
|
||||
while( it->mDistance < maxDist)
|
||||
{
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon && it->mSmoothGroups == pSG)
|
||||
{
|
||||
poResults.push_back( it->mIndex);
|
||||
}
|
||||
++it;
|
||||
if( end == it )break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the given smoothing group is 0, we'll return all surrounding vertices
|
||||
if (!pSG)
|
||||
{
|
||||
while( it->mDistance < maxDist)
|
||||
{
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon)
|
||||
poResults.push_back( it->mIndex);
|
||||
++it;
|
||||
if( end == it)break;
|
||||
}
|
||||
}
|
||||
else while( it->mDistance < maxDist)
|
||||
{
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon &&
|
||||
(it->mSmoothGroups & pSG || !it->mSmoothGroups))
|
||||
{
|
||||
poResults.push_back( it->mIndex);
|
||||
}
|
||||
++it;
|
||||
if( end == it)break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1329
thirdparty/assimp/code/Common/SceneCombiner.cpp
vendored
Normal file
1329
thirdparty/assimp/code/Common/SceneCombiner.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
261
thirdparty/assimp/code/Common/ScenePreprocessor.cpp
vendored
Normal file
261
thirdparty/assimp/code/Common/ScenePreprocessor.cpp
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "ScenePreprocessor.h"
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
void ScenePreprocessor::ProcessScene ()
|
||||
{
|
||||
ai_assert(scene != NULL);
|
||||
|
||||
// Process all meshes
|
||||
for (unsigned int i = 0; i < scene->mNumMeshes;++i)
|
||||
ProcessMesh(scene->mMeshes[i]);
|
||||
|
||||
// - nothing to do for nodes for the moment
|
||||
// - nothing to do for textures for the moment
|
||||
// - nothing to do for lights for the moment
|
||||
// - nothing to do for cameras for the moment
|
||||
|
||||
// Process all animations
|
||||
for (unsigned int i = 0; i < scene->mNumAnimations;++i)
|
||||
ProcessAnimation(scene->mAnimations[i]);
|
||||
|
||||
// Generate a default material if none was specified
|
||||
if (!scene->mNumMaterials && scene->mNumMeshes) {
|
||||
scene->mMaterials = new aiMaterial*[2];
|
||||
aiMaterial* helper;
|
||||
|
||||
aiString name;
|
||||
|
||||
scene->mMaterials[scene->mNumMaterials] = helper = new aiMaterial();
|
||||
aiColor3D clr(0.6f,0.6f,0.6f);
|
||||
helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
|
||||
|
||||
// setup the default name to make this material identifiable
|
||||
name.Set(AI_DEFAULT_MATERIAL_NAME);
|
||||
helper->AddProperty(&name,AI_MATKEY_NAME);
|
||||
|
||||
ASSIMP_LOG_DEBUG("ScenePreprocessor: Adding default material \'" AI_DEFAULT_MATERIAL_NAME "\'");
|
||||
|
||||
for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
|
||||
scene->mMeshes[i]->mMaterialIndex = scene->mNumMaterials;
|
||||
}
|
||||
|
||||
scene->mNumMaterials++;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
void ScenePreprocessor::ProcessMesh (aiMesh* mesh)
|
||||
{
|
||||
// If aiMesh::mNumUVComponents is *not* set assign the default value of 2
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
if (!mesh->mTextureCoords[i]) {
|
||||
mesh->mNumUVComponents[i] = 0;
|
||||
} else {
|
||||
if (!mesh->mNumUVComponents[i])
|
||||
mesh->mNumUVComponents[i] = 2;
|
||||
|
||||
aiVector3D* p = mesh->mTextureCoords[i], *end = p+mesh->mNumVertices;
|
||||
|
||||
// Ensure unused components are zeroed. This will make 1D texture channels work
|
||||
// as if they were 2D channels .. just in case an application doesn't handle
|
||||
// this case
|
||||
if (2 == mesh->mNumUVComponents[i]) {
|
||||
for (; p != end; ++p)
|
||||
p->z = 0.f;
|
||||
}
|
||||
else if (1 == mesh->mNumUVComponents[i]) {
|
||||
for (; p != end; ++p)
|
||||
p->z = p->y = 0.f;
|
||||
}
|
||||
else if (3 == mesh->mNumUVComponents[i]) {
|
||||
// Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element
|
||||
for (; p != end; ++p) {
|
||||
if (p->z != 0)
|
||||
break;
|
||||
}
|
||||
if (p == end) {
|
||||
ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D.");
|
||||
mesh->mNumUVComponents[i] = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the information which primitive types are there in the
|
||||
// mesh is currently not available, compute it.
|
||||
if (!mesh->mPrimitiveTypes) {
|
||||
for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
|
||||
aiFace& face = mesh->mFaces[a];
|
||||
switch (face.mNumIndices)
|
||||
{
|
||||
case 3u:
|
||||
mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
break;
|
||||
|
||||
case 2u:
|
||||
mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
||||
break;
|
||||
|
||||
case 1u:
|
||||
mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
||||
break;
|
||||
|
||||
default:
|
||||
mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If tangents and normals are given but no bitangents compute them
|
||||
if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) {
|
||||
|
||||
mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices;++i) {
|
||||
mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
|
||||
{
|
||||
double first = 10e10, last = -10e10;
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
||||
aiNodeAnim* channel = anim->mChannels[i];
|
||||
|
||||
/* If the exact duration of the animation is not given
|
||||
* compute it now.
|
||||
*/
|
||||
if (anim->mDuration == -1.) {
|
||||
|
||||
// Position keys
|
||||
for (unsigned int j = 0; j < channel->mNumPositionKeys;++j) {
|
||||
aiVectorKey& key = channel->mPositionKeys[j];
|
||||
first = std::min (first, key.mTime);
|
||||
last = std::max (last, key.mTime);
|
||||
}
|
||||
|
||||
// Scaling keys
|
||||
for (unsigned int j = 0; j < channel->mNumScalingKeys;++j ) {
|
||||
aiVectorKey& key = channel->mScalingKeys[j];
|
||||
first = std::min (first, key.mTime);
|
||||
last = std::max (last, key.mTime);
|
||||
}
|
||||
|
||||
// Rotation keys
|
||||
for (unsigned int j = 0; j < channel->mNumRotationKeys;++j ) {
|
||||
aiQuatKey& key = channel->mRotationKeys[ j ];
|
||||
first = std::min (first, key.mTime);
|
||||
last = std::max (last, key.mTime);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether the animation channel has no rotation
|
||||
* or position tracks. In this case we generate a dummy
|
||||
* track from the information we have in the transformation
|
||||
* matrix of the corresponding node.
|
||||
*/
|
||||
if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) {
|
||||
// Find the node that belongs to this animation
|
||||
aiNode* node = scene->mRootNode->FindNode(channel->mNodeName);
|
||||
if (node) // ValidateDS will complain later if 'node' is NULL
|
||||
{
|
||||
// Decompose the transformation matrix of the node
|
||||
aiVector3D scaling, position;
|
||||
aiQuaternion rotation;
|
||||
|
||||
node->mTransformation.Decompose(scaling, rotation,position);
|
||||
|
||||
// No rotation keys? Generate a dummy track
|
||||
if (!channel->mNumRotationKeys) {
|
||||
channel->mNumRotationKeys = 1;
|
||||
channel->mRotationKeys = new aiQuatKey[1];
|
||||
aiQuatKey& q = channel->mRotationKeys[0];
|
||||
|
||||
q.mTime = 0.;
|
||||
q.mValue = rotation;
|
||||
|
||||
ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy rotation track has been generated");
|
||||
}
|
||||
|
||||
// No scaling keys? Generate a dummy track
|
||||
if (!channel->mNumScalingKeys) {
|
||||
channel->mNumScalingKeys = 1;
|
||||
channel->mScalingKeys = new aiVectorKey[1];
|
||||
aiVectorKey& q = channel->mScalingKeys[0];
|
||||
|
||||
q.mTime = 0.;
|
||||
q.mValue = scaling;
|
||||
|
||||
ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy scaling track has been generated");
|
||||
}
|
||||
|
||||
// No position keys? Generate a dummy track
|
||||
if (!channel->mNumPositionKeys) {
|
||||
channel->mNumPositionKeys = 1;
|
||||
channel->mPositionKeys = new aiVectorKey[1];
|
||||
aiVectorKey& q = channel->mPositionKeys[0];
|
||||
|
||||
q.mTime = 0.;
|
||||
q.mValue = position;
|
||||
|
||||
ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy position track has been generated");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (anim->mDuration == -1.) {
|
||||
ASSIMP_LOG_DEBUG("ScenePreprocessor: Setting animation duration");
|
||||
anim->mDuration = last - std::min( first, 0. );
|
||||
}
|
||||
}
|
||||
125
thirdparty/assimp/code/Common/ScenePreprocessor.h
vendored
Normal file
125
thirdparty/assimp/code/Common/ScenePreprocessor.h
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
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 Defines a post processing step to search all meshes for
|
||||
degenerated faces */
|
||||
#ifndef AI_SCENE_PREPROCESSOR_H_INC
|
||||
#define AI_SCENE_PREPROCESSOR_H_INC
|
||||
|
||||
#include <assimp/defs.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct aiScene;
|
||||
struct aiAnimation;
|
||||
struct aiMesh;
|
||||
|
||||
class ScenePreprocessorTest;
|
||||
namespace Assimp {
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
/** ScenePreprocessor: Preprocess a scene before any post-processing
|
||||
* steps are executed.
|
||||
*
|
||||
* The step computes data that needn't necessarily be provided by the
|
||||
* importer, such as aiMesh::mPrimitiveTypes.
|
||||
*/
|
||||
// ----------------------------------------------------------------------------------
|
||||
class ASSIMP_API ScenePreprocessor
|
||||
{
|
||||
// Make ourselves a friend of the corresponding test unit.
|
||||
friend class ::ScenePreprocessorTest;
|
||||
public:
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
/** Default c'tpr. Use SetScene() to assign a scene to the object.
|
||||
*/
|
||||
ScenePreprocessor()
|
||||
: scene (NULL)
|
||||
{}
|
||||
|
||||
/** Constructs the object and assigns a specific scene to it
|
||||
*/
|
||||
ScenePreprocessor(aiScene* _scene)
|
||||
: scene (_scene)
|
||||
{}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
/** Assign a (new) scene to the object.
|
||||
*
|
||||
* One 'SceneProcessor' can be used for multiple scenes.
|
||||
* Call ProcessScene to have the scene preprocessed.
|
||||
* @param sc Scene to be processed.
|
||||
*/
|
||||
void SetScene (aiScene* sc) {
|
||||
scene = sc;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
/** Preprocess the current scene
|
||||
*/
|
||||
void ProcessScene ();
|
||||
|
||||
protected:
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
/** Preprocess an animation in the scene
|
||||
* @param anim Anim to be preprocessed.
|
||||
*/
|
||||
void ProcessAnimation (aiAnimation* anim);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
/** Preprocess a mesh in the scene
|
||||
* @param mesh Mesh to be preprocessed.
|
||||
*/
|
||||
void ProcessMesh (aiMesh* mesh);
|
||||
|
||||
protected:
|
||||
|
||||
//! Scene we're currently working on
|
||||
aiScene* scene;
|
||||
};
|
||||
|
||||
|
||||
} // ! end namespace Assimp
|
||||
|
||||
#endif // include guard
|
||||
105
thirdparty/assimp/code/Common/ScenePrivate.h
vendored
Normal file
105
thirdparty/assimp/code/Common/ScenePrivate.h
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
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 Stuff to deal with aiScene::mPrivate
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef AI_SCENEPRIVATE_H_INCLUDED
|
||||
#define AI_SCENEPRIVATE_H_INCLUDED
|
||||
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/scene.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// Forward declarations
|
||||
class Importer;
|
||||
|
||||
struct ScenePrivateData {
|
||||
// The struct constructor.
|
||||
ScenePrivateData() AI_NO_EXCEPT;
|
||||
|
||||
// Importer that originally loaded the scene though the C-API
|
||||
// If set, this object is owned by this private data instance.
|
||||
Assimp::Importer* mOrigImporter;
|
||||
|
||||
// List of post-processing steps already applied to the scene.
|
||||
unsigned int mPPStepsApplied;
|
||||
|
||||
// true if the scene is a copy made with aiCopyScene()
|
||||
// or the corresponding C++ API. This means that user code
|
||||
// may have made modifications to it, so mPPStepsApplied
|
||||
// and mOrigImporter are no longer safe to rely on and only
|
||||
// serve informative purposes.
|
||||
bool mIsCopy;
|
||||
};
|
||||
|
||||
inline
|
||||
ScenePrivateData::ScenePrivateData() AI_NO_EXCEPT
|
||||
: mOrigImporter( nullptr )
|
||||
, mPPStepsApplied( 0 )
|
||||
, mIsCopy( false ) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// Access private data stored in the scene
|
||||
inline
|
||||
ScenePrivateData* ScenePriv(aiScene* in) {
|
||||
ai_assert( nullptr != in );
|
||||
if ( nullptr == in ) {
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<ScenePrivateData*>(in->mPrivate);
|
||||
}
|
||||
|
||||
inline
|
||||
const ScenePrivateData* ScenePriv(const aiScene* in) {
|
||||
ai_assert( nullptr != in );
|
||||
if ( nullptr == in ) {
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<const ScenePrivateData*>(in->mPrivate);
|
||||
}
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // AI_SCENEPRIVATE_H_INCLUDED
|
||||
270
thirdparty/assimp/code/Common/SkeletonMeshBuilder.cpp
vendored
Normal file
270
thirdparty/assimp/code/Common/SkeletonMeshBuilder.cpp
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
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 SkeletonMeshBuilder.cpp
|
||||
* @brief Implementation of a little class to construct a dummy mesh for a skeleton
|
||||
*/
|
||||
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/SkeletonMeshBuilder.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// The constructor processes the given scene and adds a mesh there.
|
||||
SkeletonMeshBuilder::SkeletonMeshBuilder( aiScene* pScene, aiNode* root, bool bKnobsOnly)
|
||||
{
|
||||
// nothing to do if there's mesh data already present at the scene
|
||||
if( pScene->mNumMeshes > 0 || pScene->mRootNode == NULL)
|
||||
return;
|
||||
|
||||
if (!root)
|
||||
root = pScene->mRootNode;
|
||||
|
||||
mKnobsOnly = bKnobsOnly;
|
||||
|
||||
// build some faces around each node
|
||||
CreateGeometry( root );
|
||||
|
||||
// create a mesh to hold all the generated faces
|
||||
pScene->mNumMeshes = 1;
|
||||
pScene->mMeshes = new aiMesh*[1];
|
||||
pScene->mMeshes[0] = CreateMesh();
|
||||
// and install it at the root node
|
||||
root->mNumMeshes = 1;
|
||||
root->mMeshes = new unsigned int[1];
|
||||
root->mMeshes[0] = 0;
|
||||
|
||||
// create a dummy material for the mesh
|
||||
if(pScene->mNumMaterials==0){
|
||||
pScene->mNumMaterials = 1;
|
||||
pScene->mMaterials = new aiMaterial*[1];
|
||||
pScene->mMaterials[0] = CreateMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively builds a simple mesh representation for the given node
|
||||
void SkeletonMeshBuilder::CreateGeometry( const aiNode* pNode)
|
||||
{
|
||||
// add a joint entry for the node.
|
||||
const unsigned int vertexStartIndex = static_cast<unsigned int>(mVertices.size());
|
||||
|
||||
// now build the geometry.
|
||||
if( pNode->mNumChildren > 0 && !mKnobsOnly)
|
||||
{
|
||||
// If the node has children, we build little pointers to each of them
|
||||
for( unsigned int a = 0; a < pNode->mNumChildren; a++)
|
||||
{
|
||||
// find a suitable coordinate system
|
||||
const aiMatrix4x4& childTransform = pNode->mChildren[a]->mTransformation;
|
||||
aiVector3D childpos( childTransform.a4, childTransform.b4, childTransform.c4);
|
||||
ai_real distanceToChild = childpos.Length();
|
||||
if( distanceToChild < 0.0001)
|
||||
continue;
|
||||
aiVector3D up = aiVector3D( childpos).Normalize();
|
||||
|
||||
aiVector3D orth( 1.0, 0.0, 0.0);
|
||||
if( std::fabs( orth * up) > 0.99)
|
||||
orth.Set( 0.0, 1.0, 0.0);
|
||||
|
||||
aiVector3D front = (up ^ orth).Normalize();
|
||||
aiVector3D side = (front ^ up).Normalize();
|
||||
|
||||
unsigned int localVertexStart = static_cast<unsigned int>(mVertices.size());
|
||||
mVertices.push_back( -front * distanceToChild * (ai_real)0.1);
|
||||
mVertices.push_back( childpos);
|
||||
mVertices.push_back( -side * distanceToChild * (ai_real)0.1);
|
||||
mVertices.push_back( -side * distanceToChild * (ai_real)0.1);
|
||||
mVertices.push_back( childpos);
|
||||
mVertices.push_back( front * distanceToChild * (ai_real)0.1);
|
||||
mVertices.push_back( front * distanceToChild * (ai_real)0.1);
|
||||
mVertices.push_back( childpos);
|
||||
mVertices.push_back( side * distanceToChild * (ai_real)0.1);
|
||||
mVertices.push_back( side * distanceToChild * (ai_real)0.1);
|
||||
mVertices.push_back( childpos);
|
||||
mVertices.push_back( -front * distanceToChild * (ai_real)0.1);
|
||||
|
||||
mFaces.push_back( Face( localVertexStart + 0, localVertexStart + 1, localVertexStart + 2));
|
||||
mFaces.push_back( Face( localVertexStart + 3, localVertexStart + 4, localVertexStart + 5));
|
||||
mFaces.push_back( Face( localVertexStart + 6, localVertexStart + 7, localVertexStart + 8));
|
||||
mFaces.push_back( Face( localVertexStart + 9, localVertexStart + 10, localVertexStart + 11));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the node has no children, it's an end node. Put a little knob there instead
|
||||
aiVector3D ownpos( pNode->mTransformation.a4, pNode->mTransformation.b4, pNode->mTransformation.c4);
|
||||
ai_real sizeEstimate = ownpos.Length() * ai_real( 0.18 );
|
||||
|
||||
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0));
|
||||
mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0));
|
||||
mVertices.push_back( aiVector3D( 0.0, 0.0, -sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0));
|
||||
mVertices.push_back( aiVector3D( sizeEstimate, 0.0, 0.0));
|
||||
mVertices.push_back( aiVector3D( 0.0, 0.0, -sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( sizeEstimate, 0.0, 0.0));
|
||||
mVertices.push_back( aiVector3D( 0.0, -sizeEstimate, 0.0));
|
||||
mVertices.push_back( aiVector3D( 0.0, 0.0, -sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( 0.0, -sizeEstimate, 0.0));
|
||||
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0));
|
||||
mVertices.push_back( aiVector3D( 0.0, 0.0, -sizeEstimate));
|
||||
|
||||
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0));
|
||||
mVertices.push_back( aiVector3D( 0.0, 0.0, sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0));
|
||||
mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0));
|
||||
mVertices.push_back( aiVector3D( 0.0, 0.0, sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( sizeEstimate, 0.0, 0.0));
|
||||
mVertices.push_back( aiVector3D( sizeEstimate, 0.0, 0.0));
|
||||
mVertices.push_back( aiVector3D( 0.0, 0.0, sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( 0.0, -sizeEstimate, 0.0));
|
||||
mVertices.push_back( aiVector3D( 0.0, -sizeEstimate, 0.0));
|
||||
mVertices.push_back( aiVector3D( 0.0, 0.0, sizeEstimate));
|
||||
mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0));
|
||||
|
||||
mFaces.push_back( Face( vertexStartIndex + 0, vertexStartIndex + 1, vertexStartIndex + 2));
|
||||
mFaces.push_back( Face( vertexStartIndex + 3, vertexStartIndex + 4, vertexStartIndex + 5));
|
||||
mFaces.push_back( Face( vertexStartIndex + 6, vertexStartIndex + 7, vertexStartIndex + 8));
|
||||
mFaces.push_back( Face( vertexStartIndex + 9, vertexStartIndex + 10, vertexStartIndex + 11));
|
||||
mFaces.push_back( Face( vertexStartIndex + 12, vertexStartIndex + 13, vertexStartIndex + 14));
|
||||
mFaces.push_back( Face( vertexStartIndex + 15, vertexStartIndex + 16, vertexStartIndex + 17));
|
||||
mFaces.push_back( Face( vertexStartIndex + 18, vertexStartIndex + 19, vertexStartIndex + 20));
|
||||
mFaces.push_back( Face( vertexStartIndex + 21, vertexStartIndex + 22, vertexStartIndex + 23));
|
||||
}
|
||||
|
||||
unsigned int numVertices = static_cast<unsigned int>(mVertices.size() - vertexStartIndex);
|
||||
if( numVertices > 0)
|
||||
{
|
||||
// create a bone affecting all the newly created vertices
|
||||
aiBone* bone = new aiBone;
|
||||
mBones.push_back( bone);
|
||||
bone->mName = pNode->mName;
|
||||
|
||||
// calculate the bone offset matrix by concatenating the inverse transformations of all parents
|
||||
bone->mOffsetMatrix = aiMatrix4x4( pNode->mTransformation).Inverse();
|
||||
for( aiNode* parent = pNode->mParent; parent != NULL; parent = parent->mParent)
|
||||
bone->mOffsetMatrix = aiMatrix4x4( parent->mTransformation).Inverse() * bone->mOffsetMatrix;
|
||||
|
||||
// add all the vertices to the bone's influences
|
||||
bone->mNumWeights = numVertices;
|
||||
bone->mWeights = new aiVertexWeight[numVertices];
|
||||
for( unsigned int a = 0; a < numVertices; a++)
|
||||
bone->mWeights[a] = aiVertexWeight( vertexStartIndex + a, 1.0);
|
||||
|
||||
// HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
|
||||
// them to the array, but I'm tired now and I'm annoyed.
|
||||
aiMatrix4x4 boneToMeshTransform = aiMatrix4x4( bone->mOffsetMatrix).Inverse();
|
||||
for( unsigned int a = vertexStartIndex; a < mVertices.size(); a++)
|
||||
mVertices[a] = boneToMeshTransform * mVertices[a];
|
||||
}
|
||||
|
||||
// and finally recurse into the children list
|
||||
for( unsigned int a = 0; a < pNode->mNumChildren; a++)
|
||||
CreateGeometry( pNode->mChildren[a]);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Creates the mesh from the internally accumulated stuff and returns it.
|
||||
aiMesh* SkeletonMeshBuilder::CreateMesh()
|
||||
{
|
||||
aiMesh* mesh = new aiMesh();
|
||||
|
||||
// add points
|
||||
mesh->mNumVertices = static_cast<unsigned int>(mVertices.size());
|
||||
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
||||
std::copy( mVertices.begin(), mVertices.end(), mesh->mVertices);
|
||||
|
||||
mesh->mNormals = new aiVector3D[mesh->mNumVertices];
|
||||
|
||||
// add faces
|
||||
mesh->mNumFaces = static_cast<unsigned int>(mFaces.size());
|
||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||
for( unsigned int a = 0; a < mesh->mNumFaces; a++)
|
||||
{
|
||||
const Face& inface = mFaces[a];
|
||||
aiFace& outface = mesh->mFaces[a];
|
||||
outface.mNumIndices = 3;
|
||||
outface.mIndices = new unsigned int[3];
|
||||
outface.mIndices[0] = inface.mIndices[0];
|
||||
outface.mIndices[1] = inface.mIndices[1];
|
||||
outface.mIndices[2] = inface.mIndices[2];
|
||||
|
||||
// Compute per-face normals ... we don't want the bones to be smoothed ... they're built to visualize
|
||||
// the skeleton, so it's good if there's a visual difference to the rest of the geometry
|
||||
aiVector3D nor = ((mVertices[inface.mIndices[2]] - mVertices[inface.mIndices[0]]) ^
|
||||
(mVertices[inface.mIndices[1]] - mVertices[inface.mIndices[0]]));
|
||||
|
||||
if (nor.Length() < 1e-5) /* ensure that FindInvalidData won't remove us ...*/
|
||||
nor = aiVector3D(1.0,0.0,0.0);
|
||||
|
||||
for (unsigned int n = 0; n < 3; ++n)
|
||||
mesh->mNormals[inface.mIndices[n]] = nor;
|
||||
}
|
||||
|
||||
// add the bones
|
||||
mesh->mNumBones = static_cast<unsigned int>(mBones.size());
|
||||
mesh->mBones = new aiBone*[mesh->mNumBones];
|
||||
std::copy( mBones.begin(), mBones.end(), mesh->mBones);
|
||||
|
||||
// default
|
||||
mesh->mMaterialIndex = 0;
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Creates a dummy material and returns it.
|
||||
aiMaterial* SkeletonMeshBuilder::CreateMaterial()
|
||||
{
|
||||
aiMaterial* matHelper = new aiMaterial;
|
||||
|
||||
// Name
|
||||
aiString matName( std::string( "SkeletonMaterial"));
|
||||
matHelper->AddProperty( &matName, AI_MATKEY_NAME);
|
||||
|
||||
// Prevent backface culling
|
||||
const int no_cull = 1;
|
||||
matHelper->AddProperty(&no_cull,1,AI_MATKEY_TWOSIDED);
|
||||
|
||||
return matHelper;
|
||||
}
|
||||
342
thirdparty/assimp/code/Common/SpatialSort.cpp
vendored
Normal file
342
thirdparty/assimp/code/Common/SpatialSort.cpp
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 Implementation of the helper class to quickly find vertices close to a given position */
|
||||
|
||||
#include <assimp/SpatialSort.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// CHAR_BIT seems to be defined under MVSC, but not under GCC. Pray that the correct value is 8.
|
||||
#ifndef CHAR_BIT
|
||||
# define CHAR_BIT 8
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructs a spatially sorted representation from the given position array.
|
||||
SpatialSort::SpatialSort( const aiVector3D* pPositions, unsigned int pNumPositions,
|
||||
unsigned int pElementOffset)
|
||||
|
||||
// define the reference plane. We choose some arbitrary vector away from all basic axises
|
||||
// in the hope that no model spreads all its vertices along this plane.
|
||||
: mPlaneNormal(0.8523f, 0.34321f, 0.5736f)
|
||||
{
|
||||
mPlaneNormal.Normalize();
|
||||
Fill(pPositions,pNumPositions,pElementOffset);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SpatialSort :: SpatialSort()
|
||||
: mPlaneNormal(0.8523f, 0.34321f, 0.5736f)
|
||||
{
|
||||
mPlaneNormal.Normalize();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
SpatialSort::~SpatialSort()
|
||||
{
|
||||
// nothing to do here, everything destructs automatically
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SpatialSort::Fill( const aiVector3D* pPositions, unsigned int pNumPositions,
|
||||
unsigned int pElementOffset,
|
||||
bool pFinalize /*= true */)
|
||||
{
|
||||
mPositions.clear();
|
||||
Append(pPositions,pNumPositions,pElementOffset,pFinalize);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SpatialSort :: Finalize()
|
||||
{
|
||||
std::sort( mPositions.begin(), mPositions.end());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SpatialSort::Append( const aiVector3D* pPositions, unsigned int pNumPositions,
|
||||
unsigned int pElementOffset,
|
||||
bool pFinalize /*= true */)
|
||||
{
|
||||
// store references to all given positions along with their distance to the reference plane
|
||||
const size_t initial = mPositions.size();
|
||||
mPositions.reserve(initial + (pFinalize?pNumPositions:pNumPositions*2));
|
||||
for( unsigned int a = 0; a < pNumPositions; a++)
|
||||
{
|
||||
const char* tempPointer = reinterpret_cast<const char*> (pPositions);
|
||||
const aiVector3D* vec = reinterpret_cast<const aiVector3D*> (tempPointer + a * pElementOffset);
|
||||
|
||||
// store position by index and distance
|
||||
ai_real distance = *vec * mPlaneNormal;
|
||||
mPositions.push_back( Entry( static_cast<unsigned int>(a+initial), *vec, distance));
|
||||
}
|
||||
|
||||
if (pFinalize) {
|
||||
// now sort the array ascending by distance.
|
||||
Finalize();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns an iterator for all positions close to the given position.
|
||||
void SpatialSort::FindPositions( const aiVector3D& pPosition,
|
||||
ai_real pRadius, std::vector<unsigned int>& poResults) const
|
||||
{
|
||||
const ai_real dist = pPosition * mPlaneNormal;
|
||||
const ai_real minDist = dist - pRadius, maxDist = dist + pRadius;
|
||||
|
||||
// clear the array
|
||||
poResults.clear();
|
||||
|
||||
// quick check for positions outside the range
|
||||
if( mPositions.size() == 0)
|
||||
return;
|
||||
if( maxDist < mPositions.front().mDistance)
|
||||
return;
|
||||
if( minDist > mPositions.back().mDistance)
|
||||
return;
|
||||
|
||||
// do a binary search for the minimal distance to start the iteration there
|
||||
unsigned int index = (unsigned int)mPositions.size() / 2;
|
||||
unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4;
|
||||
while( binaryStepSize > 1)
|
||||
{
|
||||
if( mPositions[index].mDistance < minDist)
|
||||
index += binaryStepSize;
|
||||
else
|
||||
index -= binaryStepSize;
|
||||
|
||||
binaryStepSize /= 2;
|
||||
}
|
||||
|
||||
// depending on the direction of the last step we need to single step a bit back or forth
|
||||
// to find the actual beginning element of the range
|
||||
while( index > 0 && mPositions[index].mDistance > minDist)
|
||||
index--;
|
||||
while( index < (mPositions.size() - 1) && mPositions[index].mDistance < minDist)
|
||||
index++;
|
||||
|
||||
// Mow start iterating from there until the first position lays outside of the distance range.
|
||||
// Add all positions inside the distance range within the given radius to the result aray
|
||||
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
|
||||
const ai_real pSquared = pRadius*pRadius;
|
||||
while( it->mDistance < maxDist)
|
||||
{
|
||||
if( (it->mPosition - pPosition).SquareLength() < pSquared)
|
||||
poResults.push_back( it->mIndex);
|
||||
++it;
|
||||
if( it == mPositions.end())
|
||||
break;
|
||||
}
|
||||
|
||||
// that's it
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Binary, signed-integer representation of a single-precision floating-point value.
|
||||
// IEEE 754 says: "If two floating-point numbers in the same format are ordered then they are
|
||||
// ordered the same way when their bits are reinterpreted as sign-magnitude integers."
|
||||
// This allows us to convert all floating-point numbers to signed integers of arbitrary size
|
||||
// and then use them to work with ULPs (Units in the Last Place, for high-precision
|
||||
// computations) or to compare them (integer comparisons are faster than floating-point
|
||||
// comparisons on many platforms).
|
||||
typedef ai_int BinFloat;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// Converts the bit pattern of a floating-point number to its signed integer representation.
|
||||
BinFloat ToBinary( const ai_real & pValue) {
|
||||
|
||||
// If this assertion fails, signed int is not big enough to store a float on your platform.
|
||||
// Please correct the declaration of BinFloat a few lines above - but do it in a portable,
|
||||
// #ifdef'd manner!
|
||||
static_assert( sizeof(BinFloat) >= sizeof(ai_real), "sizeof(BinFloat) >= sizeof(ai_real)");
|
||||
|
||||
#if defined( _MSC_VER)
|
||||
// If this assertion fails, Visual C++ has finally moved to ILP64. This means that this
|
||||
// code has just become legacy code! Find out the current value of _MSC_VER and modify
|
||||
// the #if above so it evaluates false on the current and all upcoming VC versions (or
|
||||
// on the current platform, if LP64 or LLP64 are still used on other platforms).
|
||||
static_assert( sizeof(BinFloat) == sizeof(ai_real), "sizeof(BinFloat) == sizeof(ai_real)");
|
||||
|
||||
// This works best on Visual C++, but other compilers have their problems with it.
|
||||
const BinFloat binValue = reinterpret_cast<BinFloat const &>(pValue);
|
||||
#else
|
||||
// On many compilers, reinterpreting a float address as an integer causes aliasing
|
||||
// problems. This is an ugly but more or less safe way of doing it.
|
||||
union {
|
||||
ai_real asFloat;
|
||||
BinFloat asBin;
|
||||
} conversion;
|
||||
conversion.asBin = 0; // zero empty space in case sizeof(BinFloat) > sizeof(float)
|
||||
conversion.asFloat = pValue;
|
||||
const BinFloat binValue = conversion.asBin;
|
||||
#endif
|
||||
|
||||
// floating-point numbers are of sign-magnitude format, so find out what signed number
|
||||
// representation we must convert negative values to.
|
||||
// See http://en.wikipedia.org/wiki/Signed_number_representations.
|
||||
|
||||
// Two's complement?
|
||||
if( (-42 == (~42 + 1)) && (binValue & 0x80000000))
|
||||
return BinFloat(1 << (CHAR_BIT * sizeof(BinFloat) - 1)) - binValue;
|
||||
// One's complement?
|
||||
else if ( (-42 == ~42) && (binValue & 0x80000000))
|
||||
return BinFloat(-0) - binValue;
|
||||
// Sign-magnitude?
|
||||
else if( (-42 == (42 | (-0))) && (binValue & 0x80000000)) // -0 = 1000... binary
|
||||
return binValue;
|
||||
else
|
||||
return binValue;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Fills an array with indices of all positions identical to the given position. In opposite to
|
||||
// FindPositions(), not an epsilon is used but a (very low) tolerance of four floating-point units.
|
||||
void SpatialSort::FindIdenticalPositions( const aiVector3D& pPosition,
|
||||
std::vector<unsigned int>& poResults) const
|
||||
{
|
||||
// Epsilons have a huge disadvantage: they are of constant precision, while floating-point
|
||||
// values are of log2 precision. If you apply e=0.01 to 100, the epsilon is rather small, but
|
||||
// if you apply it to 0.001, it is enormous.
|
||||
|
||||
// The best way to overcome this is the unit in the last place (ULP). A precision of 2 ULPs
|
||||
// tells us that a float does not differ more than 2 bits from the "real" value. ULPs are of
|
||||
// logarithmic precision - around 1, they are 1*(2^24) and around 10000, they are 0.00125.
|
||||
|
||||
// For standard C math, we can assume a precision of 0.5 ULPs according to IEEE 754. The
|
||||
// incoming vertex positions might have already been transformed, probably using rather
|
||||
// inaccurate SSE instructions, so we assume a tolerance of 4 ULPs to safely identify
|
||||
// identical vertex positions.
|
||||
static const int toleranceInULPs = 4;
|
||||
// An interesting point is that the inaccuracy grows linear with the number of operations:
|
||||
// multiplying to numbers, each inaccurate to four ULPs, results in an inaccuracy of four ULPs
|
||||
// plus 0.5 ULPs for the multiplication.
|
||||
// To compute the distance to the plane, a dot product is needed - that is a multiplication and
|
||||
// an addition on each number.
|
||||
static const int distanceToleranceInULPs = toleranceInULPs + 1;
|
||||
// The squared distance between two 3D vectors is computed the same way, but with an additional
|
||||
// subtraction.
|
||||
static const int distance3DToleranceInULPs = distanceToleranceInULPs + 1;
|
||||
|
||||
// Convert the plane distance to its signed integer representation so the ULPs tolerance can be
|
||||
// applied. For some reason, VC won't optimize two calls of the bit pattern conversion.
|
||||
const BinFloat minDistBinary = ToBinary( pPosition * mPlaneNormal) - distanceToleranceInULPs;
|
||||
const BinFloat maxDistBinary = minDistBinary + 2 * distanceToleranceInULPs;
|
||||
|
||||
// clear the array in this strange fashion because a simple clear() would also deallocate
|
||||
// the array which we want to avoid
|
||||
poResults.resize( 0 );
|
||||
|
||||
// do a binary search for the minimal distance to start the iteration there
|
||||
unsigned int index = (unsigned int)mPositions.size() / 2;
|
||||
unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4;
|
||||
while( binaryStepSize > 1)
|
||||
{
|
||||
// Ugly, but conditional jumps are faster with integers than with floats
|
||||
if( minDistBinary > ToBinary(mPositions[index].mDistance))
|
||||
index += binaryStepSize;
|
||||
else
|
||||
index -= binaryStepSize;
|
||||
|
||||
binaryStepSize /= 2;
|
||||
}
|
||||
|
||||
// depending on the direction of the last step we need to single step a bit back or forth
|
||||
// to find the actual beginning element of the range
|
||||
while( index > 0 && minDistBinary < ToBinary(mPositions[index].mDistance) )
|
||||
index--;
|
||||
while( index < (mPositions.size() - 1) && minDistBinary > ToBinary(mPositions[index].mDistance))
|
||||
index++;
|
||||
|
||||
// Now start iterating from there until the first position lays outside of the distance range.
|
||||
// Add all positions inside the distance range within the tolerance to the result array
|
||||
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
|
||||
while( ToBinary(it->mDistance) < maxDistBinary)
|
||||
{
|
||||
if( distance3DToleranceInULPs >= ToBinary((it->mPosition - pPosition).SquareLength()))
|
||||
poResults.push_back(it->mIndex);
|
||||
++it;
|
||||
if( it == mPositions.end())
|
||||
break;
|
||||
}
|
||||
|
||||
// that's it
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int SpatialSort::GenerateMappingTable(std::vector<unsigned int>& fill, ai_real pRadius) const
|
||||
{
|
||||
fill.resize(mPositions.size(),UINT_MAX);
|
||||
ai_real dist, maxDist;
|
||||
|
||||
unsigned int t=0;
|
||||
const ai_real pSquared = pRadius*pRadius;
|
||||
for (size_t i = 0; i < mPositions.size();) {
|
||||
dist = mPositions[i].mPosition * mPlaneNormal;
|
||||
maxDist = dist + pRadius;
|
||||
|
||||
fill[mPositions[i].mIndex] = t;
|
||||
const aiVector3D& oldpos = mPositions[i].mPosition;
|
||||
for (++i; i < fill.size() && mPositions[i].mDistance < maxDist
|
||||
&& (mPositions[i].mPosition - oldpos).SquareLength() < pSquared; ++i)
|
||||
{
|
||||
fill[mPositions[i].mIndex] = t;
|
||||
}
|
||||
++t;
|
||||
}
|
||||
|
||||
#ifdef ASSIMP_BUILD_DEBUG
|
||||
|
||||
// debug invariant: mPositions[i].mIndex values must range from 0 to mPositions.size()-1
|
||||
for (size_t i = 0; i < fill.size(); ++i) {
|
||||
ai_assert(fill[i]<mPositions.size());
|
||||
}
|
||||
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
407
thirdparty/assimp/code/Common/SplitByBoneCountProcess.cpp
vendored
Normal file
407
thirdparty/assimp/code/Common/SplitByBoneCountProcess.cpp
vendored
Normal file
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
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 SplitByBoneCountProcess.cpp
|
||||
/// Implementation of the SplitByBoneCount postprocessing step
|
||||
|
||||
// internal headers of the post-processing framework
|
||||
#include "SplitByBoneCountProcess.h"
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <assimp/TinyFormatter.h>
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Formatter;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor
|
||||
SplitByBoneCountProcess::SplitByBoneCountProcess()
|
||||
{
|
||||
// set default, might be overridden by importer config
|
||||
mMaxBoneCount = AI_SBBC_DEFAULT_MAX_BONES;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
SplitByBoneCountProcess::~SplitByBoneCountProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag.
|
||||
bool SplitByBoneCountProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return !!(pFlags & aiProcess_SplitByBoneCount);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Updates internal properties
|
||||
void SplitByBoneCountProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
mMaxBoneCount = pImp->GetPropertyInteger(AI_CONFIG_PP_SBBC_MAX_BONES,AI_SBBC_DEFAULT_MAX_BONES);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void SplitByBoneCountProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("SplitByBoneCountProcess begin");
|
||||
|
||||
// early out
|
||||
bool isNecessary = false;
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
|
||||
if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount )
|
||||
isNecessary = true;
|
||||
|
||||
if( !isNecessary )
|
||||
{
|
||||
ASSIMP_LOG_DEBUG( format() << "SplitByBoneCountProcess early-out: no meshes with more than " << mMaxBoneCount << " bones." );
|
||||
return;
|
||||
}
|
||||
|
||||
// we need to do something. Let's go.
|
||||
mSubMeshIndices.clear();
|
||||
mSubMeshIndices.resize( pScene->mNumMeshes);
|
||||
|
||||
// build a new array of meshes for the scene
|
||||
std::vector<aiMesh*> meshes;
|
||||
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
|
||||
{
|
||||
aiMesh* srcMesh = pScene->mMeshes[a];
|
||||
|
||||
std::vector<aiMesh*> newMeshes;
|
||||
SplitMesh( pScene->mMeshes[a], newMeshes);
|
||||
|
||||
// mesh was split
|
||||
if( !newMeshes.empty() )
|
||||
{
|
||||
// store new meshes and indices of the new meshes
|
||||
for( unsigned int b = 0; b < newMeshes.size(); ++b)
|
||||
{
|
||||
mSubMeshIndices[a].push_back( static_cast<unsigned int>(meshes.size()));
|
||||
meshes.push_back( newMeshes[b]);
|
||||
}
|
||||
|
||||
// and destroy the source mesh. It should be completely contained inside the new submeshes
|
||||
delete srcMesh;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mesh is kept unchanged - store it's new place in the mesh array
|
||||
mSubMeshIndices[a].push_back( static_cast<unsigned int>(meshes.size()));
|
||||
meshes.push_back( srcMesh);
|
||||
}
|
||||
}
|
||||
|
||||
// rebuild the scene's mesh array
|
||||
pScene->mNumMeshes = static_cast<unsigned int>(meshes.size());
|
||||
delete [] pScene->mMeshes;
|
||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
||||
std::copy( meshes.begin(), meshes.end(), pScene->mMeshes);
|
||||
|
||||
// recurse through all nodes and translate the node's mesh indices to fit the new mesh array
|
||||
UpdateNode( pScene->mRootNode);
|
||||
|
||||
ASSIMP_LOG_DEBUG( format() << "SplitByBoneCountProcess end: split " << mSubMeshIndices.size() << " meshes into " << meshes.size() << " submeshes." );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Splits the given mesh by bone count.
|
||||
void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh*>& poNewMeshes) const
|
||||
{
|
||||
// skip if not necessary
|
||||
if( pMesh->mNumBones <= mMaxBoneCount )
|
||||
return;
|
||||
|
||||
// necessary optimisation: build a list of all affecting bones for each vertex
|
||||
// TODO: (thom) maybe add a custom allocator here to avoid allocating tens of thousands of small arrays
|
||||
typedef std::pair<unsigned int, float> BoneWeight;
|
||||
std::vector< std::vector<BoneWeight> > vertexBones( pMesh->mNumVertices);
|
||||
for( unsigned int a = 0; a < pMesh->mNumBones; ++a)
|
||||
{
|
||||
const aiBone* bone = pMesh->mBones[a];
|
||||
for( unsigned int b = 0; b < bone->mNumWeights; ++b)
|
||||
vertexBones[ bone->mWeights[b].mVertexId ].push_back( BoneWeight( a, bone->mWeights[b].mWeight));
|
||||
}
|
||||
|
||||
unsigned int numFacesHandled = 0;
|
||||
std::vector<bool> isFaceHandled( pMesh->mNumFaces, false);
|
||||
while( numFacesHandled < pMesh->mNumFaces )
|
||||
{
|
||||
// which bones are used in the current submesh
|
||||
unsigned int numBones = 0;
|
||||
std::vector<bool> isBoneUsed( pMesh->mNumBones, false);
|
||||
// indices of the faces which are going to go into this submesh
|
||||
std::vector<unsigned int> subMeshFaces;
|
||||
subMeshFaces.reserve( pMesh->mNumFaces);
|
||||
// accumulated vertex count of all the faces in this submesh
|
||||
unsigned int numSubMeshVertices = 0;
|
||||
// a small local array of new bones for the current face. State of all used bones for that face
|
||||
// can only be updated AFTER the face is completely analysed. Thanks to imre for the fix.
|
||||
std::vector<unsigned int> newBonesAtCurrentFace;
|
||||
|
||||
// add faces to the new submesh as long as all bones affecting the faces' vertices fit in the limit
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; ++a)
|
||||
{
|
||||
// skip if the face is already stored in a submesh
|
||||
if( isFaceHandled[a] )
|
||||
continue;
|
||||
|
||||
const aiFace& face = pMesh->mFaces[a];
|
||||
// check every vertex if its bones would still fit into the current submesh
|
||||
for( unsigned int b = 0; b < face.mNumIndices; ++b )
|
||||
{
|
||||
const std::vector<BoneWeight>& vb = vertexBones[face.mIndices[b]];
|
||||
for( unsigned int c = 0; c < vb.size(); ++c)
|
||||
{
|
||||
unsigned int boneIndex = vb[c].first;
|
||||
// if the bone is already used in this submesh, it's ok
|
||||
if( isBoneUsed[boneIndex] )
|
||||
continue;
|
||||
|
||||
// if it's not used, yet, we would need to add it. Store its bone index
|
||||
if( std::find( newBonesAtCurrentFace.begin(), newBonesAtCurrentFace.end(), boneIndex) == newBonesAtCurrentFace.end() )
|
||||
newBonesAtCurrentFace.push_back( boneIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// leave out the face if the new bones required for this face don't fit the bone count limit anymore
|
||||
if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount )
|
||||
continue;
|
||||
|
||||
// mark all new bones as necessary
|
||||
while( !newBonesAtCurrentFace.empty() )
|
||||
{
|
||||
unsigned int newIndex = newBonesAtCurrentFace.back();
|
||||
newBonesAtCurrentFace.pop_back(); // this also avoids the deallocation which comes with a clear()
|
||||
if( isBoneUsed[newIndex] )
|
||||
continue;
|
||||
|
||||
isBoneUsed[newIndex] = true;
|
||||
numBones++;
|
||||
}
|
||||
|
||||
// store the face index and the vertex count
|
||||
subMeshFaces.push_back( a);
|
||||
numSubMeshVertices += face.mNumIndices;
|
||||
|
||||
// remember that this face is handled
|
||||
isFaceHandled[a] = true;
|
||||
numFacesHandled++;
|
||||
}
|
||||
|
||||
// create a new mesh to hold this subset of the source mesh
|
||||
aiMesh* newMesh = new aiMesh;
|
||||
if( pMesh->mName.length > 0 )
|
||||
newMesh->mName.Set( format() << pMesh->mName.data << "_sub" << poNewMeshes.size());
|
||||
newMesh->mMaterialIndex = pMesh->mMaterialIndex;
|
||||
newMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes;
|
||||
poNewMeshes.push_back( newMesh);
|
||||
|
||||
// create all the arrays for this mesh if the old mesh contained them
|
||||
newMesh->mNumVertices = numSubMeshVertices;
|
||||
newMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size());
|
||||
newMesh->mVertices = new aiVector3D[newMesh->mNumVertices];
|
||||
if( pMesh->HasNormals() )
|
||||
newMesh->mNormals = new aiVector3D[newMesh->mNumVertices];
|
||||
if( pMesh->HasTangentsAndBitangents() )
|
||||
{
|
||||
newMesh->mTangents = new aiVector3D[newMesh->mNumVertices];
|
||||
newMesh->mBitangents = new aiVector3D[newMesh->mNumVertices];
|
||||
}
|
||||
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
|
||||
{
|
||||
if( pMesh->HasTextureCoords( a) )
|
||||
newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices];
|
||||
newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a];
|
||||
}
|
||||
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
|
||||
{
|
||||
if( pMesh->HasVertexColors( a) )
|
||||
newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices];
|
||||
}
|
||||
|
||||
// and copy over the data, generating faces with linear indices along the way
|
||||
newMesh->mFaces = new aiFace[subMeshFaces.size()];
|
||||
unsigned int nvi = 0; // next vertex index
|
||||
std::vector<unsigned int> previousVertexIndices( numSubMeshVertices, std::numeric_limits<unsigned int>::max()); // per new vertex: its index in the source mesh
|
||||
for( unsigned int a = 0; a < subMeshFaces.size(); ++a )
|
||||
{
|
||||
const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]];
|
||||
aiFace& dstFace = newMesh->mFaces[a];
|
||||
dstFace.mNumIndices = srcFace.mNumIndices;
|
||||
dstFace.mIndices = new unsigned int[dstFace.mNumIndices];
|
||||
|
||||
// accumulate linearly all the vertices of the source face
|
||||
for( unsigned int b = 0; b < dstFace.mNumIndices; ++b )
|
||||
{
|
||||
unsigned int srcIndex = srcFace.mIndices[b];
|
||||
dstFace.mIndices[b] = nvi;
|
||||
previousVertexIndices[nvi] = srcIndex;
|
||||
|
||||
newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex];
|
||||
if( pMesh->HasNormals() )
|
||||
newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex];
|
||||
if( pMesh->HasTangentsAndBitangents() )
|
||||
{
|
||||
newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex];
|
||||
newMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex];
|
||||
}
|
||||
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c )
|
||||
{
|
||||
if( pMesh->HasTextureCoords( c) )
|
||||
newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex];
|
||||
}
|
||||
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c )
|
||||
{
|
||||
if( pMesh->HasVertexColors( c) )
|
||||
newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex];
|
||||
}
|
||||
|
||||
nvi++;
|
||||
}
|
||||
}
|
||||
|
||||
ai_assert( nvi == numSubMeshVertices );
|
||||
|
||||
// Create the bones for the new submesh: first create the bone array
|
||||
newMesh->mNumBones = 0;
|
||||
newMesh->mBones = new aiBone*[numBones];
|
||||
|
||||
std::vector<unsigned int> mappedBoneIndex( pMesh->mNumBones, std::numeric_limits<unsigned int>::max());
|
||||
for( unsigned int a = 0; a < pMesh->mNumBones; ++a )
|
||||
{
|
||||
if( !isBoneUsed[a] )
|
||||
continue;
|
||||
|
||||
// create the new bone
|
||||
const aiBone* srcBone = pMesh->mBones[a];
|
||||
aiBone* dstBone = new aiBone;
|
||||
mappedBoneIndex[a] = newMesh->mNumBones;
|
||||
newMesh->mBones[newMesh->mNumBones++] = dstBone;
|
||||
dstBone->mName = srcBone->mName;
|
||||
dstBone->mOffsetMatrix = srcBone->mOffsetMatrix;
|
||||
dstBone->mNumWeights = 0;
|
||||
}
|
||||
|
||||
ai_assert( newMesh->mNumBones == numBones );
|
||||
|
||||
// iterate over all new vertices and count which bones affected its old vertex in the source mesh
|
||||
for( unsigned int a = 0; a < numSubMeshVertices; ++a )
|
||||
{
|
||||
unsigned int oldIndex = previousVertexIndices[a];
|
||||
const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[oldIndex];
|
||||
|
||||
for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b )
|
||||
{
|
||||
unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
|
||||
if( newBoneIndex != std::numeric_limits<unsigned int>::max() )
|
||||
newMesh->mBones[newBoneIndex]->mNumWeights++;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate all bone weight arrays accordingly
|
||||
for( unsigned int a = 0; a < newMesh->mNumBones; ++a )
|
||||
{
|
||||
aiBone* bone = newMesh->mBones[a];
|
||||
ai_assert( bone->mNumWeights > 0 );
|
||||
bone->mWeights = new aiVertexWeight[bone->mNumWeights];
|
||||
bone->mNumWeights = 0; // for counting up in the next step
|
||||
}
|
||||
|
||||
// now copy all the bone vertex weights for all the vertices which made it into the new submesh
|
||||
for( unsigned int a = 0; a < numSubMeshVertices; ++a)
|
||||
{
|
||||
// find the source vertex for it in the source mesh
|
||||
unsigned int previousIndex = previousVertexIndices[a];
|
||||
// these bones were affecting it
|
||||
const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[previousIndex];
|
||||
// all of the bones affecting it should be present in the new submesh, or else
|
||||
// the face it comprises shouldn't be present
|
||||
for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b)
|
||||
{
|
||||
unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
|
||||
ai_assert( newBoneIndex != std::numeric_limits<unsigned int>::max() );
|
||||
aiVertexWeight* dstWeight = newMesh->mBones[newBoneIndex]->mWeights + newMesh->mBones[newBoneIndex]->mNumWeights;
|
||||
newMesh->mBones[newBoneIndex]->mNumWeights++;
|
||||
|
||||
dstWeight->mVertexId = a;
|
||||
dstWeight->mWeight = bonesOnThisVertex[b].second;
|
||||
}
|
||||
}
|
||||
|
||||
// I have the strange feeling that this will break apart at some point in time...
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively updates the node's mesh list to account for the changed mesh list
|
||||
void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const
|
||||
{
|
||||
// rebuild the node's mesh index list
|
||||
if( pNode->mNumMeshes > 0 )
|
||||
{
|
||||
std::vector<unsigned int> newMeshList;
|
||||
for( unsigned int a = 0; a < pNode->mNumMeshes; ++a)
|
||||
{
|
||||
unsigned int srcIndex = pNode->mMeshes[a];
|
||||
const std::vector<unsigned int>& replaceMeshes = mSubMeshIndices[srcIndex];
|
||||
newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end());
|
||||
}
|
||||
|
||||
delete [] pNode->mMeshes;
|
||||
pNode->mNumMeshes = static_cast<unsigned int>(newMeshList.size());
|
||||
pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
|
||||
std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes);
|
||||
}
|
||||
|
||||
// do that also recursively for all children
|
||||
for( unsigned int a = 0; a < pNode->mNumChildren; ++a )
|
||||
{
|
||||
UpdateNode( pNode->mChildren[a]);
|
||||
}
|
||||
}
|
||||
111
thirdparty/assimp/code/Common/SplitByBoneCountProcess.h
vendored
Normal file
111
thirdparty/assimp/code/Common/SplitByBoneCountProcess.h
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
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 SplitByBoneCountProcess.h
|
||||
/// Defines a post processing step to split meshes with many bones into submeshes
|
||||
#ifndef AI_SPLITBYBONECOUNTPROCESS_H_INC
|
||||
#define AI_SPLITBYBONECOUNTPROCESS_H_INC
|
||||
|
||||
#include <vector>
|
||||
#include "BaseProcess.h"
|
||||
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/scene.h>
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
|
||||
/** Postprocessing filter to split meshes with many bones into submeshes
|
||||
* so that each submesh has a certain max bone count.
|
||||
*
|
||||
* Applied BEFORE the JoinVertices-Step occurs.
|
||||
* Returns NON-UNIQUE vertices, splits by bone count.
|
||||
*/
|
||||
class SplitByBoneCountProcess : public BaseProcess
|
||||
{
|
||||
public:
|
||||
|
||||
SplitByBoneCountProcess();
|
||||
~SplitByBoneCountProcess();
|
||||
|
||||
public:
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
* @param pFlags The processing flags the importer was called with. A
|
||||
* bitwise combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields,
|
||||
* false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
virtual void SetupProperties(const Importer* pImp);
|
||||
|
||||
protected:
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
/// Splits the given mesh by bone count.
|
||||
/// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split.
|
||||
/// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary.
|
||||
void SplitMesh( const aiMesh* pMesh, std::vector<aiMesh*>& poNewMeshes) const;
|
||||
|
||||
/// Recursively updates the node's mesh list to account for the changed mesh list
|
||||
void UpdateNode( aiNode* pNode) const;
|
||||
|
||||
public:
|
||||
/// Max bone count. Splitting occurs if a mesh has more than that number of bones.
|
||||
size_t mMaxBoneCount;
|
||||
|
||||
/// Per mesh index: Array of indices of the new submeshes.
|
||||
std::vector< std::vector<unsigned int> > mSubMeshIndices;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // !!AI_SPLITBYBONECOUNTPROCESS_H_INC
|
||||
507
thirdparty/assimp/code/Common/StandardShapes.cpp
vendored
Normal file
507
thirdparty/assimp/code/Common/StandardShapes.cpp
vendored
Normal file
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
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 StandardShapes.cpp
|
||||
* @brief Implementation of the StandardShapes class
|
||||
*
|
||||
* The primitive geometry data comes from
|
||||
* http://geometrictools.com/Documentation/PlatonicSolids.pdf.
|
||||
*/
|
||||
|
||||
#include <assimp/StandardShapes.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <stddef.h>
|
||||
#include <assimp/Defines.h>
|
||||
#include <assimp/mesh.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
|
||||
# define ADD_TRIANGLE(n0,n1,n2) \
|
||||
positions.push_back(n0); \
|
||||
positions.push_back(n1); \
|
||||
positions.push_back(n2);
|
||||
|
||||
# define ADD_PENTAGON(n0,n1,n2,n3,n4) \
|
||||
if (polygons) \
|
||||
{ \
|
||||
positions.push_back(n0); \
|
||||
positions.push_back(n1); \
|
||||
positions.push_back(n2); \
|
||||
positions.push_back(n3); \
|
||||
positions.push_back(n4); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
ADD_TRIANGLE(n0, n1, n2) \
|
||||
ADD_TRIANGLE(n0, n2, n3) \
|
||||
ADD_TRIANGLE(n0, n3, n4) \
|
||||
}
|
||||
|
||||
# define ADD_QUAD(n0,n1,n2,n3) \
|
||||
if (polygons) \
|
||||
{ \
|
||||
positions.push_back(n0); \
|
||||
positions.push_back(n1); \
|
||||
positions.push_back(n2); \
|
||||
positions.push_back(n3); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
ADD_TRIANGLE(n0, n1, n2) \
|
||||
ADD_TRIANGLE(n0, n2, n3) \
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Fast subdivision for a mesh whose verts have a magnitude of 1
|
||||
void Subdivide(std::vector<aiVector3D>& positions)
|
||||
{
|
||||
// assume this to be constant - (fixme: must be 1.0? I think so)
|
||||
const ai_real fl1 = positions[0].Length();
|
||||
|
||||
unsigned int origSize = (unsigned int)positions.size();
|
||||
for (unsigned int i = 0 ; i < origSize ; i+=3)
|
||||
{
|
||||
aiVector3D& tv0 = positions[i];
|
||||
aiVector3D& tv1 = positions[i+1];
|
||||
aiVector3D& tv2 = positions[i+2];
|
||||
|
||||
aiVector3D a = tv0, b = tv1, c = tv2;
|
||||
aiVector3D v1 = aiVector3D(a.x+b.x, a.y+b.y, a.z+b.z).Normalize()*fl1;
|
||||
aiVector3D v2 = aiVector3D(a.x+c.x, a.y+c.y, a.z+c.z).Normalize()*fl1;
|
||||
aiVector3D v3 = aiVector3D(b.x+c.x, b.y+c.y, b.z+c.z).Normalize()*fl1;
|
||||
|
||||
tv0 = v1; tv1 = v3; tv2 = v2; // overwrite the original
|
||||
ADD_TRIANGLE(v1, v2, a);
|
||||
ADD_TRIANGLE(v2, v3, c);
|
||||
ADD_TRIANGLE(v3, v1, b);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Construct a mesh from given vertex positions
|
||||
aiMesh* StandardShapes::MakeMesh(const std::vector<aiVector3D>& positions,
|
||||
unsigned int numIndices)
|
||||
{
|
||||
if (positions.empty() || !numIndices) return NULL;
|
||||
|
||||
// Determine which kinds of primitives the mesh consists of
|
||||
aiMesh* out = new aiMesh();
|
||||
switch (numIndices) {
|
||||
case 1:
|
||||
out->mPrimitiveTypes = aiPrimitiveType_POINT;
|
||||
break;
|
||||
case 2:
|
||||
out->mPrimitiveTypes = aiPrimitiveType_LINE;
|
||||
break;
|
||||
case 3:
|
||||
out->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
||||
break;
|
||||
default:
|
||||
out->mPrimitiveTypes = aiPrimitiveType_POLYGON;
|
||||
break;
|
||||
};
|
||||
|
||||
out->mNumFaces = (unsigned int)positions.size() / numIndices;
|
||||
out->mFaces = new aiFace[out->mNumFaces];
|
||||
for (unsigned int i = 0, a = 0; i < out->mNumFaces;++i) {
|
||||
aiFace& f = out->mFaces[i];
|
||||
f.mNumIndices = numIndices;
|
||||
f.mIndices = new unsigned int[numIndices];
|
||||
for (unsigned int j = 0; i < numIndices; ++i, ++a) {
|
||||
f.mIndices[j] = a;
|
||||
}
|
||||
}
|
||||
out->mNumVertices = (unsigned int)positions.size();
|
||||
out->mVertices = new aiVector3D[out->mNumVertices];
|
||||
::memcpy(out->mVertices,&positions[0],out->mNumVertices*sizeof(aiVector3D));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Construct a mesh with a specific shape (callback)
|
||||
aiMesh* StandardShapes::MakeMesh ( unsigned int (*GenerateFunc)(
|
||||
std::vector<aiVector3D>&))
|
||||
{
|
||||
std::vector<aiVector3D> temp;
|
||||
unsigned num = (*GenerateFunc)(temp);
|
||||
return MakeMesh(temp,num);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Construct a mesh with a specific shape (callback)
|
||||
aiMesh* StandardShapes::MakeMesh ( unsigned int (*GenerateFunc)(
|
||||
std::vector<aiVector3D>&, bool))
|
||||
{
|
||||
std::vector<aiVector3D> temp;
|
||||
unsigned num = (*GenerateFunc)(temp,true);
|
||||
return MakeMesh(temp,num);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Construct a mesh with a specific shape (callback)
|
||||
aiMesh* StandardShapes::MakeMesh (unsigned int num, void (*GenerateFunc)(
|
||||
unsigned int,std::vector<aiVector3D>&))
|
||||
{
|
||||
std::vector<aiVector3D> temp;
|
||||
(*GenerateFunc)(num,temp);
|
||||
return MakeMesh(temp,3);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build an incosahedron with points.magnitude == 1
|
||||
unsigned int StandardShapes::MakeIcosahedron(std::vector<aiVector3D>& positions)
|
||||
{
|
||||
positions.reserve(positions.size()+60);
|
||||
|
||||
const ai_real t = ( ai_real( 1.0 )+ ai_real( 2.236067977 ) ) / ai_real( 2.0 );
|
||||
const ai_real s = std::sqrt(ai_real(1.0) + t*t);
|
||||
|
||||
const aiVector3D v0 = aiVector3D(t,1.0, 0.0)/s;
|
||||
const aiVector3D v1 = aiVector3D(-t,1.0, 0.0)/s;
|
||||
const aiVector3D v2 = aiVector3D(t,-1.0, 0.0)/s;
|
||||
const aiVector3D v3 = aiVector3D(-t,-1.0, 0.0)/s;
|
||||
const aiVector3D v4 = aiVector3D(1.0, 0.0, t)/s;
|
||||
const aiVector3D v5 = aiVector3D(1.0, 0.0,-t)/s;
|
||||
const aiVector3D v6 = aiVector3D(-1.0, 0.0,t)/s;
|
||||
const aiVector3D v7 = aiVector3D(-1.0, 0.0,-t)/s;
|
||||
const aiVector3D v8 = aiVector3D(0.0, t, 1.0)/s;
|
||||
const aiVector3D v9 = aiVector3D(0.0,-t, 1.0)/s;
|
||||
const aiVector3D v10 = aiVector3D(0.0, t,-1.0)/s;
|
||||
const aiVector3D v11 = aiVector3D(0.0,-t,-1.0)/s;
|
||||
|
||||
ADD_TRIANGLE(v0,v8,v4);
|
||||
ADD_TRIANGLE(v0,v5,v10);
|
||||
ADD_TRIANGLE(v2,v4,v9);
|
||||
ADD_TRIANGLE(v2,v11,v5);
|
||||
|
||||
ADD_TRIANGLE(v1,v6,v8);
|
||||
ADD_TRIANGLE(v1,v10,v7);
|
||||
ADD_TRIANGLE(v3,v9,v6);
|
||||
ADD_TRIANGLE(v3,v7,v11);
|
||||
|
||||
ADD_TRIANGLE(v0,v10,v8);
|
||||
ADD_TRIANGLE(v1,v8,v10);
|
||||
ADD_TRIANGLE(v2,v9,v11);
|
||||
ADD_TRIANGLE(v3,v11,v9);
|
||||
|
||||
ADD_TRIANGLE(v4,v2,v0);
|
||||
ADD_TRIANGLE(v5,v0,v2);
|
||||
ADD_TRIANGLE(v6,v1,v3);
|
||||
ADD_TRIANGLE(v7,v3,v1);
|
||||
|
||||
ADD_TRIANGLE(v8,v6,v4);
|
||||
ADD_TRIANGLE(v9,v4,v6);
|
||||
ADD_TRIANGLE(v10,v5,v7);
|
||||
ADD_TRIANGLE(v11,v7,v5);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build a dodecahedron with points.magnitude == 1
|
||||
unsigned int StandardShapes::MakeDodecahedron(std::vector<aiVector3D>& positions,
|
||||
bool polygons /*= false*/)
|
||||
{
|
||||
positions.reserve(positions.size()+108);
|
||||
|
||||
const ai_real a = ai_real( 1.0 ) / ai_real(1.7320508);
|
||||
const ai_real b = std::sqrt(( ai_real( 3.0 )- ai_real( 2.23606797))/ ai_real( 6.0) );
|
||||
const ai_real c = std::sqrt(( ai_real( 3.0 )+ ai_real( 2.23606797f))/ ai_real( 6.0) );
|
||||
|
||||
const aiVector3D v0 = aiVector3D(a,a,a);
|
||||
const aiVector3D v1 = aiVector3D(a,a,-a);
|
||||
const aiVector3D v2 = aiVector3D(a,-a,a);
|
||||
const aiVector3D v3 = aiVector3D(a,-a,-a);
|
||||
const aiVector3D v4 = aiVector3D(-a,a,a);
|
||||
const aiVector3D v5 = aiVector3D(-a,a,-a);
|
||||
const aiVector3D v6 = aiVector3D(-a,-a,a);
|
||||
const aiVector3D v7 = aiVector3D(-a,-a,-a);
|
||||
const aiVector3D v8 = aiVector3D(b,c,0.0);
|
||||
const aiVector3D v9 = aiVector3D(-b,c,0.0);
|
||||
const aiVector3D v10 = aiVector3D(b,-c,0.0);
|
||||
const aiVector3D v11 = aiVector3D(-b,-c,0.0);
|
||||
const aiVector3D v12 = aiVector3D(c, 0.0, b);
|
||||
const aiVector3D v13 = aiVector3D(c, 0.0, -b);
|
||||
const aiVector3D v14 = aiVector3D(-c, 0.0, b);
|
||||
const aiVector3D v15 = aiVector3D(-c, 0.0, -b);
|
||||
const aiVector3D v16 = aiVector3D(0.0, b, c);
|
||||
const aiVector3D v17 = aiVector3D(0.0, -b, c);
|
||||
const aiVector3D v18 = aiVector3D(0.0, b, -c);
|
||||
const aiVector3D v19 = aiVector3D(0.0, -b, -c);
|
||||
|
||||
ADD_PENTAGON(v0, v8, v9, v4, v16);
|
||||
ADD_PENTAGON(v0, v12, v13, v1, v8);
|
||||
ADD_PENTAGON(v0, v16, v17, v2, v12);
|
||||
ADD_PENTAGON(v8, v1, v18, v5, v9);
|
||||
ADD_PENTAGON(v12, v2, v10, v3, v13);
|
||||
ADD_PENTAGON(v16, v4, v14, v6, v17);
|
||||
ADD_PENTAGON(v9, v5, v15, v14, v4);
|
||||
|
||||
ADD_PENTAGON(v6, v11, v10, v2, v17);
|
||||
ADD_PENTAGON(v3, v19, v18, v1, v13);
|
||||
ADD_PENTAGON(v7, v15, v5, v18, v19);
|
||||
ADD_PENTAGON(v7, v11, v6, v14, v15);
|
||||
ADD_PENTAGON(v7, v19, v3, v10, v11);
|
||||
return (polygons ? 5 : 3);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build an octahedron with points.magnitude == 1
|
||||
unsigned int StandardShapes::MakeOctahedron(std::vector<aiVector3D>& positions)
|
||||
{
|
||||
positions.reserve(positions.size()+24);
|
||||
|
||||
const aiVector3D v0 = aiVector3D(1.0, 0.0, 0.0) ;
|
||||
const aiVector3D v1 = aiVector3D(-1.0, 0.0, 0.0);
|
||||
const aiVector3D v2 = aiVector3D(0.0, 1.0, 0.0);
|
||||
const aiVector3D v3 = aiVector3D(0.0, -1.0, 0.0);
|
||||
const aiVector3D v4 = aiVector3D(0.0, 0.0, 1.0);
|
||||
const aiVector3D v5 = aiVector3D(0.0, 0.0, -1.0);
|
||||
|
||||
ADD_TRIANGLE(v4,v0,v2);
|
||||
ADD_TRIANGLE(v4,v2,v1);
|
||||
ADD_TRIANGLE(v4,v1,v3);
|
||||
ADD_TRIANGLE(v4,v3,v0);
|
||||
|
||||
ADD_TRIANGLE(v5,v2,v0);
|
||||
ADD_TRIANGLE(v5,v1,v2);
|
||||
ADD_TRIANGLE(v5,v3,v1);
|
||||
ADD_TRIANGLE(v5,v0,v3);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build a tetrahedron with points.magnitude == 1
|
||||
unsigned int StandardShapes::MakeTetrahedron(std::vector<aiVector3D>& positions)
|
||||
{
|
||||
positions.reserve(positions.size()+9);
|
||||
|
||||
const ai_real invThree = ai_real( 1.0 ) / ai_real( 3.0 );
|
||||
const ai_real a = ai_real( 1.41421 ) * invThree;
|
||||
const ai_real b = ai_real( 2.4494 ) * invThree;
|
||||
|
||||
const aiVector3D v0 = aiVector3D(0.0,0.0,1.0);
|
||||
const aiVector3D v1 = aiVector3D(2*a,0,-invThree );
|
||||
const aiVector3D v2 = aiVector3D(-a,b,-invThree );
|
||||
const aiVector3D v3 = aiVector3D(-a,-b,-invThree );
|
||||
|
||||
ADD_TRIANGLE(v0,v1,v2);
|
||||
ADD_TRIANGLE(v0,v2,v3);
|
||||
ADD_TRIANGLE(v0,v3,v1);
|
||||
ADD_TRIANGLE(v1,v3,v2);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build a hexahedron with points.magnitude == 1
|
||||
unsigned int StandardShapes::MakeHexahedron(std::vector<aiVector3D>& positions,
|
||||
bool polygons /*= false*/)
|
||||
{
|
||||
positions.reserve(positions.size()+36);
|
||||
const ai_real length = ai_real(1.0)/ai_real(1.73205080);
|
||||
|
||||
const aiVector3D v0 = aiVector3D(-1.0,-1.0,-1.0)*length;
|
||||
const aiVector3D v1 = aiVector3D(1.0,-1.0,-1.0)*length;
|
||||
const aiVector3D v2 = aiVector3D(1.0,1.0,-1.0)*length;
|
||||
const aiVector3D v3 = aiVector3D(-1.0,1.0,-1.0)*length;
|
||||
const aiVector3D v4 = aiVector3D(-1.0,-1.0,1.0)*length;
|
||||
const aiVector3D v5 = aiVector3D(1.0,-1.0,1.0)*length;
|
||||
const aiVector3D v6 = aiVector3D(1.0,1.0,1.0)*length;
|
||||
const aiVector3D v7 = aiVector3D(-1.0,1.0,1.0)*length;
|
||||
|
||||
ADD_QUAD(v0,v3,v2,v1);
|
||||
ADD_QUAD(v0,v1,v5,v4);
|
||||
ADD_QUAD(v0,v4,v7,v3);
|
||||
ADD_QUAD(v6,v5,v1,v2);
|
||||
ADD_QUAD(v6,v2,v3,v7);
|
||||
ADD_QUAD(v6,v7,v4,v5);
|
||||
return (polygons ? 4 : 3);
|
||||
}
|
||||
|
||||
// Cleanup ...
|
||||
#undef ADD_TRIANGLE
|
||||
#undef ADD_QUAD
|
||||
#undef ADD_PENTAGON
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Create a subdivision sphere
|
||||
void StandardShapes::MakeSphere(unsigned int tess,
|
||||
std::vector<aiVector3D>& positions)
|
||||
{
|
||||
// Reserve enough storage. Every subdivision
|
||||
// splits each triangle in 4, the icosahedron consists of 60 verts
|
||||
positions.reserve(positions.size()+60 * integer_pow(4, tess));
|
||||
|
||||
// Construct an icosahedron to start with
|
||||
MakeIcosahedron(positions);
|
||||
|
||||
// ... and subdivide it until the requested output
|
||||
// tessellation is reached
|
||||
for (unsigned int i = 0; i<tess;++i)
|
||||
Subdivide(positions);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build a cone
|
||||
void StandardShapes::MakeCone(ai_real height,ai_real radius1,
|
||||
ai_real radius2,unsigned int tess,
|
||||
std::vector<aiVector3D>& positions,bool bOpen /*= false */)
|
||||
{
|
||||
// Sorry, a cone with less than 3 segments makes ABSOLUTELY NO SENSE
|
||||
if (tess < 3 || !height)
|
||||
return;
|
||||
|
||||
size_t old = positions.size();
|
||||
|
||||
// No negative radii
|
||||
radius1 = std::fabs(radius1);
|
||||
radius2 = std::fabs(radius2);
|
||||
|
||||
ai_real halfHeight = height / ai_real(2.0);
|
||||
|
||||
// radius1 is always the smaller one
|
||||
if (radius2 > radius1)
|
||||
{
|
||||
std::swap(radius2,radius1);
|
||||
halfHeight = -halfHeight;
|
||||
}
|
||||
else old = SIZE_MAX;
|
||||
|
||||
// Use a large epsilon to check whether the cone is pointy
|
||||
if (radius1 < (radius2-radius1)*10e-3)radius1 = 0.0;
|
||||
|
||||
// We will need 3*2 verts per segment + 3*2 verts per segment
|
||||
// if the cone is closed
|
||||
const unsigned int mem = tess*6 + (!bOpen ? tess*3 * (radius1 ? 2 : 1) : 0);
|
||||
positions.reserve(positions.size () + mem);
|
||||
|
||||
// Now construct all segments
|
||||
const ai_real angle_delta = (ai_real)AI_MATH_TWO_PI / tess;
|
||||
const ai_real angle_max = (ai_real)AI_MATH_TWO_PI;
|
||||
|
||||
ai_real s = 1.0; // std::cos(angle == 0);
|
||||
ai_real t = 0.0; // std::sin(angle == 0);
|
||||
|
||||
for (ai_real angle = 0.0; angle < angle_max; )
|
||||
{
|
||||
const aiVector3D v1 = aiVector3D (s * radius1, -halfHeight, t * radius1 );
|
||||
const aiVector3D v2 = aiVector3D (s * radius2, halfHeight, t * radius2 );
|
||||
|
||||
const ai_real next = angle + angle_delta;
|
||||
ai_real s2 = std::cos(next);
|
||||
ai_real t2 = std::sin(next);
|
||||
|
||||
const aiVector3D v3 = aiVector3D (s2 * radius2, halfHeight, t2 * radius2 );
|
||||
const aiVector3D v4 = aiVector3D (s2 * radius1, -halfHeight, t2 * radius1 );
|
||||
|
||||
positions.push_back(v1);
|
||||
positions.push_back(v2);
|
||||
positions.push_back(v3);
|
||||
positions.push_back(v4);
|
||||
positions.push_back(v1);
|
||||
positions.push_back(v3);
|
||||
|
||||
if (!bOpen)
|
||||
{
|
||||
// generate the end 'cap'
|
||||
positions.push_back(aiVector3D(s * radius2, halfHeight, t * radius2 ));
|
||||
positions.push_back(aiVector3D(s2 * radius2, halfHeight, t2 * radius2 ));
|
||||
positions.push_back(aiVector3D(0.0, halfHeight, 0.0));
|
||||
|
||||
|
||||
if (radius1)
|
||||
{
|
||||
// generate the other end 'cap'
|
||||
positions.push_back(aiVector3D(s * radius1, -halfHeight, t * radius1 ));
|
||||
positions.push_back(aiVector3D(s2 * radius1, -halfHeight, t2 * radius1 ));
|
||||
positions.push_back(aiVector3D(0.0, -halfHeight, 0.0));
|
||||
|
||||
}
|
||||
}
|
||||
s = s2;
|
||||
t = t2;
|
||||
angle = next;
|
||||
}
|
||||
|
||||
// Need to flip face order?
|
||||
if ( SIZE_MAX != old ) {
|
||||
for (size_t p = old; p < positions.size();p += 3) {
|
||||
std::swap(positions[p],positions[p+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build a circle
|
||||
void StandardShapes::MakeCircle(ai_real radius, unsigned int tess,
|
||||
std::vector<aiVector3D>& positions)
|
||||
{
|
||||
// Sorry, a circle with less than 3 segments makes ABSOLUTELY NO SENSE
|
||||
if (tess < 3 || !radius)
|
||||
return;
|
||||
|
||||
radius = std::fabs(radius);
|
||||
|
||||
// We will need 3 vertices per segment
|
||||
positions.reserve(positions.size()+tess*3);
|
||||
|
||||
const ai_real angle_delta = (ai_real)AI_MATH_TWO_PI / tess;
|
||||
const ai_real angle_max = (ai_real)AI_MATH_TWO_PI;
|
||||
|
||||
ai_real s = 1.0; // std::cos(angle == 0);
|
||||
ai_real t = 0.0; // std::sin(angle == 0);
|
||||
|
||||
for (ai_real angle = 0.0; angle < angle_max; )
|
||||
{
|
||||
positions.push_back(aiVector3D(s * radius,0.0,t * radius));
|
||||
angle += angle_delta;
|
||||
s = std::cos(angle);
|
||||
t = std::sin(angle);
|
||||
positions.push_back(aiVector3D(s * radius,0.0,t * radius));
|
||||
|
||||
positions.push_back(aiVector3D(0.0,0.0,0.0));
|
||||
}
|
||||
}
|
||||
|
||||
} // ! Assimp
|
||||
101
thirdparty/assimp/code/Common/StdOStreamLogStream.h
vendored
Normal file
101
thirdparty/assimp/code/Common/StdOStreamLogStream.h
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 StdOStreamLogStream.h
|
||||
* @brief Implementation of StdOStreamLogStream
|
||||
*/
|
||||
|
||||
#ifndef AI_STROSTREAMLOGSTREAM_H_INC
|
||||
#define AI_STROSTREAMLOGSTREAM_H_INC
|
||||
|
||||
#include <assimp/LogStream.hpp>
|
||||
#include <ostream>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @class StdOStreamLogStream
|
||||
* @brief Logs into a std::ostream
|
||||
*/
|
||||
class StdOStreamLogStream : public LogStream {
|
||||
public:
|
||||
/** @brief Construction from an existing std::ostream
|
||||
* @param _ostream Output stream to be used
|
||||
*/
|
||||
explicit StdOStreamLogStream(std::ostream& _ostream);
|
||||
|
||||
/** @brief Destructor */
|
||||
~StdOStreamLogStream();
|
||||
|
||||
/** @brief Writer */
|
||||
void write(const char* message);
|
||||
|
||||
private:
|
||||
std::ostream& mOstream;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Default constructor
|
||||
inline StdOStreamLogStream::StdOStreamLogStream(std::ostream& _ostream)
|
||||
: mOstream (_ostream){
|
||||
// empty
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Default constructor
|
||||
inline StdOStreamLogStream::~StdOStreamLogStream() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Write method
|
||||
inline void StdOStreamLogStream::write(const char* message) {
|
||||
mOstream << message;
|
||||
mOstream.flush();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // guard
|
||||
589
thirdparty/assimp/code/Common/Subdivision.cpp
vendored
Normal file
589
thirdparty/assimp/code/Common/Subdivision.cpp
vendored
Normal file
@@ -0,0 +1,589 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <assimp/Subdivision.h>
|
||||
#include <assimp/SceneCombiner.h>
|
||||
#include <assimp/SpatialSort.h>
|
||||
#include <assimp/Vertex.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
|
||||
#include "PostProcessing/ProcessHelper.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace Assimp;
|
||||
void mydummy() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Subdivider stub class to implement the Catmull-Clarke subdivision algorithm. The
|
||||
* implementation is basing on recursive refinement. Directly evaluating the result is also
|
||||
* possible and much quicker, but it depends on lengthy matrix lookup tables. */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class CatmullClarkSubdivider : public Subdivider {
|
||||
public:
|
||||
void Subdivide (aiMesh* mesh, aiMesh*& out, unsigned int num, bool discard_input);
|
||||
void Subdivide (aiMesh** smesh, size_t nmesh,
|
||||
aiMesh** out, unsigned int num, bool discard_input);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Intermediate description of an edge between two corners of a polygon*/
|
||||
// ---------------------------------------------------------------------------
|
||||
struct Edge
|
||||
{
|
||||
Edge()
|
||||
: ref(0)
|
||||
{}
|
||||
Vertex edge_point, midpoint;
|
||||
unsigned int ref;
|
||||
};
|
||||
|
||||
typedef std::vector<unsigned int> UIntVector;
|
||||
typedef std::map<uint64_t,Edge> EdgeMap;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Hashing function to derive an index into an #EdgeMap from two given
|
||||
// 'unsigned int' vertex coordinates (!!distinct coordinates - same
|
||||
// vertex position == same index!!).
|
||||
// NOTE - this leads to rare hash collisions if a) sizeof(unsigned int)>4
|
||||
// and (id[0]>2^32-1 or id[0]>2^32-1).
|
||||
// MAKE_EDGE_HASH() uses temporaries, so INIT_EDGE_HASH() needs to be put
|
||||
// at the head of every function which is about to use MAKE_EDGE_HASH().
|
||||
// Reason is that the hash is that hash construction needs to hold the
|
||||
// invariant id0<id1 to identify an edge - else two hashes would refer
|
||||
// to the same edge.
|
||||
// ---------------------------------------------------------------------------
|
||||
#define MAKE_EDGE_HASH(id0,id1) (eh_tmp0__=id0,eh_tmp1__=id1,\
|
||||
(eh_tmp0__<eh_tmp1__?std::swap(eh_tmp0__,eh_tmp1__):mydummy()),(uint64_t)eh_tmp0__^((uint64_t)eh_tmp1__<<32u))
|
||||
|
||||
|
||||
#define INIT_EDGE_HASH_TEMPORARIES()\
|
||||
unsigned int eh_tmp0__, eh_tmp1__;
|
||||
|
||||
private:
|
||||
void InternSubdivide (const aiMesh* const * smesh,
|
||||
size_t nmesh,aiMesh** out, unsigned int num);
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Construct a subdivider of a specific type
|
||||
Subdivider* Subdivider::Create (Algorithm algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case CATMULL_CLARKE:
|
||||
return new CatmullClarkSubdivider();
|
||||
};
|
||||
|
||||
ai_assert(false);
|
||||
return NULL; // shouldn't happen
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Call the Catmull Clark subdivision algorithm for one mesh
|
||||
void CatmullClarkSubdivider::Subdivide (
|
||||
aiMesh* mesh,
|
||||
aiMesh*& out,
|
||||
unsigned int num,
|
||||
bool discard_input
|
||||
)
|
||||
{
|
||||
ai_assert(mesh != out);
|
||||
|
||||
Subdivide(&mesh,1,&out,num,discard_input);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Call the Catmull Clark subdivision algorithm for multiple meshes
|
||||
void CatmullClarkSubdivider::Subdivide (
|
||||
aiMesh** smesh,
|
||||
size_t nmesh,
|
||||
aiMesh** out,
|
||||
unsigned int num,
|
||||
bool discard_input
|
||||
)
|
||||
{
|
||||
ai_assert( NULL != smesh );
|
||||
ai_assert( NULL != out );
|
||||
|
||||
// course, both regions may not overlap
|
||||
ai_assert(smesh<out || smesh+nmesh>out+nmesh);
|
||||
if (!num) {
|
||||
// No subdivision at all. Need to copy all the meshes .. argh.
|
||||
if (discard_input) {
|
||||
for (size_t s = 0; s < nmesh; ++s) {
|
||||
out[s] = smesh[s];
|
||||
smesh[s] = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (size_t s = 0; s < nmesh; ++s) {
|
||||
SceneCombiner::Copy(out+s,smesh[s]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<aiMesh*> inmeshes;
|
||||
std::vector<aiMesh*> outmeshes;
|
||||
std::vector<unsigned int> maptbl;
|
||||
|
||||
inmeshes.reserve(nmesh);
|
||||
outmeshes.reserve(nmesh);
|
||||
maptbl.reserve(nmesh);
|
||||
|
||||
// Remove pure line and point meshes from the working set to reduce the
|
||||
// number of edge cases the subdivider is forced to deal with. Line and
|
||||
// point meshes are simply passed through.
|
||||
for (size_t s = 0; s < nmesh; ++s) {
|
||||
aiMesh* i = smesh[s];
|
||||
// FIX - mPrimitiveTypes might not yet be initialized
|
||||
if (i->mPrimitiveTypes && (i->mPrimitiveTypes & (aiPrimitiveType_LINE|aiPrimitiveType_POINT))==i->mPrimitiveTypes) {
|
||||
ASSIMP_LOG_DEBUG("Catmull-Clark Subdivider: Skipping pure line/point mesh");
|
||||
|
||||
if (discard_input) {
|
||||
out[s] = i;
|
||||
smesh[s] = NULL;
|
||||
}
|
||||
else {
|
||||
SceneCombiner::Copy(out+s,i);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
outmeshes.push_back(NULL);inmeshes.push_back(i);
|
||||
maptbl.push_back(static_cast<unsigned int>(s));
|
||||
}
|
||||
|
||||
// Do the actual subdivision on the preallocated storage. InternSubdivide
|
||||
// *always* assumes that enough storage is available, it does not bother
|
||||
// checking any ranges.
|
||||
ai_assert(inmeshes.size()==outmeshes.size()&&inmeshes.size()==maptbl.size());
|
||||
if (inmeshes.empty()) {
|
||||
ASSIMP_LOG_WARN("Catmull-Clark Subdivider: Pure point/line scene, I can't do anything");
|
||||
return;
|
||||
}
|
||||
InternSubdivide(&inmeshes.front(),inmeshes.size(),&outmeshes.front(),num);
|
||||
for (unsigned int i = 0; i < maptbl.size(); ++i) {
|
||||
ai_assert(nullptr != outmeshes[i]);
|
||||
out[maptbl[i]] = outmeshes[i];
|
||||
}
|
||||
|
||||
if (discard_input) {
|
||||
for (size_t s = 0; s < nmesh; ++s) {
|
||||
delete smesh[s];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Note - this is an implementation of the standard (recursive) Cm-Cl algorithm without further
|
||||
// optimizations (except we're using some nice LUTs). A description of the algorithm can be found
|
||||
// here: http://en.wikipedia.org/wiki/Catmull-Clark_subdivision_surface
|
||||
//
|
||||
// The code is mostly O(n), however parts are O(nlogn) which is therefore the algorithm's
|
||||
// expected total runtime complexity. The implementation is able to work in-place on the same
|
||||
// mesh arrays. Calling #InternSubdivide() directly is not encouraged. The code can operate
|
||||
// in-place unless 'smesh' and 'out' are equal (no strange overlaps or reorderings).
|
||||
// Previous data is replaced/deleted then.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void CatmullClarkSubdivider::InternSubdivide (
|
||||
const aiMesh* const * smesh,
|
||||
size_t nmesh,
|
||||
aiMesh** out,
|
||||
unsigned int num
|
||||
)
|
||||
{
|
||||
ai_assert(NULL != smesh && NULL != out);
|
||||
INIT_EDGE_HASH_TEMPORARIES();
|
||||
|
||||
// no subdivision requested or end of recursive refinement
|
||||
if (!num) {
|
||||
return;
|
||||
}
|
||||
|
||||
UIntVector maptbl;
|
||||
SpatialSort spatial;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 0. Offset table to index all meshes continuously, generate a spatially
|
||||
// sorted representation of all vertices in all meshes.
|
||||
// ---------------------------------------------------------------------
|
||||
typedef std::pair<unsigned int,unsigned int> IntPair;
|
||||
std::vector<IntPair> moffsets(nmesh);
|
||||
unsigned int totfaces = 0, totvert = 0;
|
||||
for (size_t t = 0; t < nmesh; ++t) {
|
||||
const aiMesh* mesh = smesh[t];
|
||||
|
||||
spatial.Append(mesh->mVertices,mesh->mNumVertices,sizeof(aiVector3D),false);
|
||||
moffsets[t] = IntPair(totfaces,totvert);
|
||||
|
||||
totfaces += mesh->mNumFaces;
|
||||
totvert += mesh->mNumVertices;
|
||||
}
|
||||
|
||||
spatial.Finalize();
|
||||
const unsigned int num_unique = spatial.GenerateMappingTable(maptbl,ComputePositionEpsilon(smesh,nmesh));
|
||||
|
||||
|
||||
#define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second+vert_idx)
|
||||
#define FLATTEN_FACE_IDX(mesh_idx, face_idx) (moffsets[mesh_idx].first+face_idx)
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 1. Compute the centroid point for all faces
|
||||
// ---------------------------------------------------------------------
|
||||
std::vector<Vertex> centroids(totfaces);
|
||||
unsigned int nfacesout = 0;
|
||||
for (size_t t = 0, n = 0; t < nmesh; ++t) {
|
||||
const aiMesh* mesh = smesh[t];
|
||||
for (unsigned int i = 0; i < mesh->mNumFaces;++i,++n)
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[i];
|
||||
Vertex& c = centroids[n];
|
||||
|
||||
for (unsigned int a = 0; a < face.mNumIndices;++a) {
|
||||
c += Vertex(mesh,face.mIndices[a]);
|
||||
}
|
||||
|
||||
c /= static_cast<float>(face.mNumIndices);
|
||||
nfacesout += face.mNumIndices;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// we want edges to go away before the recursive calls so begin a new scope
|
||||
EdgeMap edges;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 2. Set each edge point to be the average of all neighbouring
|
||||
// face points and original points. Every edge exists twice
|
||||
// if there is a neighboring face.
|
||||
// ---------------------------------------------------------------------
|
||||
for (size_t t = 0; t < nmesh; ++t) {
|
||||
const aiMesh* mesh = smesh[t];
|
||||
|
||||
for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
|
||||
const aiFace& face = mesh->mFaces[i];
|
||||
|
||||
for (unsigned int p =0; p< face.mNumIndices; ++p) {
|
||||
const unsigned int id[] = {
|
||||
face.mIndices[p],
|
||||
face.mIndices[p==face.mNumIndices-1?0:p+1]
|
||||
};
|
||||
const unsigned int mp[] = {
|
||||
maptbl[FLATTEN_VERTEX_IDX(t,id[0])],
|
||||
maptbl[FLATTEN_VERTEX_IDX(t,id[1])]
|
||||
};
|
||||
|
||||
Edge& e = edges[MAKE_EDGE_HASH(mp[0],mp[1])];
|
||||
e.ref++;
|
||||
if (e.ref<=2) {
|
||||
if (e.ref==1) { // original points (end points) - add only once
|
||||
e.edge_point = e.midpoint = Vertex(mesh,id[0])+Vertex(mesh,id[1]);
|
||||
e.midpoint *= 0.5f;
|
||||
}
|
||||
e.edge_point += centroids[FLATTEN_FACE_IDX(t,i)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 3. Normalize edge points
|
||||
// ---------------------------------------------------------------------
|
||||
{unsigned int bad_cnt = 0;
|
||||
for (EdgeMap::iterator it = edges.begin(); it != edges.end(); ++it) {
|
||||
if ((*it).second.ref < 2) {
|
||||
ai_assert((*it).second.ref);
|
||||
++bad_cnt;
|
||||
}
|
||||
(*it).second.edge_point *= 1.f/((*it).second.ref+2.f);
|
||||
}
|
||||
|
||||
if (bad_cnt) {
|
||||
// Report the number of bad edges. bad edges are referenced by less than two
|
||||
// faces in the mesh. They occur at outer model boundaries in non-closed
|
||||
// shapes.
|
||||
ASSIMP_LOG_DEBUG_F("Catmull-Clark Subdivider: got ", bad_cnt, " bad edges touching only one face (totally ",
|
||||
static_cast<unsigned int>(edges.size()), " edges). ");
|
||||
}}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 4. Compute a vertex-face adjacency table. We can't reuse the code
|
||||
// from VertexTriangleAdjacency because we need the table for multiple
|
||||
// meshes and out vertex indices need to be mapped to distinct values
|
||||
// first.
|
||||
// ---------------------------------------------------------------------
|
||||
UIntVector faceadjac(nfacesout), cntadjfac(maptbl.size(),0), ofsadjvec(maptbl.size()+1,0); {
|
||||
for (size_t t = 0; t < nmesh; ++t) {
|
||||
const aiMesh* const minp = smesh[t];
|
||||
for (unsigned int i = 0; i < minp->mNumFaces; ++i) {
|
||||
|
||||
const aiFace& f = minp->mFaces[i];
|
||||
for (unsigned int n = 0; n < f.mNumIndices; ++n) {
|
||||
++cntadjfac[maptbl[FLATTEN_VERTEX_IDX(t,f.mIndices[n])]];
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned int cur = 0;
|
||||
for (size_t i = 0; i < cntadjfac.size(); ++i) {
|
||||
ofsadjvec[i+1] = cur;
|
||||
cur += cntadjfac[i];
|
||||
}
|
||||
for (size_t t = 0; t < nmesh; ++t) {
|
||||
const aiMesh* const minp = smesh[t];
|
||||
for (unsigned int i = 0; i < minp->mNumFaces; ++i) {
|
||||
|
||||
const aiFace& f = minp->mFaces[i];
|
||||
for (unsigned int n = 0; n < f.mNumIndices; ++n) {
|
||||
faceadjac[ofsadjvec[1+maptbl[FLATTEN_VERTEX_IDX(t,f.mIndices[n])]]++] = FLATTEN_FACE_IDX(t,i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check the other way round for consistency
|
||||
#ifdef ASSIMP_BUILD_DEBUG
|
||||
|
||||
for (size_t t = 0; t < ofsadjvec.size()-1; ++t) {
|
||||
for (unsigned int m = 0; m < cntadjfac[t]; ++m) {
|
||||
const unsigned int fidx = faceadjac[ofsadjvec[t]+m];
|
||||
ai_assert(fidx < totfaces);
|
||||
for (size_t n = 1; n < nmesh; ++n) {
|
||||
|
||||
if (moffsets[n].first > fidx) {
|
||||
const aiMesh* msh = smesh[--n];
|
||||
const aiFace& f = msh->mFaces[fidx-moffsets[n].first];
|
||||
|
||||
bool haveit = false;
|
||||
for (unsigned int i = 0; i < f.mNumIndices; ++i) {
|
||||
if (maptbl[FLATTEN_VERTEX_IDX(n,f.mIndices[i])]==(unsigned int)t) {
|
||||
haveit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ai_assert(haveit);
|
||||
if (!haveit) {
|
||||
ASSIMP_LOG_DEBUG("Catmull-Clark Subdivider: Index not used");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#define GET_ADJACENT_FACES_AND_CNT(vidx,fstartout,numout) \
|
||||
fstartout = &faceadjac[ofsadjvec[vidx]], numout = cntadjfac[vidx]
|
||||
|
||||
typedef std::pair<bool,Vertex> TouchedOVertex;
|
||||
std::vector<TouchedOVertex > new_points(num_unique,TouchedOVertex(false,Vertex()));
|
||||
// ---------------------------------------------------------------------
|
||||
// 5. Spawn a quad from each face point to the corresponding edge points
|
||||
// the original points being the fourth quad points.
|
||||
// ---------------------------------------------------------------------
|
||||
for (size_t t = 0; t < nmesh; ++t) {
|
||||
const aiMesh* const minp = smesh[t];
|
||||
aiMesh* const mout = out[t] = new aiMesh();
|
||||
|
||||
for (unsigned int a = 0; a < minp->mNumFaces; ++a) {
|
||||
mout->mNumFaces += minp->mFaces[a].mNumIndices;
|
||||
}
|
||||
|
||||
// We need random access to the old face buffer, so reuse is not possible.
|
||||
mout->mFaces = new aiFace[mout->mNumFaces];
|
||||
|
||||
mout->mNumVertices = mout->mNumFaces*4;
|
||||
mout->mVertices = new aiVector3D[mout->mNumVertices];
|
||||
|
||||
// quads only, keep material index
|
||||
mout->mPrimitiveTypes = aiPrimitiveType_POLYGON;
|
||||
mout->mMaterialIndex = minp->mMaterialIndex;
|
||||
|
||||
if (minp->HasNormals()) {
|
||||
mout->mNormals = new aiVector3D[mout->mNumVertices];
|
||||
}
|
||||
|
||||
if (minp->HasTangentsAndBitangents()) {
|
||||
mout->mTangents = new aiVector3D[mout->mNumVertices];
|
||||
mout->mBitangents = new aiVector3D[mout->mNumVertices];
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; minp->HasTextureCoords(i); ++i) {
|
||||
mout->mTextureCoords[i] = new aiVector3D[mout->mNumVertices];
|
||||
mout->mNumUVComponents[i] = minp->mNumUVComponents[i];
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; minp->HasVertexColors(i); ++i) {
|
||||
mout->mColors[i] = new aiColor4D[mout->mNumVertices];
|
||||
}
|
||||
|
||||
mout->mNumVertices = mout->mNumFaces<<2u;
|
||||
for (unsigned int i = 0, v = 0, n = 0; i < minp->mNumFaces;++i) {
|
||||
|
||||
const aiFace& face = minp->mFaces[i];
|
||||
for (unsigned int a = 0; a < face.mNumIndices;++a) {
|
||||
|
||||
// Get a clean new face.
|
||||
aiFace& faceOut = mout->mFaces[n++];
|
||||
faceOut.mIndices = new unsigned int [faceOut.mNumIndices = 4];
|
||||
|
||||
// Spawn a new quadrilateral (ccw winding) for this original point between:
|
||||
// a) face centroid
|
||||
centroids[FLATTEN_FACE_IDX(t,i)].SortBack(mout,faceOut.mIndices[0]=v++);
|
||||
|
||||
// b) adjacent edge on the left, seen from the centroid
|
||||
const Edge& e0 = edges[MAKE_EDGE_HASH(maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])],
|
||||
maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a==face.mNumIndices-1?0:a+1])
|
||||
])]; // fixme: replace with mod face.mNumIndices?
|
||||
|
||||
// c) adjacent edge on the right, seen from the centroid
|
||||
const Edge& e1 = edges[MAKE_EDGE_HASH(maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])],
|
||||
maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[!a?face.mNumIndices-1:a-1])
|
||||
])]; // fixme: replace with mod face.mNumIndices?
|
||||
|
||||
e0.edge_point.SortBack(mout,faceOut.mIndices[3]=v++);
|
||||
e1.edge_point.SortBack(mout,faceOut.mIndices[1]=v++);
|
||||
|
||||
// d= original point P with distinct index i
|
||||
// F := 0
|
||||
// R := 0
|
||||
// n := 0
|
||||
// for each face f containing i
|
||||
// F := F+ centroid of f
|
||||
// R := R+ midpoint of edge of f from i to i+1
|
||||
// n := n+1
|
||||
//
|
||||
// (F+2R+(n-3)P)/n
|
||||
const unsigned int org = maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])];
|
||||
TouchedOVertex& ov = new_points[org];
|
||||
|
||||
if (!ov.first) {
|
||||
ov.first = true;
|
||||
|
||||
const unsigned int* adj; unsigned int cnt;
|
||||
GET_ADJACENT_FACES_AND_CNT(org,adj,cnt);
|
||||
|
||||
if (cnt < 3) {
|
||||
ov.second = Vertex(minp,face.mIndices[a]);
|
||||
}
|
||||
else {
|
||||
|
||||
Vertex F,R;
|
||||
for (unsigned int o = 0; o < cnt; ++o) {
|
||||
ai_assert(adj[o] < totfaces);
|
||||
F += centroids[adj[o]];
|
||||
|
||||
// adj[0] is a global face index - search the face in the mesh list
|
||||
const aiMesh* mp = NULL;
|
||||
size_t nidx;
|
||||
|
||||
if (adj[o] < moffsets[0].first) {
|
||||
mp = smesh[nidx=0];
|
||||
}
|
||||
else {
|
||||
for (nidx = 1; nidx<= nmesh; ++nidx) {
|
||||
if (nidx == nmesh ||moffsets[nidx].first > adj[o]) {
|
||||
mp = smesh[--nidx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ai_assert(adj[o]-moffsets[nidx].first < mp->mNumFaces);
|
||||
const aiFace& f = mp->mFaces[adj[o]-moffsets[nidx].first];
|
||||
bool haveit = false;
|
||||
|
||||
// find our original point in the face
|
||||
for (unsigned int m = 0; m < f.mNumIndices; ++m) {
|
||||
if (maptbl[FLATTEN_VERTEX_IDX(nidx,f.mIndices[m])] == org) {
|
||||
|
||||
// add *both* edges. this way, we can be sure that we add
|
||||
// *all* adjacent edges to R. In a closed shape, every
|
||||
// edge is added twice - so we simply leave out the
|
||||
// factor 2.f in the amove formula and get the right
|
||||
// result.
|
||||
|
||||
const Edge& c0 = edges[MAKE_EDGE_HASH(org,maptbl[FLATTEN_VERTEX_IDX(
|
||||
nidx,f.mIndices[!m?f.mNumIndices-1:m-1])])];
|
||||
// fixme: replace with mod face.mNumIndices?
|
||||
|
||||
const Edge& c1 = edges[MAKE_EDGE_HASH(org,maptbl[FLATTEN_VERTEX_IDX(
|
||||
nidx,f.mIndices[m==f.mNumIndices-1?0:m+1])])];
|
||||
// fixme: replace with mod face.mNumIndices?
|
||||
R += c0.midpoint+c1.midpoint;
|
||||
|
||||
haveit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// this invariant *must* hold if the vertex-to-face adjacency table is valid
|
||||
ai_assert(haveit);
|
||||
if ( !haveit ) {
|
||||
ASSIMP_LOG_WARN( "OBJ: no name for material library specified." );
|
||||
}
|
||||
}
|
||||
|
||||
const float div = static_cast<float>(cnt), divsq = 1.f/(div*div);
|
||||
ov.second = Vertex(minp,face.mIndices[a])*((div-3.f) / div) + R*divsq + F*divsq;
|
||||
}
|
||||
}
|
||||
ov.second.SortBack(mout,faceOut.mIndices[2]=v++);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end of scope for edges, freeing its memory
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 7. Apply the next subdivision step.
|
||||
// ---------------------------------------------------------------------
|
||||
if (num != 1) {
|
||||
std::vector<aiMesh*> tmp(nmesh);
|
||||
InternSubdivide (out,nmesh,&tmp.front(),num-1);
|
||||
for (size_t i = 0; i < nmesh; ++i) {
|
||||
delete out[i];
|
||||
out[i] = tmp[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
248
thirdparty/assimp/code/Common/TargetAnimation.cpp
vendored
Normal file
248
thirdparty/assimp/code/Common/TargetAnimation.cpp
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "TargetAnimation.h"
|
||||
#include <algorithm>
|
||||
#include <assimp/ai_assert.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
KeyIterator::KeyIterator(const std::vector<aiVectorKey>* _objPos,
|
||||
const std::vector<aiVectorKey>* _targetObjPos,
|
||||
const aiVector3D* defaultObjectPos /*= NULL*/,
|
||||
const aiVector3D* defaultTargetPos /*= NULL*/)
|
||||
|
||||
: reachedEnd (false)
|
||||
, curTime (-1.)
|
||||
, objPos (_objPos)
|
||||
, targetObjPos (_targetObjPos)
|
||||
, nextObjPos (0)
|
||||
, nextTargetObjPos(0)
|
||||
{
|
||||
// Generate default transformation tracks if necessary
|
||||
if (!objPos || objPos->empty())
|
||||
{
|
||||
defaultObjPos.resize(1);
|
||||
defaultObjPos.front().mTime = 10e10;
|
||||
|
||||
if (defaultObjectPos)
|
||||
defaultObjPos.front().mValue = *defaultObjectPos;
|
||||
|
||||
objPos = & defaultObjPos;
|
||||
}
|
||||
if (!targetObjPos || targetObjPos->empty())
|
||||
{
|
||||
defaultTargetObjPos.resize(1);
|
||||
defaultTargetObjPos.front().mTime = 10e10;
|
||||
|
||||
if (defaultTargetPos)
|
||||
defaultTargetObjPos.front().mValue = *defaultTargetPos;
|
||||
|
||||
targetObjPos = & defaultTargetObjPos;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
inline T Interpolate(const T& one, const T& two, ai_real val)
|
||||
{
|
||||
return one + (two-one)*val;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void KeyIterator::operator ++()
|
||||
{
|
||||
// If we are already at the end of all keyframes, return
|
||||
if (reachedEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now search in all arrays for the time value closest
|
||||
// to our current position on the time line
|
||||
double d0,d1;
|
||||
|
||||
d0 = objPos->at ( std::min ( nextObjPos, static_cast<unsigned int>(objPos->size()-1)) ).mTime;
|
||||
d1 = targetObjPos->at( std::min ( nextTargetObjPos, static_cast<unsigned int>(targetObjPos->size()-1)) ).mTime;
|
||||
|
||||
// Easiest case - all are identical. In this
|
||||
// case we don't need to interpolate so we can
|
||||
// return earlier
|
||||
if ( d0 == d1 )
|
||||
{
|
||||
curTime = d0;
|
||||
curPosition = objPos->at(nextObjPos).mValue;
|
||||
curTargetPosition = targetObjPos->at(nextTargetObjPos).mValue;
|
||||
|
||||
// increment counters
|
||||
if (objPos->size() != nextObjPos-1)
|
||||
++nextObjPos;
|
||||
|
||||
if (targetObjPos->size() != nextTargetObjPos-1)
|
||||
++nextTargetObjPos;
|
||||
}
|
||||
|
||||
// An object position key is closest to us
|
||||
else if (d0 < d1)
|
||||
{
|
||||
curTime = d0;
|
||||
|
||||
// interpolate the other
|
||||
if (1 == targetObjPos->size() || !nextTargetObjPos) {
|
||||
curTargetPosition = targetObjPos->at(0).mValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
const aiVectorKey& last = targetObjPos->at(nextTargetObjPos);
|
||||
const aiVectorKey& first = targetObjPos->at(nextTargetObjPos-1);
|
||||
|
||||
curTargetPosition = Interpolate(first.mValue, last.mValue, (ai_real) (
|
||||
(curTime-first.mTime) / (last.mTime-first.mTime) ));
|
||||
}
|
||||
|
||||
if (objPos->size() != nextObjPos-1)
|
||||
++nextObjPos;
|
||||
}
|
||||
// A target position key is closest to us
|
||||
else
|
||||
{
|
||||
curTime = d1;
|
||||
|
||||
// interpolate the other
|
||||
if (1 == objPos->size() || !nextObjPos) {
|
||||
curPosition = objPos->at(0).mValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
const aiVectorKey& last = objPos->at(nextObjPos);
|
||||
const aiVectorKey& first = objPos->at(nextObjPos-1);
|
||||
|
||||
curPosition = Interpolate(first.mValue, last.mValue, (ai_real) (
|
||||
(curTime-first.mTime) / (last.mTime-first.mTime)));
|
||||
}
|
||||
|
||||
if (targetObjPos->size() != nextTargetObjPos-1)
|
||||
++nextTargetObjPos;
|
||||
}
|
||||
|
||||
if (nextObjPos >= objPos->size()-1 &&
|
||||
nextTargetObjPos >= targetObjPos->size()-1)
|
||||
{
|
||||
// We reached the very last keyframe
|
||||
reachedEnd = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TargetAnimationHelper::SetTargetAnimationChannel (
|
||||
const std::vector<aiVectorKey>* _targetPositions)
|
||||
{
|
||||
ai_assert(NULL != _targetPositions);
|
||||
targetPositions = _targetPositions;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TargetAnimationHelper::SetMainAnimationChannel (
|
||||
const std::vector<aiVectorKey>* _objectPositions)
|
||||
{
|
||||
ai_assert(NULL != _objectPositions);
|
||||
objectPositions = _objectPositions;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TargetAnimationHelper::SetFixedMainAnimationChannel(
|
||||
const aiVector3D& fixed)
|
||||
{
|
||||
objectPositions = NULL; // just to avoid confusion
|
||||
fixedMain = fixed;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TargetAnimationHelper::Process(std::vector<aiVectorKey>* distanceTrack)
|
||||
{
|
||||
ai_assert(NULL != targetPositions && NULL != distanceTrack);
|
||||
|
||||
// TODO: in most cases we won't need the extra array
|
||||
std::vector<aiVectorKey> real;
|
||||
|
||||
std::vector<aiVectorKey>* fill = (distanceTrack == objectPositions ? &real : distanceTrack);
|
||||
fill->reserve(std::max( objectPositions->size(), targetPositions->size() ));
|
||||
|
||||
// Iterate through all object keys and interpolate their values if necessary.
|
||||
// Then get the corresponding target position, compute the difference
|
||||
// vector between object and target position. Then compute a rotation matrix
|
||||
// that rotates the base vector of the object coordinate system at that time
|
||||
// to match the diff vector.
|
||||
|
||||
KeyIterator iter(objectPositions,targetPositions,&fixedMain);
|
||||
for (;!iter.Finished();++iter)
|
||||
{
|
||||
const aiVector3D& position = iter.GetCurPosition();
|
||||
const aiVector3D& tposition = iter.GetCurTargetPosition();
|
||||
|
||||
// diff vector
|
||||
aiVector3D diff = tposition - position;
|
||||
ai_real f = diff.Length();
|
||||
|
||||
// output distance vector
|
||||
if (f)
|
||||
{
|
||||
fill->push_back(aiVectorKey());
|
||||
aiVectorKey& v = fill->back();
|
||||
v.mTime = iter.GetCurTime();
|
||||
v.mValue = diff;
|
||||
|
||||
diff /= f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: handle this
|
||||
}
|
||||
|
||||
// diff is now the vector in which our camera is pointing
|
||||
}
|
||||
|
||||
if (real.size()) {
|
||||
*distanceTrack = real;
|
||||
}
|
||||
}
|
||||
183
thirdparty/assimp/code/Common/TargetAnimation.h
vendored
Normal file
183
thirdparty/assimp/code/Common/TargetAnimation.h
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
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 Defines a helper class for the ASE and 3DS loaders to
|
||||
help them compute camera and spot light animation channels */
|
||||
#ifndef AI_TARGET_ANIMATION_H_INC
|
||||
#define AI_TARGET_ANIMATION_H_INC
|
||||
|
||||
#include <assimp/anim.h>
|
||||
#include <vector>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper class to iterate through all keys in an animation channel.
|
||||
*
|
||||
* Missing tracks are interpolated. This is a helper class for
|
||||
* TargetAnimationHelper, but it can be freely used for other purposes.
|
||||
*/
|
||||
class KeyIterator
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
/** Constructs a new key iterator
|
||||
*
|
||||
* @param _objPos Object position track. May be NULL.
|
||||
* @param _targetObjPos Target object position track. May be NULL.
|
||||
* @param defaultObjectPos Default object position to be used if
|
||||
* no animated track is available. May be NULL.
|
||||
* @param defaultTargetPos Default target position to be used if
|
||||
* no animated track is available. May be NULL.
|
||||
*/
|
||||
KeyIterator(const std::vector<aiVectorKey>* _objPos,
|
||||
const std::vector<aiVectorKey>* _targetObjPos,
|
||||
const aiVector3D* defaultObjectPos = NULL,
|
||||
const aiVector3D* defaultTargetPos = NULL);
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
/** Returns true if all keys have been processed
|
||||
*/
|
||||
bool Finished() const
|
||||
{return reachedEnd;}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
/** Increment the iterator
|
||||
*/
|
||||
void operator++();
|
||||
inline void operator++(int)
|
||||
{return ++(*this);}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
/** Getters to retrieve the current state of the iterator
|
||||
*/
|
||||
inline const aiVector3D& GetCurPosition() const
|
||||
{return curPosition;}
|
||||
|
||||
inline const aiVector3D& GetCurTargetPosition() const
|
||||
{return curTargetPosition;}
|
||||
|
||||
inline double GetCurTime() const
|
||||
{return curTime;}
|
||||
|
||||
private:
|
||||
|
||||
//! Did we reach the end?
|
||||
bool reachedEnd;
|
||||
|
||||
//! Represents the current position of the iterator
|
||||
aiVector3D curPosition, curTargetPosition;
|
||||
|
||||
double curTime;
|
||||
|
||||
//! Input tracks and the next key to process
|
||||
const std::vector<aiVectorKey>* objPos,*targetObjPos;
|
||||
|
||||
unsigned int nextObjPos, nextTargetObjPos;
|
||||
std::vector<aiVectorKey> defaultObjPos,defaultTargetObjPos;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper class for the 3DS and ASE loaders to compute camera and spot light
|
||||
* animations.
|
||||
*
|
||||
* 3DS and ASE store the differently to Assimp - there is an animation
|
||||
* channel for the camera/spot light itself and a separate position
|
||||
* animation channels specifying the position of the camera/spot light
|
||||
* look-at target */
|
||||
class TargetAnimationHelper
|
||||
{
|
||||
public:
|
||||
|
||||
TargetAnimationHelper()
|
||||
: targetPositions (NULL)
|
||||
, objectPositions (NULL)
|
||||
{}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
/** Sets the target animation channel
|
||||
*
|
||||
* This channel specifies the position of the camera/spot light
|
||||
* target at a specific position.
|
||||
*
|
||||
* @param targetPositions Translation channel*/
|
||||
void SetTargetAnimationChannel (const
|
||||
std::vector<aiVectorKey>* targetPositions);
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
/** Sets the main animation channel
|
||||
*
|
||||
* @param objectPositions Translation channel */
|
||||
void SetMainAnimationChannel ( const
|
||||
std::vector<aiVectorKey>* objectPositions);
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
/** Sets the main animation channel to a fixed value
|
||||
*
|
||||
* @param fixed Fixed value for the main animation channel*/
|
||||
void SetFixedMainAnimationChannel(const aiVector3D& fixed);
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
/** Computes final animation channels
|
||||
* @param distanceTrack Receive camera translation keys ... != NULL. */
|
||||
void Process( std::vector<aiVectorKey>* distanceTrack );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
const std::vector<aiVectorKey>* targetPositions,*objectPositions;
|
||||
aiVector3D fixedMain;
|
||||
};
|
||||
|
||||
|
||||
} // ! end namespace Assimp
|
||||
|
||||
#endif // include guard
|
||||
185
thirdparty/assimp/code/Common/Version.cpp
vendored
Normal file
185
thirdparty/assimp/code/Common/Version.cpp
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// Actually just a dummy, used by the compiler to build the precompiled header.
|
||||
|
||||
#include <assimp/version.h>
|
||||
#include <assimp/scene.h>
|
||||
#include "ScenePrivate.h"
|
||||
|
||||
static const unsigned int MajorVersion = 5;
|
||||
static const unsigned int MinorVersion = 0;
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Legal information string - don't remove this.
|
||||
static const char* LEGAL_INFORMATION =
|
||||
|
||||
"Open Asset Import Library (Assimp).\n"
|
||||
"A free C/C++ library to import various 3D file formats into applications\n\n"
|
||||
|
||||
"(c) 2008-2020, assimp team\n"
|
||||
"License under the terms and conditions of the 3-clause BSD license\n"
|
||||
"https://github.com/assimp/assimp\n"
|
||||
;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get legal string
|
||||
ASSIMP_API const char* aiGetLegalString () {
|
||||
return LEGAL_INFORMATION;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get Assimp minor version
|
||||
ASSIMP_API unsigned int aiGetVersionMinor () {
|
||||
return MinorVersion;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get Assimp major version
|
||||
ASSIMP_API unsigned int aiGetVersionMajor () {
|
||||
return MajorVersion;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get flags used for compilation
|
||||
ASSIMP_API unsigned int aiGetCompileFlags () {
|
||||
|
||||
unsigned int flags = 0;
|
||||
|
||||
#ifdef ASSIMP_BUILD_BOOST_WORKAROUND
|
||||
flags |= ASSIMP_CFLAGS_NOBOOST;
|
||||
#endif
|
||||
#ifdef ASSIMP_BUILD_SINGLETHREADED
|
||||
flags |= ASSIMP_CFLAGS_SINGLETHREADED;
|
||||
#endif
|
||||
#ifdef ASSIMP_BUILD_DEBUG
|
||||
flags |= ASSIMP_CFLAGS_DEBUG;
|
||||
#endif
|
||||
#ifdef ASSIMP_BUILD_DLL_EXPORT
|
||||
flags |= ASSIMP_CFLAGS_SHARED;
|
||||
#endif
|
||||
#ifdef _STLPORT_VERSION
|
||||
flags |= ASSIMP_CFLAGS_STLPORT;
|
||||
#endif
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
// include current build revision, which is even updated from time to time -- :-)
|
||||
#include "revision.h"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API unsigned int aiGetVersionRevision() {
|
||||
return GitVersion;
|
||||
}
|
||||
|
||||
ASSIMP_API const char *aiGetBranchName() {
|
||||
return GitBranch;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API aiScene::aiScene()
|
||||
: mFlags(0)
|
||||
, mRootNode(nullptr)
|
||||
, mNumMeshes(0)
|
||||
, mMeshes(nullptr)
|
||||
, mNumMaterials(0)
|
||||
, mMaterials(nullptr)
|
||||
, mNumAnimations(0)
|
||||
, mAnimations(nullptr)
|
||||
, mNumTextures(0)
|
||||
, mTextures(nullptr)
|
||||
, mNumLights(0)
|
||||
, mLights(nullptr)
|
||||
, mNumCameras(0)
|
||||
, mCameras(nullptr)
|
||||
, mMetaData(nullptr)
|
||||
, mPrivate(new Assimp::ScenePrivateData()) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API aiScene::~aiScene() {
|
||||
// delete all sub-objects recursively
|
||||
delete mRootNode;
|
||||
|
||||
// To make sure we won't crash if the data is invalid it's
|
||||
// much better to check whether both mNumXXX and mXXX are
|
||||
// valid instead of relying on just one of them.
|
||||
if (mNumMeshes && mMeshes)
|
||||
for( unsigned int a = 0; a < mNumMeshes; a++)
|
||||
delete mMeshes[a];
|
||||
delete [] mMeshes;
|
||||
|
||||
if (mNumMaterials && mMaterials) {
|
||||
for (unsigned int a = 0; a < mNumMaterials; ++a ) {
|
||||
delete mMaterials[ a ];
|
||||
}
|
||||
}
|
||||
delete [] mMaterials;
|
||||
|
||||
if (mNumAnimations && mAnimations)
|
||||
for( unsigned int a = 0; a < mNumAnimations; a++)
|
||||
delete mAnimations[a];
|
||||
delete [] mAnimations;
|
||||
|
||||
if (mNumTextures && mTextures)
|
||||
for( unsigned int a = 0; a < mNumTextures; a++)
|
||||
delete mTextures[a];
|
||||
delete [] mTextures;
|
||||
|
||||
if (mNumLights && mLights)
|
||||
for( unsigned int a = 0; a < mNumLights; a++)
|
||||
delete mLights[a];
|
||||
delete [] mLights;
|
||||
|
||||
if (mNumCameras && mCameras)
|
||||
for( unsigned int a = 0; a < mNumCameras; a++)
|
||||
delete mCameras[a];
|
||||
delete [] mCameras;
|
||||
|
||||
aiMetadata::Dealloc(mMetaData);
|
||||
mMetaData = nullptr;
|
||||
|
||||
delete static_cast<Assimp::ScenePrivateData*>( mPrivate );
|
||||
}
|
||||
|
||||
134
thirdparty/assimp/code/Common/VertexTriangleAdjacency.cpp
vendored
Normal file
134
thirdparty/assimp/code/Common/VertexTriangleAdjacency.cpp
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 Implementation of the VertexTriangleAdjacency helper class
|
||||
*/
|
||||
|
||||
// internal headers
|
||||
#include "VertexTriangleAdjacency.h"
|
||||
#include <assimp/mesh.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
|
||||
unsigned int iNumFaces,
|
||||
unsigned int iNumVertices /*= 0*/,
|
||||
bool bComputeNumTriangles /*= false*/)
|
||||
{
|
||||
// compute the number of referenced vertices if it wasn't specified by the caller
|
||||
const aiFace* const pcFaceEnd = pcFaces + iNumFaces;
|
||||
if (!iNumVertices) {
|
||||
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
|
||||
ai_assert( nullptr != pcFace );
|
||||
ai_assert(3 == pcFace->mNumIndices);
|
||||
iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]);
|
||||
iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]);
|
||||
iNumVertices = std::max(iNumVertices,pcFace->mIndices[2]);
|
||||
}
|
||||
}
|
||||
|
||||
mNumVertices = iNumVertices;
|
||||
|
||||
unsigned int* pi;
|
||||
|
||||
// allocate storage
|
||||
if (bComputeNumTriangles) {
|
||||
pi = mLiveTriangles = new unsigned int[iNumVertices+1];
|
||||
::memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1));
|
||||
mOffsetTable = new unsigned int[iNumVertices+2]+1;
|
||||
} else {
|
||||
pi = mOffsetTable = new unsigned int[iNumVertices+2]+1;
|
||||
::memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1));
|
||||
mLiveTriangles = NULL; // important, otherwise the d'tor would crash
|
||||
}
|
||||
|
||||
// get a pointer to the end of the buffer
|
||||
unsigned int* piEnd = pi+iNumVertices;
|
||||
*piEnd++ = 0u;
|
||||
|
||||
// first pass: compute the number of faces referencing each vertex
|
||||
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace)
|
||||
{
|
||||
unsigned nind = pcFace->mNumIndices;
|
||||
unsigned * ind = pcFace->mIndices;
|
||||
if (nind > 0) pi[ind[0]]++;
|
||||
if (nind > 1) pi[ind[1]]++;
|
||||
if (nind > 2) pi[ind[2]]++;
|
||||
}
|
||||
|
||||
// second pass: compute the final offset table
|
||||
unsigned int iSum = 0;
|
||||
unsigned int* piCurOut = this->mOffsetTable;
|
||||
for (unsigned int* piCur = pi; piCur != piEnd;++piCur,++piCurOut) {
|
||||
|
||||
unsigned int iLastSum = iSum;
|
||||
iSum += *piCur;
|
||||
*piCurOut = iLastSum;
|
||||
}
|
||||
pi = this->mOffsetTable;
|
||||
|
||||
// third pass: compute the final table
|
||||
this->mAdjacencyTable = new unsigned int[iSum];
|
||||
iSum = 0;
|
||||
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace,++iSum) {
|
||||
unsigned nind = pcFace->mNumIndices;
|
||||
unsigned * ind = pcFace->mIndices;
|
||||
|
||||
if (nind > 0) mAdjacencyTable[pi[ind[0]]++] = iSum;
|
||||
if (nind > 1) mAdjacencyTable[pi[ind[1]]++] = iSum;
|
||||
if (nind > 2) mAdjacencyTable[pi[ind[2]]++] = iSum;
|
||||
}
|
||||
// fourth pass: undo the offset computations made during the third pass
|
||||
// We could do this in a separate buffer, but this would be TIMES slower.
|
||||
--mOffsetTable;
|
||||
*mOffsetTable = 0u;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
VertexTriangleAdjacency::~VertexTriangleAdjacency()
|
||||
{
|
||||
// delete allocated storage
|
||||
delete[] mOffsetTable;
|
||||
delete[] mAdjacencyTable;
|
||||
delete[] mLiveTriangles;
|
||||
}
|
||||
117
thirdparty/assimp/code/Common/VertexTriangleAdjacency.h
vendored
Normal file
117
thirdparty/assimp/code/Common/VertexTriangleAdjacency.h
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
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 Defines a helper class to compute a vertex-triangle adjacency map */
|
||||
#ifndef AI_VTADJACENCY_H_INC
|
||||
#define AI_VTADJACENCY_H_INC
|
||||
|
||||
#include "BaseProcess.h"
|
||||
#include <assimp/types.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
|
||||
struct aiMesh;
|
||||
struct aiFace;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
/** @brief The VertexTriangleAdjacency class computes a vertex-triangle
|
||||
* adjacency map from a given index buffer.
|
||||
*
|
||||
* @note Although it is called #VertexTriangleAdjacency, the current version does also
|
||||
* support arbitrary polygons. */
|
||||
// --------------------------------------------------------------------------------------------
|
||||
class ASSIMP_API VertexTriangleAdjacency {
|
||||
public:
|
||||
// ----------------------------------------------------------------------------
|
||||
/** @brief Construction from an existing index buffer
|
||||
* @param pcFaces Index buffer
|
||||
* @param iNumFaces Number of faces in the buffer
|
||||
* @param iNumVertices Number of referenced vertices. This value
|
||||
* is computed automatically if 0 is specified.
|
||||
* @param bComputeNumTriangles If you want the class to compute
|
||||
* a list containing the number of referenced triangles per vertex
|
||||
* per vertex - pass true. */
|
||||
VertexTriangleAdjacency(aiFace* pcFaces,unsigned int iNumFaces,
|
||||
unsigned int iNumVertices = 0,
|
||||
bool bComputeNumTriangles = true);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** @brief Destructor */
|
||||
~VertexTriangleAdjacency();
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** @brief Get all triangles adjacent to a vertex
|
||||
* @param iVertIndex Index of the vertex
|
||||
* @return A pointer to the adjacency list. */
|
||||
unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const {
|
||||
ai_assert(iVertIndex < mNumVertices);
|
||||
return &mAdjacencyTable[ mOffsetTable[iVertIndex]];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** @brief Get the number of triangles that are referenced by
|
||||
* a vertex. This function returns a reference that can be modified
|
||||
* @param iVertIndex Index of the vertex
|
||||
* @return Number of referenced triangles */
|
||||
unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex) {
|
||||
ai_assert( iVertIndex < mNumVertices );
|
||||
ai_assert( nullptr != mLiveTriangles );
|
||||
return mLiveTriangles[iVertIndex];
|
||||
}
|
||||
|
||||
//! Offset table
|
||||
unsigned int* mOffsetTable;
|
||||
|
||||
//! Adjacency table
|
||||
unsigned int* mAdjacencyTable;
|
||||
|
||||
//! Table containing the number of referenced triangles per vertex
|
||||
unsigned int* mLiveTriangles;
|
||||
|
||||
//! Debug: Number of referenced vertices
|
||||
unsigned int mNumVertices;
|
||||
};
|
||||
|
||||
} //! ns Assimp
|
||||
|
||||
#endif // !! AI_VTADJACENCY_H_INC
|
||||
95
thirdparty/assimp/code/Common/Win32DebugLogStream.h
vendored
Normal file
95
thirdparty/assimp/code/Common/Win32DebugLogStream.h
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 Win32DebugLogStream.h
|
||||
* @brief Implementation of Win32DebugLogStream
|
||||
*/
|
||||
#ifndef AI_WIN32DEBUGLOGSTREAM_H_INC
|
||||
#define AI_WIN32DEBUGLOGSTREAM_H_INC
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <assimp/LogStream.hpp>
|
||||
#include "windows.h"
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @class Win32DebugLogStream
|
||||
* @brief Logs into the debug stream from win32.
|
||||
*/
|
||||
class Win32DebugLogStream : public LogStream {
|
||||
public:
|
||||
/** @brief Default constructor */
|
||||
Win32DebugLogStream();
|
||||
|
||||
/** @brief Destructor */
|
||||
~Win32DebugLogStream();
|
||||
|
||||
/** @brief Writer */
|
||||
void write(const char* messgae);
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
inline
|
||||
Win32DebugLogStream::Win32DebugLogStream(){
|
||||
// empty
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
inline
|
||||
Win32DebugLogStream::~Win32DebugLogStream(){
|
||||
// empty
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
inline
|
||||
void Win32DebugLogStream::write(const char* message) {
|
||||
::OutputDebugStringA( message);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // ! _WIN32
|
||||
#endif // guard
|
||||
539
thirdparty/assimp/code/Common/ZipArchiveIOSystem.cpp
vendored
Normal file
539
thirdparty/assimp/code/Common/ZipArchiveIOSystem.cpp
vendored
Normal 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());
|
||||
}
|
||||
|
||||
}
|
||||
196
thirdparty/assimp/code/Common/assbin_chunks.h
vendored
Normal file
196
thirdparty/assimp/code/Common/assbin_chunks.h
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
#ifndef INCLUDED_ASSBIN_CHUNKS_H
|
||||
#define INCLUDED_ASSBIN_CHUNKS_H
|
||||
|
||||
#define ASSBIN_VERSION_MAJOR 1
|
||||
#define ASSBIN_VERSION_MINOR 0
|
||||
|
||||
/**
|
||||
@page assfile .ASS File formats
|
||||
|
||||
@section over Overview
|
||||
Assimp provides its own interchange format, which is intended to applications which need
|
||||
to serialize 3D-models and to reload them quickly. Assimp's file formats are designed to
|
||||
be read by Assimp itself. They encode additional information needed by Assimp to optimize
|
||||
its postprocessing pipeline. If you once apply specific steps to a scene, then save it
|
||||
and reread it from an ASS format using the same post processing settings, they won't
|
||||
be executed again.
|
||||
|
||||
The format comes in two flavours: XML and binary - both of them hold a complete dump of
|
||||
the 'aiScene' data structure returned by the APIs. The focus for the binary format
|
||||
(<tt>.assbin</tt>) is fast loading. Optional deflate compression helps reduce file size. The XML
|
||||
flavour, <tt>.assxml</tt> or simply .xml, is just a plain-to-xml conversion of aiScene.
|
||||
|
||||
ASSBIN is Assimp's binary interchange format. assimp_cmd (<tt><root>/tools/assimp_cmd</tt>) is able to
|
||||
write it and the core library provides a loader for it.
|
||||
|
||||
@section assxml XML File format
|
||||
|
||||
The format is pretty much self-explanatory due to its similarity to the in-memory aiScene structure.
|
||||
With few exceptions, C structures are wrapped in XML elements.
|
||||
|
||||
The DTD for ASSXML can be found in <tt><root>/doc/AssXML_Scheme.xml</tt>. Or have look
|
||||
at the output files generated by assimp_cmd.
|
||||
|
||||
@section assbin Binary file format
|
||||
|
||||
The ASSBIN file format is composed of chunks to represent the hierarchical aiScene data structure.
|
||||
This makes the format extensible and allows backward-compatibility with future data structure
|
||||
versions. The <tt><root>/code/assbin_chunks.h</tt> header contains some magic constants
|
||||
for use by stand-alone ASSBIN loaders. Also, Assimp's own file writer can be found
|
||||
in <tt><root>/tools/assimp_cmd/WriteDumb.cpp</tt> (yes, the 'b' is no typo ...).
|
||||
|
||||
@verbatim
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
1. File structure:
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
----------------------
|
||||
| Header (512 bytes) |
|
||||
----------------------
|
||||
| Variable chunks |
|
||||
----------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
2. Definitions:
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
integer is four bytes wide, stored in little-endian byte order.
|
||||
short is two bytes wide, stored in little-endian byte order.
|
||||
byte is a single byte.
|
||||
string is an integer n followed by n UTF-8 characters, not terminated by zero
|
||||
float is an IEEE 754 single-precision floating-point value
|
||||
double is an IEEE 754 double-precision floating-point value
|
||||
t[n] is an array of n elements of type t
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
2. Header:
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
byte[44] Magic identification string for ASSBIN files.
|
||||
'ASSIMP.binary'
|
||||
|
||||
integer Major version of the Assimp library which wrote the file
|
||||
integer Minor version of the Assimp library which wrote the file
|
||||
match these against ASSBIN_VERSION_MAJOR and ASSBIN_VERSION_MINOR
|
||||
|
||||
integer SVN revision of the Assimp library (intended for our internal
|
||||
debugging - if you write Ass files from your own APPs, set this value to 0.
|
||||
integer Assimp compile flags
|
||||
|
||||
short 0 for normal files, 1 for shortened dumps for regression tests
|
||||
these should have the file extension assbin.regress
|
||||
|
||||
short 1 if the data after the header is compressed with the DEFLATE algorithm,
|
||||
0 for uncompressed files.
|
||||
For compressed files, the first integer after the header is
|
||||
always the uncompressed data size
|
||||
|
||||
byte[256] Zero-terminated source file name, UTF-8
|
||||
byte[128] Zero-terminated command line parameters passed to assimp_cmd, UTF-8
|
||||
|
||||
byte[64] Reserved for future use
|
||||
---> Total length: 512 bytes
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
3. Chunks:
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
integer Magic chunk ID (ASSBIN_CHUNK_XXX)
|
||||
integer Chunk data length, in bytes
|
||||
(unknown chunks are possible, a good reader skips over them)
|
||||
(chunk-data-length does not include the first two integers)
|
||||
|
||||
byte[n] chunk-data-length bytes of data, depending on the chunk type
|
||||
|
||||
Chunks can contain nested chunks. Nested chunks are ALWAYS at the end of the chunk,
|
||||
their size is included in chunk-data-length.
|
||||
|
||||
The chunk layout for all ASSIMP data structures is derived from their C declarations.
|
||||
The general 'rule' to get from Assimp headers to the serialized layout is:
|
||||
|
||||
1. POD members (i.e. aiMesh::mPrimitiveTypes, aiMesh::mNumVertices),
|
||||
in order of declaration.
|
||||
|
||||
2. Array-members (aiMesh::mFaces, aiMesh::mVertices, aiBone::mWeights),
|
||||
in order of declaration.
|
||||
|
||||
2. Object array members (i.e aiMesh::mBones, aiScene::mMeshes) are stored in
|
||||
subchunks directly following the data written in 1.) and 2.)
|
||||
|
||||
|
||||
Of course, there are some exceptions to this general order:
|
||||
|
||||
[[aiScene]]
|
||||
|
||||
- The root node holding the scene structure is naturally stored in
|
||||
a ASSBIN_CHUNK_AINODE subchunk following 1.) and 2.) (which is
|
||||
empty for aiScene).
|
||||
|
||||
[[aiMesh]]
|
||||
|
||||
- mTextureCoords and mNumUVComponents are serialized as follows:
|
||||
|
||||
[number of used uv channels times]
|
||||
integer mNumUVComponents[n]
|
||||
float mTextureCoords[n][3]
|
||||
|
||||
-> more than AI_MAX_TEXCOORD_CHANNELS can be stored. This allows Assimp
|
||||
builds with different settings for AI_MAX_TEXCOORD_CHANNELS to exchange
|
||||
data.
|
||||
-> the on-disk format always uses 3 floats to write UV coordinates.
|
||||
If mNumUVComponents[0] is 1, the corresponding mTextureCoords array
|
||||
consists of 3 floats.
|
||||
|
||||
- The array member block of aiMesh is prefixed with an integer that specifies
|
||||
the kinds of vertex components actually present in the mesh. This is a
|
||||
bitwise combination of the ASSBIN_MESH_HAS_xxx constants.
|
||||
|
||||
[[aiFace]]
|
||||
|
||||
- mNumIndices is stored as short
|
||||
- mIndices are written as short, if aiMesh::mNumVertices<65536
|
||||
|
||||
[[aiNode]]
|
||||
|
||||
- mParent is omitted
|
||||
|
||||
[[aiLight]]
|
||||
|
||||
- mAttenuationXXX not written if aiLight::mType == aiLightSource_DIRECTIONAL
|
||||
- mAngleXXX not written if aiLight::mType != aiLightSource_SPOT
|
||||
|
||||
[[aiMaterial]]
|
||||
|
||||
- mNumAllocated is omitted, for obvious reasons :-)
|
||||
|
||||
|
||||
@endverbatim*/
|
||||
|
||||
|
||||
#define ASSBIN_HEADER_LENGTH 512
|
||||
|
||||
// these are the magic chunk identifiers for the binary ASS file format
|
||||
#define ASSBIN_CHUNK_AICAMERA 0x1234
|
||||
#define ASSBIN_CHUNK_AILIGHT 0x1235
|
||||
#define ASSBIN_CHUNK_AITEXTURE 0x1236
|
||||
#define ASSBIN_CHUNK_AIMESH 0x1237
|
||||
#define ASSBIN_CHUNK_AINODEANIM 0x1238
|
||||
#define ASSBIN_CHUNK_AISCENE 0x1239
|
||||
#define ASSBIN_CHUNK_AIBONE 0x123a
|
||||
#define ASSBIN_CHUNK_AIANIMATION 0x123b
|
||||
#define ASSBIN_CHUNK_AINODE 0x123c
|
||||
#define ASSBIN_CHUNK_AIMATERIAL 0x123d
|
||||
#define ASSBIN_CHUNK_AIMATERIALPROPERTY 0x123e
|
||||
|
||||
#define ASSBIN_MESH_HAS_POSITIONS 0x1
|
||||
#define ASSBIN_MESH_HAS_NORMALS 0x2
|
||||
#define ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS 0x4
|
||||
#define ASSBIN_MESH_HAS_TEXCOORD_BASE 0x100
|
||||
#define ASSBIN_MESH_HAS_COLOR_BASE 0x10000
|
||||
|
||||
#define ASSBIN_MESH_HAS_TEXCOORD(n) (ASSBIN_MESH_HAS_TEXCOORD_BASE << n)
|
||||
#define ASSBIN_MESH_HAS_COLOR(n) (ASSBIN_MESH_HAS_COLOR_BASE << n)
|
||||
|
||||
|
||||
#endif // INCLUDED_ASSBIN_CHUNKS_H
|
||||
140
thirdparty/assimp/code/Common/scene.cpp
vendored
Normal file
140
thirdparty/assimp/code/Common/scene.cpp
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
#include <assimp/scene.h>
|
||||
|
||||
aiNode::aiNode()
|
||||
: mName("")
|
||||
, mParent(NULL)
|
||||
, mNumChildren(0)
|
||||
, mChildren(NULL)
|
||||
, mNumMeshes(0)
|
||||
, mMeshes(NULL)
|
||||
, mMetaData(NULL) {
|
||||
// empty
|
||||
}
|
||||
|
||||
aiNode::aiNode(const std::string& name)
|
||||
: mName(name)
|
||||
, mParent(NULL)
|
||||
, mNumChildren(0)
|
||||
, mChildren(NULL)
|
||||
, mNumMeshes(0)
|
||||
, mMeshes(NULL)
|
||||
, mMetaData(NULL) {
|
||||
// empty
|
||||
}
|
||||
|
||||
/** Destructor */
|
||||
aiNode::~aiNode() {
|
||||
// delete all children recursively
|
||||
// to make sure we won't crash if the data is invalid ...
|
||||
if (mChildren && mNumChildren)
|
||||
{
|
||||
for (unsigned int a = 0; a < mNumChildren; a++)
|
||||
delete mChildren[a];
|
||||
}
|
||||
delete[] mChildren;
|
||||
delete[] mMeshes;
|
||||
delete mMetaData;
|
||||
}
|
||||
|
||||
const aiNode *aiNode::FindNode(const char* name) const {
|
||||
if (nullptr == name) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!::strcmp(mName.data, name)) {
|
||||
return this;
|
||||
}
|
||||
for (unsigned int i = 0; i < mNumChildren; ++i) {
|
||||
const aiNode* const p = mChildren[i]->FindNode(name);
|
||||
if (p) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
// there is definitely no sub-node with this name
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aiNode *aiNode::FindNode(const char* name) {
|
||||
if (!::strcmp(mName.data, name))return this;
|
||||
for (unsigned int i = 0; i < mNumChildren; ++i)
|
||||
{
|
||||
aiNode* const p = mChildren[i]->FindNode(name);
|
||||
if (p) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
// there is definitely no sub-node with this name
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void aiNode::addChildren(unsigned int numChildren, aiNode **children) {
|
||||
if (nullptr == children || 0 == numChildren) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < numChildren; i++) {
|
||||
aiNode *child = children[i];
|
||||
if (nullptr != child) {
|
||||
child->mParent = this;
|
||||
}
|
||||
}
|
||||
|
||||
if (mNumChildren > 0) {
|
||||
aiNode **tmp = new aiNode*[mNumChildren];
|
||||
::memcpy(tmp, mChildren, sizeof(aiNode*) * mNumChildren);
|
||||
delete[] mChildren;
|
||||
mChildren = new aiNode*[mNumChildren + numChildren];
|
||||
::memcpy(mChildren, tmp, sizeof(aiNode*) * mNumChildren);
|
||||
::memcpy(&mChildren[mNumChildren], children, sizeof(aiNode*)* numChildren);
|
||||
mNumChildren += numChildren;
|
||||
delete[] tmp;
|
||||
}
|
||||
else {
|
||||
mChildren = new aiNode*[numChildren];
|
||||
for (unsigned int i = 0; i < numChildren; i++) {
|
||||
mChildren[i] = children[i];
|
||||
}
|
||||
mNumChildren = numChildren;
|
||||
}
|
||||
}
|
||||
79
thirdparty/assimp/code/Common/simd.cpp
vendored
Normal file
79
thirdparty/assimp/code/Common/simd.cpp
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
#include "simd.h"
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
bool CPUSupportsSSE2() {
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
//* x86_64 always has SSE2 instructions */
|
||||
return true;
|
||||
#elif defined(__GNUC__) && defined(i386)
|
||||
// for GCC x86 we check cpuid
|
||||
unsigned int d;
|
||||
__asm__(
|
||||
"pushl %%ebx\n\t"
|
||||
"cpuid\n\t"
|
||||
"popl %%ebx\n\t"
|
||||
: "=d" ( d )
|
||||
:"a" ( 1 ) );
|
||||
return ( d & 0x04000000 ) != 0;
|
||||
#elif (defined(_MSC_VER) && defined(_M_IX86))
|
||||
// also check cpuid for MSVC x86
|
||||
unsigned int d;
|
||||
__asm {
|
||||
xor eax, eax
|
||||
inc eax
|
||||
push ebx
|
||||
cpuid
|
||||
pop ebx
|
||||
mov d, edx
|
||||
}
|
||||
return ( d & 0x04000000 ) != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
} // Namespace Assimp
|
||||
53
thirdparty/assimp/code/Common/simd.h
vendored
Normal file
53
thirdparty/assimp/code/Common/simd.h
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <assimp/defs.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/// @brief Checks if the platform supports SSE2 optimization
|
||||
/// @return true, if SSE2 is supported. false if SSE2 is not supported.
|
||||
bool ASSIMP_API CPUSupportsSSE2();
|
||||
|
||||
} // Namespace Assimp
|
||||
Reference in New Issue
Block a user