new stuff
This commit is contained in:
parent
8998bc3936
commit
64c8492e5c
6907 changed files with 3401899 additions and 0 deletions
70
assimp/code/Common/AssertHandler.cpp
Normal file
70
assimp/code/Common/AssertHandler.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 AssertHandler.cpp
|
||||
* @brief Implementation of assert handling logic.
|
||||
*/
|
||||
|
||||
#include <assimp/AssertHandler.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
void Assimp::defaultAiAssertHandler(const char* failedExpression, const char* file, int line) {
|
||||
std::cerr << "ai_assert failure in " << file << "(" << line << "): " << failedExpression << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
namespace {
|
||||
Assimp::AiAssertHandler s_handler = Assimp::defaultAiAssertHandler;
|
||||
}
|
||||
|
||||
void Assimp::setAiAssertHandler(AiAssertHandler handler) {
|
||||
if (handler != nullptr) {
|
||||
s_handler = handler;
|
||||
} else {
|
||||
s_handler = Assimp::defaultAiAssertHandler;
|
||||
}
|
||||
}
|
||||
|
||||
void Assimp::aiAssertViolation(const char* failedExpression, const char* file, int line) {
|
||||
s_handler(failedExpression, file, line);
|
||||
}
|
||||
1315
assimp/code/Common/Assimp.cpp
Normal file
1315
assimp/code/Common/Assimp.cpp
Normal file
File diff suppressed because it is too large
Load diff
190
assimp/code/Common/Base64.cpp
Normal file
190
assimp/code/Common/Base64.cpp
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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/Base64.hpp>
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
namespace Base64 {
|
||||
|
||||
static constexpr uint8_t tableDecodeBase64[128] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0,
|
||||
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
|
||||
0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static constexpr char tableEncodeBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
|
||||
static inline char EncodeChar(uint8_t b) {
|
||||
return tableEncodeBase64[size_t(b)];
|
||||
}
|
||||
|
||||
inline uint8_t DecodeChar(char c) {
|
||||
if (c & 0x80) {
|
||||
throw DeadlyImportError("Invalid base64 char value: ", size_t(c));
|
||||
}
|
||||
return tableDecodeBase64[size_t(c & 0x7F)]; // TODO faster with lookup table or ifs?
|
||||
}
|
||||
|
||||
void Encode(const uint8_t *in, size_t inLength, std::string &out) {
|
||||
if (in == nullptr || inLength==0) {
|
||||
out.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
size_t outLength = ((inLength + 2) / 3) * 4;
|
||||
|
||||
size_t j = out.size();
|
||||
out.resize(j + outLength);
|
||||
|
||||
for (size_t i = 0; i < inLength; i += 3) {
|
||||
uint8_t b = (in[i] & 0xFC) >> 2;
|
||||
out[j++] = EncodeChar(b);
|
||||
|
||||
b = (in[i] & 0x03) << 4;
|
||||
if (i + 1 < inLength) {
|
||||
b |= (in[i + 1] & 0xF0) >> 4;
|
||||
out[j++] = EncodeChar(b);
|
||||
|
||||
b = (in[i + 1] & 0x0F) << 2;
|
||||
if (i + 2 < inLength) {
|
||||
b |= (in[i + 2] & 0xC0) >> 6;
|
||||
out[j++] = EncodeChar(b);
|
||||
|
||||
b = in[i + 2] & 0x3F;
|
||||
out[j++] = EncodeChar(b);
|
||||
} else {
|
||||
out[j++] = EncodeChar(b);
|
||||
out[j++] = '=';
|
||||
}
|
||||
} else {
|
||||
out[j++] = EncodeChar(b);
|
||||
out[j++] = '=';
|
||||
out[j++] = '=';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Encode(const std::vector<uint8_t> &in, std::string &out) {
|
||||
Encode(in.data(), in.size(), out);
|
||||
}
|
||||
|
||||
std::string Encode(const std::vector<uint8_t> &in) {
|
||||
std::string encoded;
|
||||
Encode(in, encoded);
|
||||
return encoded;
|
||||
}
|
||||
|
||||
size_t Decode(const char *in, size_t inLength, uint8_t *&out) {
|
||||
if (in == nullptr) {
|
||||
out = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inLength % 4 != 0) {
|
||||
throw DeadlyImportError("Invalid base64 encoded data: \"", std::string(in, std::min(size_t(32), inLength)),
|
||||
"\", length:", inLength);
|
||||
}
|
||||
|
||||
if (inLength < 4) {
|
||||
out = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nEquals = int(in[inLength - 1] == '=') +
|
||||
int(in[inLength - 2] == '=');
|
||||
|
||||
size_t outLength = (inLength * 3) / 4 - nEquals;
|
||||
out = new uint8_t[outLength];
|
||||
memset(out, 0, outLength);
|
||||
|
||||
size_t i, j = 0;
|
||||
|
||||
for (i = 0; i + 4 < inLength; i += 4) {
|
||||
uint8_t b0 = DecodeChar(in[i]);
|
||||
uint8_t b1 = DecodeChar(in[i + 1]);
|
||||
uint8_t b2 = DecodeChar(in[i + 2]);
|
||||
uint8_t b3 = DecodeChar(in[i + 3]);
|
||||
|
||||
out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4));
|
||||
out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2));
|
||||
out[j++] = (uint8_t)((b2 << 6) | b3);
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t b0 = DecodeChar(in[i]);
|
||||
uint8_t b1 = DecodeChar(in[i + 1]);
|
||||
uint8_t b2 = DecodeChar(in[i + 2]);
|
||||
uint8_t b3 = DecodeChar(in[i + 3]);
|
||||
|
||||
out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4));
|
||||
if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2));
|
||||
if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3);
|
||||
}
|
||||
|
||||
return outLength;
|
||||
}
|
||||
|
||||
size_t Decode(const std::string &in, std::vector<uint8_t> &out) {
|
||||
uint8_t *outPtr = nullptr;
|
||||
size_t decodedSize = Decode(in.data(), in.size(), outPtr);
|
||||
if (outPtr == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
out.assign(outPtr, outPtr + decodedSize);
|
||||
delete[] outPtr;
|
||||
return decodedSize;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Decode(const std::string &in) {
|
||||
std::vector<uint8_t> result;
|
||||
Decode(in, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Base64
|
||||
} // namespace Assimp
|
||||
650
assimp/code/Common/BaseImporter.cpp
Normal file
650
assimp/code/Common/BaseImporter.cpp
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 "FileSystemFilter.h"
|
||||
#include "Importer.h"
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/ByteSwapper.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
|
||||
#include <cctype>
|
||||
#include <ios>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
namespace {
|
||||
// Checks whether the passed string is a gcs version.
|
||||
bool IsGcsVersion(const std::string &s) {
|
||||
if (s.empty()) return false;
|
||||
return std::all_of(s.cbegin(), s.cend(), [](const char c) {
|
||||
// gcs only permits numeric characters.
|
||||
return std::isdigit(static_cast<int>(c));
|
||||
});
|
||||
}
|
||||
|
||||
// Removes a possible version hash from a filename, as found for example in
|
||||
// gcs uris (e.g. `gs://bucket/model.glb#1234`), see also
|
||||
// https://github.com/GoogleCloudPlatform/gsutil/blob/c80f329bc3c4011236c78ce8910988773b2606cb/gslib/storage_url.py#L39.
|
||||
std::string StripVersionHash(const std::string &filename) {
|
||||
const std::string::size_type pos = filename.find_last_of('#');
|
||||
// Only strip if the hash is behind a possible file extension and the part
|
||||
// behind the hash is a version string.
|
||||
if (pos != std::string::npos && pos > filename.find_last_of('.') &&
|
||||
IsGcsVersion(filename.substr(pos + 1))) {
|
||||
return filename.substr(0, pos);
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
BaseImporter::BaseImporter() AI_NO_EXCEPT
|
||||
: m_progress() {
|
||||
// empty
|
||||
}
|
||||
|
||||
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("UpdateImporterScale scale set: ", 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(err.what());
|
||||
m_Exception = std::current_exception();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// return what we gathered from the import.
|
||||
return sc.release();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseImporter::SetupProperties(const Importer *) {
|
||||
// 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,
|
||||
std::size_t numTokens,
|
||||
unsigned int searchBytes /* = 200 */,
|
||||
bool tokensSol /* false */,
|
||||
bool noGraphBeforeTokens /* 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) {
|
||||
// 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((unsigned char)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(static_cast<unsigned char>(*ptr))));
|
||||
++ptr;
|
||||
}
|
||||
const char *r = strstr(buffer, token.c_str());
|
||||
if (!r) {
|
||||
continue;
|
||||
}
|
||||
// We need to make sure that we didn't accidentally 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 ", or a
|
||||
// Blender-exported glb file containing "Khronos glTF Blender I/O " was detected as "o "
|
||||
if (noGraphBeforeTokens && (r != buffer && isgraph(static_cast<unsigned char>(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("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,
|
||||
const char *ext3) {
|
||||
std::set<std::string> extensions;
|
||||
for (const char* ext : {ext0, ext1, ext2, ext3}) {
|
||||
if (ext == nullptr) continue;
|
||||
extensions.emplace(ext);
|
||||
}
|
||||
return HasExtension(pFile, extensions);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check for file extension
|
||||
/*static*/ bool BaseImporter::HasExtension(const std::string &pFile, const std::set<std::string> &extensions) {
|
||||
const std::string file = StripVersionHash(pFile);
|
||||
// CAUTION: Do not just search for the extension!
|
||||
// GetExtension() returns the part after the *last* dot, but some extensions
|
||||
// have dots inside them, e.g. ogre.mesh.xml. Compare the entire end of the
|
||||
// string.
|
||||
for (const std::string& ext : extensions) {
|
||||
// Yay for C++<20 not having std::string::ends_with()
|
||||
const std::string dotExt = "." + ext;
|
||||
if (dotExt.length() > file.length()) continue;
|
||||
// Possible optimization: Fetch the lowercase filename!
|
||||
if (0 == ASSIMP_stricmp(file.c_str() + file.length() - dotExt.length(), dotExt.c_str())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get file extension from path
|
||||
std::string BaseImporter::GetExtension(const std::string &pFile) {
|
||||
const std::string file = StripVersionHash(pFile);
|
||||
std::string::size_type pos = file.find_last_of('.');
|
||||
|
||||
// no file extension at all
|
||||
if (pos == std::string::npos) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
// thanks to Andy Maloney for the hint
|
||||
std::string ret = file.substr(pos + 1);
|
||||
ret = ai_tolower(ret);
|
||||
|
||||
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, std::size_t num, unsigned int offset, unsigned int size) {
|
||||
ai_assert(size <= 16);
|
||||
ai_assert(_magic);
|
||||
|
||||
if (!pIOHandler) {
|
||||
return false;
|
||||
}
|
||||
const char *magic = reinterpret_cast<const char *>(_magic);
|
||||
std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile));
|
||||
if (pStream) {
|
||||
|
||||
// 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 magic_u16;
|
||||
memcpy(&magic_u16, magic, 2);
|
||||
if (data_u16[0] == magic_u16 || data_u16[0] == ByteSwap::Swapped(magic_u16)) {
|
||||
return true;
|
||||
}
|
||||
} else if (4 == size) {
|
||||
uint32_t magic_u32;
|
||||
memcpy(&magic_u32, magic, 4);
|
||||
if (data_u32[0] == magic_u32 || data_u32[0] == ByteSwap::Swapped(magic_u32)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// any length ... just compare
|
||||
if (!memcmp(magic, data, size)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
magic += size;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "utf8.h"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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) {
|
||||
if (data.size() % sizeof(uint32_t) != 0) {
|
||||
throw DeadlyImportError("Not valid UTF-32 BE");
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if (data.size() % sizeof(uint32_t) != 0) {
|
||||
throw DeadlyImportError("Not valid UTF-32 LE");
|
||||
}
|
||||
ASSIMP_LOG_DEBUG("Found UTF-32 BOM ...");
|
||||
|
||||
std::vector<char> output;
|
||||
auto *ptr = (uint32_t *)&data[0];
|
||||
uint32_t *end = ptr + (data.size() / sizeof(uint32_t)) + 1;
|
||||
utf8::utf32to8(ptr, end, back_inserter(output));
|
||||
return;
|
||||
}
|
||||
|
||||
// UTF 16 BE with BOM
|
||||
if (*((uint16_t *)&data.front()) == 0xFFFE) {
|
||||
// Check to ensure no overflow can happen
|
||||
if (data.size() % sizeof(uint16_t) != 0) {
|
||||
throw DeadlyImportError("Not valid UTF-16 BE");
|
||||
}
|
||||
// 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) {
|
||||
if (data.size() % sizeof(uint16_t) != 0) {
|
||||
throw DeadlyImportError("Not valid UTF-16 LE");
|
||||
}
|
||||
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(nullptr),
|
||||
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;
|
||||
};
|
||||
} // namespace Assimp
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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 /*= nullptr*/) {
|
||||
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.emplace_back(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("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 %%%");
|
||||
}
|
||||
}
|
||||
103
assimp/code/Common/BaseProcess.cpp
Normal file
103
assimp/code/Common/BaseProcess.cpp
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 "BaseProcess.h"
|
||||
#include "Importer.h"
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
BaseProcess::BaseProcess() AI_NO_EXCEPT
|
||||
: shared(),
|
||||
progress() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseProcess::ExecuteOnScene(Importer *pImp) {
|
||||
ai_assert( nullptr != pImp );
|
||||
if (pImp == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ai_assert(nullptr != pImp->Pimpl()->mScene);
|
||||
if (pImp->Pimpl()->mScene == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
progress = pImp->GetProgressHandler();
|
||||
ai_assert(nullptr != progress);
|
||||
if (progress == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
255
assimp/code/Common/BaseProcess.h
Normal file
255
assimp/code/Common/BaseProcess.h
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 <assimp/GenericProperty.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
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() = default;
|
||||
};
|
||||
|
||||
//! Represents data that is allocated on the heap, thus needs to be deleted
|
||||
template <typename T>
|
||||
struct THeapData final : Base {
|
||||
explicit THeapData(T *in) :
|
||||
data(in) {}
|
||||
|
||||
~THeapData() override {
|
||||
delete data;
|
||||
}
|
||||
T *data;
|
||||
};
|
||||
|
||||
//! Represents static, by-value data not allocated on the heap
|
||||
template <typename T>
|
||||
struct TStaticData final : Base {
|
||||
explicit TStaticData(T in) :
|
||||
data(in) {}
|
||||
|
||||
~TStaticData() override= default;
|
||||
|
||||
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 = nullptr;
|
||||
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 ( nullptr == t) {
|
||||
return false;
|
||||
}
|
||||
out = t->data;
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Remove a property of a specific type
|
||||
void RemoveProperty(const char *name) {
|
||||
SetGenericPropertyPtr<Base>(pmap, name, nullptr );
|
||||
}
|
||||
|
||||
private:
|
||||
void AddProperty(const char *name, Base *data) {
|
||||
SetGenericPropertyPtr<Base>(pmap, name, data);
|
||||
}
|
||||
|
||||
Base *GetPropertyInternal(const char *name) const {
|
||||
return GetGenericProperty<Base *>(pmap, name, nullptr );
|
||||
}
|
||||
|
||||
private:
|
||||
//! Map of all stored properties
|
||||
PropertyMap pmap;
|
||||
};
|
||||
|
||||
#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 BaseProcess {
|
||||
friend class Importer;
|
||||
|
||||
public:
|
||||
/** @brief Constructor to be privately used by Importer */
|
||||
BaseProcess() AI_NO_EXCEPT;
|
||||
|
||||
/** @brief Destructor */
|
||||
virtual ~BaseProcess() = default;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/**
|
||||
* @brief 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;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/**
|
||||
* @brief Executes the post processing step on the given imported data.
|
||||
* The function deletes the scene if the post-process step fails (
|
||||
* the object pointer will be set to nullptr).
|
||||
* @param pImp Importer instance (pImp->mScene must be valid)
|
||||
*/
|
||||
void ExecuteOnScene(Importer *pImp);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/**
|
||||
* @brief 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);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/**
|
||||
* @brief 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 post-process steps to share data.
|
||||
* @param sh May be nullptr
|
||||
*/
|
||||
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
|
||||
158
assimp/code/Common/Bitmap.cpp
Normal file
158
assimp/code/Common/Bitmap.cpp
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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/ByteSwapper.h>
|
||||
#include <assimp/texture.h>
|
||||
#include <assimp/IOStream.hpp>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
bool Bitmap::Save(aiTexture *texture, IOStream *file) {
|
||||
if (file == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
// When padding is 0, passing it as an argument will cause an assertion failure in DefaultIOStream::Write.
|
||||
if (padding) {
|
||||
file->Write(padding_data, padding, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
||||
218
assimp/code/Common/Compression.cpp
Normal file
218
assimp/code/Common/Compression.cpp
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 "Compression.h"
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
struct Compression::impl {
|
||||
bool mOpen;
|
||||
z_stream mZSstream;
|
||||
FlushMode mFlushMode;
|
||||
|
||||
impl() :
|
||||
mOpen(false),
|
||||
mZSstream(),
|
||||
mFlushMode(Compression::FlushMode::NoFlush) {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
||||
Compression::Compression() :
|
||||
mImpl(new impl) {
|
||||
// empty
|
||||
}
|
||||
|
||||
Compression::~Compression() {
|
||||
ai_assert(mImpl != nullptr);
|
||||
|
||||
if (mImpl->mOpen) {
|
||||
close();
|
||||
}
|
||||
|
||||
delete mImpl;
|
||||
}
|
||||
|
||||
bool Compression::open(Format format, FlushMode flush, int windowBits) {
|
||||
ai_assert(mImpl != nullptr);
|
||||
|
||||
if (mImpl->mOpen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// build a zlib stream
|
||||
mImpl->mZSstream.opaque = Z_NULL;
|
||||
mImpl->mZSstream.zalloc = Z_NULL;
|
||||
mImpl->mZSstream.zfree = Z_NULL;
|
||||
mImpl->mFlushMode = flush;
|
||||
if (format == Format::Binary) {
|
||||
mImpl->mZSstream.data_type = Z_BINARY;
|
||||
} else {
|
||||
mImpl->mZSstream.data_type = Z_ASCII;
|
||||
}
|
||||
|
||||
// raw decompression without a zlib or gzip header
|
||||
if (windowBits == 0) {
|
||||
inflateInit(&mImpl->mZSstream);
|
||||
} else {
|
||||
inflateInit2(&mImpl->mZSstream, windowBits);
|
||||
}
|
||||
mImpl->mOpen = true;
|
||||
|
||||
return mImpl->mOpen;
|
||||
}
|
||||
|
||||
static int getFlushMode(Compression::FlushMode flush) {
|
||||
int z_flush = 0;
|
||||
switch (flush) {
|
||||
case Compression::FlushMode::NoFlush:
|
||||
z_flush = Z_NO_FLUSH;
|
||||
break;
|
||||
case Compression::FlushMode::Block:
|
||||
z_flush = Z_BLOCK;
|
||||
break;
|
||||
case Compression::FlushMode::Tree:
|
||||
z_flush = Z_TREES;
|
||||
break;
|
||||
case Compression::FlushMode::SyncFlush:
|
||||
z_flush = Z_SYNC_FLUSH;
|
||||
break;
|
||||
case Compression::FlushMode::Finish:
|
||||
z_flush = Z_FINISH;
|
||||
break;
|
||||
default:
|
||||
ai_assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return z_flush;
|
||||
}
|
||||
|
||||
static constexpr size_t MYBLOCK = 32786;
|
||||
|
||||
size_t Compression::decompress(const void *data, size_t in, std::vector<char> &uncompressed) {
|
||||
ai_assert(mImpl != nullptr);
|
||||
if (data == nullptr || in == 0) {
|
||||
return 0l;
|
||||
}
|
||||
|
||||
mImpl->mZSstream.next_in = (Bytef*)(data);
|
||||
mImpl->mZSstream.avail_in = (uInt)in;
|
||||
|
||||
int ret = 0;
|
||||
size_t total = 0l;
|
||||
const int flushMode = getFlushMode(mImpl->mFlushMode);
|
||||
if (flushMode == Z_FINISH) {
|
||||
mImpl->mZSstream.avail_out = static_cast<uInt>(uncompressed.size());
|
||||
mImpl->mZSstream.next_out = reinterpret_cast<Bytef *>(&*uncompressed.begin());
|
||||
ret = inflate(&mImpl->mZSstream, Z_FINISH);
|
||||
|
||||
if (ret != Z_STREAM_END && ret != Z_OK) {
|
||||
throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
|
||||
}
|
||||
total = mImpl->mZSstream.avail_out;
|
||||
} else {
|
||||
do {
|
||||
Bytef block[MYBLOCK] = {};
|
||||
mImpl->mZSstream.avail_out = MYBLOCK;
|
||||
mImpl->mZSstream.next_out = block;
|
||||
|
||||
ret = inflate(&mImpl->mZSstream, flushMode);
|
||||
|
||||
if (ret != Z_STREAM_END && ret != Z_OK) {
|
||||
throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
|
||||
}
|
||||
const size_t have = MYBLOCK - mImpl->mZSstream.avail_out;
|
||||
total += have;
|
||||
uncompressed.resize(total);
|
||||
::memcpy(uncompressed.data() + total - have, block, have);
|
||||
} while (ret != Z_STREAM_END);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
size_t Compression::decompressBlock(const void *data, size_t in, char *out, size_t availableOut) {
|
||||
ai_assert(mImpl != nullptr);
|
||||
if (data == nullptr || in == 0 || out == nullptr || availableOut == 0) {
|
||||
return 0l;
|
||||
}
|
||||
|
||||
// push data to the stream
|
||||
mImpl->mZSstream.next_in = (Bytef *)data;
|
||||
mImpl->mZSstream.avail_in = (uInt)in;
|
||||
mImpl->mZSstream.next_out = (Bytef *)out;
|
||||
mImpl->mZSstream.avail_out = (uInt)availableOut;
|
||||
|
||||
// and decompress the data ....
|
||||
int ret = ::inflate(&mImpl->mZSstream, Z_SYNC_FLUSH);
|
||||
if (ret != Z_OK && ret != Z_STREAM_END) {
|
||||
throw DeadlyImportError("X: Failed to decompress MSZIP-compressed data");
|
||||
}
|
||||
|
||||
::inflateReset(&mImpl->mZSstream);
|
||||
::inflateSetDictionary(&mImpl->mZSstream, (const Bytef *)out, (uInt)availableOut - mImpl->mZSstream.avail_out);
|
||||
|
||||
return availableOut - (size_t)mImpl->mZSstream.avail_out;
|
||||
}
|
||||
|
||||
bool Compression::isOpen() const {
|
||||
ai_assert(mImpl != nullptr);
|
||||
|
||||
return mImpl->mOpen;
|
||||
}
|
||||
|
||||
bool Compression::close() {
|
||||
ai_assert(mImpl != nullptr);
|
||||
|
||||
if (!mImpl->mOpen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inflateEnd(&mImpl->mZSstream);
|
||||
mImpl->mOpen = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
||||
117
assimp/code/Common/Compression.h
Normal file
117
assimp/code/Common/Compression.h
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 "zlib.h"
|
||||
|
||||
#include <vector>
|
||||
#include <cstddef> // size_t
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/// @brief This class provides the decompression of zlib-compressed data.
|
||||
class Compression {
|
||||
public:
|
||||
static const int MaxWBits = MAX_WBITS;
|
||||
|
||||
/// @brief Describes the format data type
|
||||
enum class Format {
|
||||
InvalidFormat = -1, ///< Invalid enum type.
|
||||
Binary = 0, ///< Binary format.
|
||||
ASCII, ///< ASCII format.
|
||||
|
||||
NumFormats ///< The number of supported formats.
|
||||
};
|
||||
|
||||
/// @brief The supported flush mode, used for blocked access.
|
||||
enum class FlushMode {
|
||||
InvalidFormat = -1, ///< Invalid enum type.
|
||||
NoFlush = 0, ///< No flush, will be done on inflate end.
|
||||
Block, ///< Assists in combination of compress.
|
||||
Tree, ///< Assists in combination of compress and returns if stream is finish.
|
||||
SyncFlush, ///< Synced flush mode.
|
||||
Finish, ///< Finish mode, all in once, no block access.
|
||||
|
||||
NumModes ///< The number of supported modes.
|
||||
};
|
||||
|
||||
/// @brief The class constructor.
|
||||
Compression();
|
||||
|
||||
/// @brief The class destructor.
|
||||
~Compression();
|
||||
|
||||
/// @brief Will open the access to the compression.
|
||||
/// @param[in] format The format type
|
||||
/// @param[in] flush The flush mode.
|
||||
/// @param[in] windowBits The windows history working size, shall be between 8 and 15.
|
||||
/// @return true if close was successful, false if not.
|
||||
bool open(Format format, FlushMode flush, int windowBits);
|
||||
|
||||
/// @brief Will return the open state.
|
||||
/// @return true if the access is opened, false if not.
|
||||
bool isOpen() const;
|
||||
|
||||
/// @brief Will close the decompress access.
|
||||
/// @return true if close was successful, false if not.
|
||||
bool close();
|
||||
|
||||
/// @brief Will decompress the data buffer in one step.
|
||||
/// @param[in] data The data to decompress
|
||||
/// @param[in] in The size of the data.
|
||||
/// @param[out uncompressed A std::vector containing the decompressed data.
|
||||
size_t decompress(const void *data, size_t in, std::vector<char> &uncompressed);
|
||||
|
||||
/// @brief Will decompress the data buffer block-wise.
|
||||
/// @param[in] data The compressed data
|
||||
/// @param[in] in The size of the data buffer
|
||||
/// @param[out] out The output buffer
|
||||
/// @param[out] availableOut The upper limit of the output buffer.
|
||||
/// @return The size of the decompressed data buffer.
|
||||
size_t decompressBlock(const void *data, size_t in, char *out, size_t availableOut);
|
||||
|
||||
private:
|
||||
struct impl;
|
||||
impl *mImpl;
|
||||
};
|
||||
|
||||
} // namespace Assimp
|
||||
92
assimp/code/Common/CreateAnimMesh.cpp
Normal file
92
assimp/code/Common/CreateAnimMesh.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2016 The Qt Company Ltd.
|
||||
Copyright (c) 2006-2026, 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, bool needPositions, bool needNormals, bool needTangents, bool needColors, bool needTexCoords)
|
||||
{
|
||||
aiAnimMesh *animesh = new aiAnimMesh;
|
||||
animesh->mNumVertices = mesh->mNumVertices;
|
||||
if (needPositions && mesh->mVertices) {
|
||||
animesh->mVertices = new aiVector3D[animesh->mNumVertices];
|
||||
std::memcpy(animesh->mVertices, mesh->mVertices, mesh->mNumVertices * sizeof(aiVector3D));
|
||||
}
|
||||
if (needNormals && mesh->mNormals) {
|
||||
animesh->mNormals = new aiVector3D[animesh->mNumVertices];
|
||||
std::memcpy(animesh->mNormals, mesh->mNormals, mesh->mNumVertices * sizeof(aiVector3D));
|
||||
}
|
||||
if (needTangents && mesh->mTangents) {
|
||||
animesh->mTangents = new aiVector3D[animesh->mNumVertices];
|
||||
std::memcpy(animesh->mTangents, mesh->mTangents, mesh->mNumVertices * sizeof(aiVector3D));
|
||||
}
|
||||
if (needTangents && mesh->mBitangents) {
|
||||
animesh->mBitangents = new aiVector3D[animesh->mNumVertices];
|
||||
std::memcpy(animesh->mBitangents, mesh->mBitangents, mesh->mNumVertices * sizeof(aiVector3D));
|
||||
}
|
||||
|
||||
if (needColors) {
|
||||
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] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needTexCoords) {
|
||||
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] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return animesh;
|
||||
}
|
||||
|
||||
} // end of namespace Assimp
|
||||
187
assimp/code/Common/DefaultIOStream.cpp
Normal file
187
assimp/code/Common/DefaultIOStream.cpp
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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/DefaultIOStream.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
namespace {
|
||||
|
||||
template <size_t sizeOfPointer>
|
||||
inline size_t select_ftell(FILE *file) {
|
||||
return ::ftell(file);
|
||||
}
|
||||
|
||||
template <size_t sizeOfPointer>
|
||||
inline int select_fseek(FILE *file, int64_t offset, int origin) {
|
||||
return ::fseek(file, static_cast<long>(offset), origin);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined _WIN32 && (!defined __GNUC__ || !defined __CLANG__ && __MSVCRT_VERSION__ >= 0x0601)
|
||||
template <>
|
||||
inline size_t select_ftell<8>(FILE *file) {
|
||||
return (size_t)::_ftelli64(file);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int select_fseek<8>(FILE *file, int64_t offset, int origin) {
|
||||
return ::_fseeki64(file, offset, origin);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
DefaultIOStream::~DefaultIOStream() {
|
||||
if (mFile) {
|
||||
::fclose(mFile);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
size_t DefaultIOStream::Read(void *pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount) {
|
||||
if (0 == pCount) {
|
||||
return 0;
|
||||
}
|
||||
ai_assert(nullptr != pvBuffer);
|
||||
ai_assert(0 != pSize);
|
||||
|
||||
return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
size_t DefaultIOStream::Write(const void *pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount) {
|
||||
ai_assert(nullptr != pvBuffer);
|
||||
ai_assert(0 != pSize);
|
||||
|
||||
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 == select_fseek<sizeof(void *)>(mFile, (int64_t)pOffset, (int)pOrigin) ? AI_SUCCESS : AI_FAILURE);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
size_t DefaultIOStream::Tell() const {
|
||||
if (!mFile) {
|
||||
return 0;
|
||||
}
|
||||
return select_ftell<sizeof(void *)>(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__ || !defined __CLANG__ && __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 _WIN32
|
||||
struct _stat fileStat;
|
||||
//using fileno + fstat avoids having to handle the filename
|
||||
int err = _fstat(_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);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
231
assimp/code/Common/DefaultIOSystem.cpp
Normal file
231
assimp/code/Common/DefaultIOSystem.cpp
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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/DefaultIOStream.h>
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#ifdef __unix__
|
||||
# include <stdlib.h>
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
const std::wstring wdummy;
|
||||
|
||||
static std::wstring Utf8ToWide(const char *in) {
|
||||
if (nullptr == in) {
|
||||
return wdummy;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
const std::string dummy;
|
||||
|
||||
static std::string WideToUtf8(const wchar_t *in) {
|
||||
if (nullptr == in) {
|
||||
return dummy;
|
||||
}
|
||||
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 {
|
||||
if (pFile == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
struct __stat64 filestat;
|
||||
if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
struct stat statbuf;
|
||||
if (stat(pFile, &statbuf) != 0) {
|
||||
return false;
|
||||
}
|
||||
// test for a regular file
|
||||
if (!S_ISREG(statbuf.st_mode)) {
|
||||
return false;
|
||||
}
|
||||
#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
|
||||
std::wstring name = Utf8ToWide(strFile);
|
||||
if (name.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
file = ::_wfopen(name.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
|
||||
else {
|
||||
// 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("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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
440
assimp/code/Common/DefaultLogger.cpp
Normal file
440
assimp/code/Common/DefaultLogger.cpp
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 "FileLogStream.h"
|
||||
#include "StdOStreamLogStream.h"
|
||||
#include "Win32DebugLogStream.h"
|
||||
#include <assimp/StringUtils.h>
|
||||
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <stdio.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/NullLogger.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
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 /*= nullptr*/) {
|
||||
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 nullptr;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// 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 /*= nullptr*/) {
|
||||
// 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 OnDebug("<fixme: long message discarded>");
|
||||
}
|
||||
return OnDebug(message);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void Logger::verboseDebug(const char *message) {
|
||||
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
|
||||
return OnVerboseDebug("<fixme: long message discarded>");
|
||||
}
|
||||
return OnVerboseDebug(message);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void Logger::info(const char *message) {
|
||||
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
|
||||
return OnInfo("<fixme: long message discarded>");
|
||||
}
|
||||
return OnInfo(message);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void Logger::warn(const char *message) {
|
||||
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
|
||||
return OnWarn("<fixme: long message discarded>");
|
||||
}
|
||||
return OnWarn(message);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void Logger::error(const char *message) {
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
|
||||
return OnError("<fixme: long message discarded>");
|
||||
}
|
||||
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) {
|
||||
m_pLogger = &s_pNullLogger;
|
||||
}
|
||||
else {
|
||||
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::DEBUGGING) {
|
||||
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);
|
||||
}
|
||||
|
||||
// Verbose debug message
|
||||
void DefaultLogger::OnVerboseDebug(const char *message) {
|
||||
if (m_Severity < Logger::VERBOSE) {
|
||||
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 = SeverityAll;
|
||||
}
|
||||
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
std::lock_guard<std::mutex> lock(m_arrayMutex);
|
||||
#endif
|
||||
|
||||
for (StreamIt it = m_StreamArray.begin();
|
||||
it != m_StreamArray.end();
|
||||
++it) {
|
||||
if ((*it)->m_pStream == pStream) {
|
||||
(*it)->m_uiErrorSeverity |= severity;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
m_StreamArray.push_back(new LogStreamInfo(severity, pStream));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Detach a stream
|
||||
bool DefaultLogger::detachStream(LogStream *pStream, unsigned int severity) {
|
||||
if (nullptr == pStream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 == severity) {
|
||||
severity = SeverityAll;
|
||||
}
|
||||
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
std::lock_guard<std::mutex> lock(m_arrayMutex);
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
std::lock_guard<std::mutex> lock(m_arrayMutex);
|
||||
#endif
|
||||
|
||||
// Check whether this is a repeated message
|
||||
auto thisLen = ::strlen(message);
|
||||
if (thisLen == lastLen - 1 && !::strncmp(message, lastMsg, lastLen - 1)) {
|
||||
if (!noRepeatMsg) {
|
||||
noRepeatMsg = true;
|
||||
message = "Skipping one or more lines with the same contents\n";
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
// append a new-line character to the message to be printed
|
||||
lastLen = thisLen;
|
||||
::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
|
||||
66
assimp/code/Common/DefaultProgressHandler.h
Normal file
66
assimp/code/Common/DefaultProgressHandler.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 final : public ProgressHandler {
|
||||
public:
|
||||
/// @brief Ignores the update callback.
|
||||
bool Update(float) override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
#endif // INCLUDED_AI_DEFAULTPROGRESSHANDLER_H
|
||||
52
assimp/code/Common/Exceptional.cpp
Normal file
52
assimp/code/Common/Exceptional.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 Exceptional.cpp
|
||||
|
||||
Implementations of the exception classes.
|
||||
|
||||
*/
|
||||
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/TinyFormatter.h>
|
||||
|
||||
DeadlyErrorBase::DeadlyErrorBase(Assimp::Formatter::format f) :
|
||||
runtime_error(std::string(f)){}
|
||||
684
assimp/code/Common/Exporter.cpp
Normal file
684
assimp/code/Common/Exporter.cpp
Normal file
|
|
@ -0,0 +1,684 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning( disable : 4800 )
|
||||
#endif // _MSC_VER
|
||||
|
||||
|
||||
// PostStepRegistry.cpp
|
||||
void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Exporter worker function prototypes. Do not use const, because some exporter need to convert
|
||||
// the scene temporary
|
||||
#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
|
||||
void ExportSceneCollada(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_X_EXPORTER
|
||||
void ExportSceneXFile(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
|
||||
void ExportSceneStep(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
|
||||
void ExportSceneObj(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneObjNoMtl(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_STL_EXPORTER
|
||||
void ExportSceneSTL(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_PLY_EXPORTER
|
||||
void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
|
||||
void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
|
||||
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*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
|
||||
void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
|
||||
void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_X3D_EXPORTER
|
||||
void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
|
||||
void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
|
||||
void ExportSceneM3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportSceneM3DA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
||||
void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*);
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_PBRT_EXPORTER
|
||||
void ExportScenePbrt(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
#endif
|
||||
|
||||
static void setupExporterArray(std::vector<Exporter::ExportFormatEntry> &exporters) {
|
||||
(void)exporters;
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
|
||||
exporters.emplace_back("collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_X_EXPORTER
|
||||
exporters.emplace_back("x", "X Files", "x", &ExportSceneXFile,
|
||||
aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
|
||||
exporters.emplace_back("stp", "Step Files", "stp", &ExportSceneStep, 0);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
|
||||
exporters.emplace_back("obj", "Wavefront OBJ format", "obj", &ExportSceneObj);
|
||||
exporters.emplace_back("objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_STL_EXPORTER
|
||||
exporters.emplace_back("stl", "Stereolithography", "stl", &ExportSceneSTL,
|
||||
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices);
|
||||
exporters.emplace_back("stlb", "Stereolithography (binary)", "stl", &ExportSceneSTLBinary,
|
||||
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_PLY_EXPORTER
|
||||
exporters.emplace_back("ply", "Stanford Polygon Library", "ply", &ExportScenePly,
|
||||
aiProcess_PreTransformVertices);
|
||||
exporters.emplace_back("plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
|
||||
aiProcess_PreTransformVertices);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
|
||||
exporters.emplace_back("3ds", "Autodesk 3DS (legacy)", "3ds", &ExportScene3DS,
|
||||
aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices);
|
||||
#endif
|
||||
|
||||
#if !defined(ASSIMP_BUILD_NO_GLTF_EXPORTER) && !defined(ASSIMP_BUILD_NO_GLTF2_EXPORTER)
|
||||
exporters.emplace_back("gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType);
|
||||
exporters.emplace_back("glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType);
|
||||
#endif
|
||||
|
||||
#if !defined(ASSIMP_BUILD_NO_GLTF_EXPORTER) && !defined(ASSIMP_BUILD_NO_GLTF1_EXPORTER)
|
||||
exporters.emplace_back("gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType);
|
||||
exporters.emplace_back("glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
|
||||
exporters.emplace_back("assbin", "Assimp Binary File", "assbin", &ExportSceneAssbin, 0);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
|
||||
exporters.emplace_back("assxml", "Assimp XML Document", "assxml", &ExportSceneAssxml, 0);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_X3D_EXPORTER
|
||||
exporters.emplace_back("x3d", "Extensible 3D", "x3d", &ExportSceneX3D, 0);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
exporters.emplace_back("fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0);
|
||||
exporters.emplace_back("fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
|
||||
exporters.push_back(Exporter::ExportFormatEntry("m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0));
|
||||
exporters.push_back(Exporter::ExportFormatEntry("m3da", "Model 3D (ascii)", "a3d", &ExportSceneM3DA, 0));
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
|
||||
exporters.emplace_back("3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_PBRT_EXPORTER
|
||||
exporters.emplace_back("pbrt", "pbrt-v4 scene description file", "pbrt", &ExportScenePbrt, aiProcess_ConvertToLeftHanded | aiProcess_Triangulate | aiProcess_SortByPType);
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
||||
exporters.emplace_back("assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
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
|
||||
setupExporterArray(mExporters);
|
||||
}
|
||||
|
||||
~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() {
|
||||
ai_assert(nullptr != pimpl);
|
||||
FreeBlob();
|
||||
delete pimpl;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Exporter::SetIOHandler( IOSystem* pIOHandler) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
pimpl->mIsDefaultIOHandler = !pIOHandler;
|
||||
pimpl->mIOSystem.reset(pIOHandler);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
IOSystem* Exporter::GetIOHandler() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
return pimpl->mIOSystem.get();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Exporter::IsDefaultIOHandler() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
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) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
if (pimpl->blob) {
|
||||
delete pimpl->blob;
|
||||
pimpl->blob = nullptr;
|
||||
}
|
||||
|
||||
auto baseName = pProperties ? pProperties->GetPropertyString(AI_CONFIG_EXPORT_BLOB_NAME, AI_BLOBIO_MAGIC) : AI_BLOBIO_MAGIC;
|
||||
|
||||
std::shared_ptr<IOSystem> old = pimpl->mIOSystem;
|
||||
BlobIOSystem *blobio = new BlobIOSystem(baseName);
|
||||
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();
|
||||
ai_assert(nullptr != pimpl);
|
||||
// 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 nullptr ExportProperties so Exporters don't have to worry.
|
||||
ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties;
|
||||
pProp->SetPropertyBool("bJoinIdenticalVertices", pp & aiProcess_JoinIdenticalVertices);
|
||||
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 {
|
||||
ai_assert(nullptr != pimpl);
|
||||
return pimpl->mError.c_str();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Exporter::FreeBlob() {
|
||||
ai_assert(nullptr != pimpl);
|
||||
delete pimpl->blob;
|
||||
pimpl->blob = nullptr;
|
||||
|
||||
pimpl->mError = "";
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportDataBlob* Exporter::GetBlob() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
return pimpl->blob;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportDataBlob* Exporter::GetOrphanedBlob() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
const aiExportDataBlob *tmp = pimpl->blob;
|
||||
pimpl->blob = nullptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t Exporter::GetExportFormatCount() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
return pimpl->mExporters.size();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
if (index >= GetExportFormatCount()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Return from static storage if the requested index is built-in.
|
||||
if (index < pimpl->mExporters.size()) {
|
||||
return &pimpl->mExporters[index].mDescription;
|
||||
}
|
||||
|
||||
return &pimpl->mExporters[index].mDescription;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
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) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
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() = default;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ExportProperties::ExportProperties(const ExportProperties &other) = default;
|
||||
|
||||
bool ExportProperties::SetPropertyCallback(const char *szName, const std::function<void *(void *)> &f) {
|
||||
return SetGenericProperty<std::function<void *(void *)>>(mCallbackProperties, szName, f);
|
||||
}
|
||||
|
||||
std::function<void *(void *)> ExportProperties::GetPropertyCallback(const char *szName) const {
|
||||
return GetGenericProperty<std::function<void *(void *)>>(mCallbackProperties, szName, nullptr);
|
||||
}
|
||||
|
||||
bool ExportProperties::HasPropertyCallback(const char *szName) const {
|
||||
return HasGenericProperty<std::function<void *(void *)>>(mCallbackProperties, szName);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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
|
||||
100
assimp/code/Common/FileLogStream.h
Normal file
100
assimp/code/Common/FileLogStream.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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/DefaultIOSystem.h>
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/LogStream.hpp>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
/** @class FileLogStream
|
||||
* @brief Logstream to write into a file.
|
||||
*/
|
||||
class FileLogStream : public LogStream {
|
||||
public:
|
||||
FileLogStream(const char *file, IOSystem *io = nullptr);
|
||||
~FileLogStream();
|
||||
void write(const char *message);
|
||||
|
||||
private:
|
||||
IOStream *m_pStream;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Constructor
|
||||
inline FileLogStream::FileLogStream(const char *file, IOSystem *io) :
|
||||
m_pStream(nullptr) {
|
||||
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 != nullptr) {
|
||||
m_pStream->Write(message, sizeof(char), ::strlen(message));
|
||||
m_pStream->Flush();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // !! ASSIMP_FILELOGSTREAM_H_INC
|
||||
344
assimp/code/Common/FileSystemFilter.h
Normal file
344
assimp/code/Common/FileSystemFilter.h
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2020, 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 = std::string();
|
||||
}
|
||||
|
||||
// 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() = default;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** 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) {
|
||||
const size_t remaining = std::distance(in.end(), it);
|
||||
// Exclude :// and \\, which remain untouched.
|
||||
// https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632
|
||||
if (remaining >= 3u && !strncmp(&*it, "://", 3 )) {
|
||||
it += 3;
|
||||
continue;
|
||||
}
|
||||
if (it == in.begin() && remaining >= 2 && !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
|
||||
131
assimp/code/Common/IFF.h
Normal file
131
assimp/code/Common/IFF.h
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
// 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;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Describes an IFF form header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
struct FormHeader
|
||||
{
|
||||
//! Length of the chunk data, in bytes
|
||||
uint32_t length;
|
||||
|
||||
//! Type of the chunk header - FourCC
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! 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 LoadForm(uint8_t*& outFile)
|
||||
{
|
||||
ChunkHeader head;
|
||||
outFile += 4;
|
||||
::memcpy(&head.length, outFile, 4);
|
||||
outFile += 4;
|
||||
::memcpy(&head.type, outFile, 4);
|
||||
|
||||
AI_LSWAP4(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 nullptr;
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif // !! AI_IFF_H_INCLUDED
|
||||
53
assimp/code/Common/IOSystem.cpp
Normal file
53
assimp/code/Common/IOSystem.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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/IOSystem.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
const std::string &IOSystem::CurrentDirectory() const {
|
||||
if ( m_pathStack.empty() ) {
|
||||
static const std::string Dummy = std::string();
|
||||
return Dummy;
|
||||
}
|
||||
return m_pathStack[ m_pathStack.size()-1 ];
|
||||
}
|
||||
1279
assimp/code/Common/Importer.cpp
Normal file
1279
assimp/code/Common/Importer.cpp
Normal file
File diff suppressed because it is too large
Load diff
252
assimp/code/Common/Importer.h
Normal file
252
assimp/code/Common/Importer.h
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 <exception>
|
||||
#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 configuration maps.
|
||||
using IntPropertyMap = std::map<KeyType, int>;
|
||||
using FloatPropertyMap = std::map<KeyType, ai_real>;
|
||||
using StringPropertyMap = std::map<KeyType, std::string>;
|
||||
using MatrixPropertyMap = std::map<KeyType, aiMatrix4x4>;
|
||||
using PointerPropertyMap = std::map<KeyType, void*>;
|
||||
|
||||
/** 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, nullptr otherwise. */
|
||||
aiScene* mScene;
|
||||
|
||||
/** The error description, if there was one. In the case of an exception,
|
||||
* mException will carry the full details. */
|
||||
std::string mErrorString;
|
||||
|
||||
/** Any exception which occurred */
|
||||
std::exception_ptr mException;
|
||||
|
||||
/** 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;
|
||||
|
||||
/** List of pointer properties */
|
||||
PointerPropertyMap mPointerProperties;
|
||||
|
||||
/** 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;
|
||||
|
||||
/// The class destructor.
|
||||
~ImporterPimpl() = default;
|
||||
};
|
||||
|
||||
inline ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT :
|
||||
mIOHandler( nullptr ),
|
||||
mIsDefaultHandler( false ),
|
||||
mProgressHandler( nullptr ),
|
||||
mIsDefaultProgressHandler( false ),
|
||||
mImporter(),
|
||||
mPostProcessingSteps(),
|
||||
mScene( nullptr ),
|
||||
mErrorString(),
|
||||
mException(),
|
||||
mIntProperties(),
|
||||
mFloatProperties(),
|
||||
mStringProperties(),
|
||||
mMatrixProperties(),
|
||||
mPointerProperties(),
|
||||
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 {
|
||||
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
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** 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 = nullptr
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** 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 nullptr 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
|
||||
401
assimp/code/Common/ImporterRegistry.cpp
Normal file
401
assimp/code/Common/ImporterRegistry.cpp
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 <assimp/anim.h>
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Importers
|
||||
// (include_new_importers_here)
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#if !defined(ASSIMP_BUILD_NO_USD_IMPORTER)
|
||||
#include "AssetLib/USD/USDLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_X_IMPORTER
|
||||
#include "AssetLib/X/XFileImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
|
||||
#include "AssetLib/AMF/AMFImporter.hpp"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
|
||||
#include "AssetLib/3DS/3DSLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MD3_IMPORTER
|
||||
#include "AssetLib/MD3/MD3Loader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MDL_IMPORTER
|
||||
#include "AssetLib/MDL/MDLLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MD2_IMPORTER
|
||||
#include "AssetLib/MD2/MD2Loader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_PLY_IMPORTER
|
||||
#include "AssetLib/Ply/PlyLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
|
||||
#include "AssetLib/ASE/ASELoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER
|
||||
#include "AssetLib/Obj/ObjFileImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_HMP_IMPORTER
|
||||
#include "AssetLib/HMP/HMPLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_SMD_IMPORTER
|
||||
#include "AssetLib/SMD/SMDLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MDC_IMPORTER
|
||||
#include "AssetLib/MDC/MDCLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MD5_IMPORTER
|
||||
#include "AssetLib/MD5/MD5Loader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_STL_IMPORTER
|
||||
#include "AssetLib/STL/STLLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_LWO_IMPORTER
|
||||
#include "AssetLib/LWO/LWOLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_DXF_IMPORTER
|
||||
#include "AssetLib/DXF/DXFLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_NFF_IMPORTER
|
||||
#include "AssetLib/NFF/NFFLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_RAW_IMPORTER
|
||||
#include "AssetLib/Raw/RawLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_SIB_IMPORTER
|
||||
#include "AssetLib/SIB/SIBImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_OFF_IMPORTER
|
||||
#include "AssetLib/OFF/OFFLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_AC_IMPORTER
|
||||
#include "AssetLib/AC/ACLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_BVH_IMPORTER
|
||||
#include "AssetLib/BVH/BVHLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER
|
||||
#include "AssetLib/Irr/IRRMeshLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_IRR_IMPORTER
|
||||
#include "AssetLib/Irr/IRRLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_Q3D_IMPORTER
|
||||
#include "AssetLib/Q3D/Q3DLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_B3D_IMPORTER
|
||||
#include "AssetLib/B3D/B3DImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER
|
||||
#include "AssetLib/Collada/ColladaLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_TERRAGEN_IMPORTER
|
||||
#include "AssetLib/Terragen/TerragenLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_CSM_IMPORTER
|
||||
#include "AssetLib/CSM/CSMLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_3D_IMPORTER
|
||||
#include "AssetLib/Unreal/UnrealLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_LWS_IMPORTER
|
||||
#include "AssetLib/LWS/LWSLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
|
||||
#include "AssetLib/Ogre/OgreImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER
|
||||
#include "AssetLib/OpenGEX/OpenGEXImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER
|
||||
#include "AssetLib/MS3D/MS3DLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_COB_IMPORTER
|
||||
#include "AssetLib/COB/COBLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||
#include "AssetLib/Blender/BlenderLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER
|
||||
#include "AssetLib/Q3BSP/Q3BSPFileImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_NDO_IMPORTER
|
||||
#include "AssetLib/NDO/NDOLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
|
||||
#include "AssetLib/IFC/IFCLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_XGL_IMPORTER
|
||||
#include "AssetLib/XGL/XGLLoader.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
#include "AssetLib/FBX/FBXImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
|
||||
#include "AssetLib/Assbin/AssbinLoader.h"
|
||||
#endif
|
||||
#if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF1_IMPORTER)
|
||||
#include "AssetLib/glTF/glTFImporter.h"
|
||||
#endif
|
||||
#if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF2_IMPORTER)
|
||||
#include "AssetLib/glTF2/glTF2Importer.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
|
||||
#include "AssetLib/C4D/C4DImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER
|
||||
#include "AssetLib/3MF/D3MFImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
|
||||
#include "AssetLib/X3D/X3DImporter.hpp"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
|
||||
#include "AssetLib/MMD/MMDImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
|
||||
#include "AssetLib/M3D/M3DImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_IQM_IMPORTER
|
||||
#include "AssetLib/IQM/IQMImporter.h"
|
||||
#endif
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void GetImporterInstanceList(std::vector<BaseImporter *> &out) {
|
||||
|
||||
// Some importers may be unimplemented or otherwise unsuitable for general use
|
||||
// in their current state. Devs can set ASSIMP_ENABLE_DEV_IMPORTERS in their
|
||||
// local environment to enable them, otherwise they're left out of the registry.
|
||||
#if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP
|
||||
// not supported under uwp
|
||||
const char *envStr = std::getenv("ASSIMP_ENABLE_DEV_IMPORTERS");
|
||||
#else
|
||||
const char *envStr = { "0" };
|
||||
#endif
|
||||
bool devImportersEnabled = envStr && strcmp(envStr, "0");
|
||||
|
||||
// Ensure no unused var warnings if all uses are #ifndef'd away below:
|
||||
(void)devImportersEnabled;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Add an instance of each worker class here
|
||||
// (register_new_importers_here)
|
||||
// ----------------------------------------------------------------------------
|
||||
out.reserve(64);
|
||||
#if !defined(ASSIMP_BUILD_NO_USD_IMPORTER)
|
||||
out.push_back(new USDImporter());
|
||||
#endif
|
||||
#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_M3D_IMPORTER)
|
||||
out.push_back(new M3DImporter());
|
||||
#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 && !defined ASSIMP_BUILD_NO_GLTF1_IMPORTER)
|
||||
out.push_back(new glTFImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_GLTF_IMPORTER && !defined ASSIMP_BUILD_NO_GLTF2_IMPORTER)
|
||||
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_IQM_IMPORTER
|
||||
out.push_back(new IQMImporter());
|
||||
#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
|
||||
93
assimp/code/Common/Maybe.h
Normal file
93
assimp/code/Common/Maybe.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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/ai_assert.h>
|
||||
#include <utility>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/// @brief This class implements an optional type
|
||||
/// @tparam T The type to store.
|
||||
template <typename T>
|
||||
struct Maybe {
|
||||
/// @brief
|
||||
Maybe() = default;
|
||||
|
||||
/// @brief
|
||||
/// @param val
|
||||
template <typename U>
|
||||
explicit Maybe(U &&val) :
|
||||
_val(std::forward<U>(val)), _valid(true) {}
|
||||
|
||||
/// @brief Validate the value
|
||||
/// @return true if valid.
|
||||
operator bool() const {
|
||||
return _valid;
|
||||
}
|
||||
|
||||
/// @brief Will assign a value.
|
||||
/// @param v The new valid value.
|
||||
template <typename U>
|
||||
void Set(U &&v) {
|
||||
ai_assert(!_valid);
|
||||
|
||||
_valid = true;
|
||||
_val = std::forward<U>(v);
|
||||
}
|
||||
|
||||
/// @brief Will return the value when it is valid.
|
||||
/// @return The value.
|
||||
const T &Get() const {
|
||||
ai_assert(_valid);
|
||||
return _val;
|
||||
}
|
||||
|
||||
Maybe &operator&() = delete;
|
||||
Maybe(const Maybe &) = delete;
|
||||
Maybe &operator=(const Maybe &) = default;
|
||||
|
||||
private:
|
||||
T _val;
|
||||
bool _valid = false;
|
||||
};
|
||||
|
||||
} // namespace Assimp
|
||||
217
assimp/code/Common/PolyTools.h
Normal file
217
assimp/code/Common/PolyTools.h
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 */
|
||||
|
||||
#pragma once
|
||||
#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 int OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2) {
|
||||
double area = GetArea2D(p0,p2,p1);
|
||||
if(std::abs(area) < ai_epsilon)
|
||||
return 0;
|
||||
else if(area > 0)
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** 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) {
|
||||
// pp should be left side of the three triangle side, by ccw arrow
|
||||
int c1 = OnLeftSideOfLine2D(p0, p1, pp);
|
||||
int c2 = OnLeftSideOfLine2D(p1, p2, pp);
|
||||
int c3 = OnLeftSideOfLine2D(p2, p0, pp);
|
||||
return (c1 >= 0) && (c2 >= 0) && (c3 >= 0);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** 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]) == 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]) == 1) {
|
||||
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);
|
||||
}
|
||||
|
||||
} // ! namespace Assimp
|
||||
|
||||
#endif // AI_POLYTOOLS_H_INCLUDED
|
||||
265
assimp/code/Common/PostStepRegistry.cpp
Normal file
265
assimp/code/Common/PostStepRegistry.cpp
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 "PostProcessing/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_ARMATUREPOPULATE_PROCESS)
|
||||
# include "PostProcessing/ArmaturePopulate.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_ARMATUREPOPULATE_PROCESS)
|
||||
out.push_back( new ArmaturePopulate());
|
||||
#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
|
||||
}
|
||||
|
||||
}
|
||||
121
assimp/code/Common/RemoveComments.cpp
Normal file
121
assimp/code/Common/RemoveComments.cpp
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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(nullptr != szComment);
|
||||
ai_assert(nullptr != szBuffer);
|
||||
ai_assert(*szComment);
|
||||
|
||||
size_t len = strlen(szComment);
|
||||
const size_t lenBuffer = strlen(szBuffer);
|
||||
if (len > lenBuffer) {
|
||||
len = lenBuffer;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < lenBuffer; i++) {
|
||||
// skip over quotes
|
||||
if (szBuffer[i] == '\"' || szBuffer[i] == '\'')
|
||||
while (++i < lenBuffer && szBuffer[i] != '\"' && szBuffer[i] != '\'');
|
||||
|
||||
if(lenBuffer - i < len) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!strncmp(szBuffer + i,szComment,len)) {
|
||||
while (i < lenBuffer && !IsLineEnd(szBuffer[i])) {
|
||||
szBuffer[i++] = chReplacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Remove multi-line comments from a file
|
||||
void CommentRemover::RemoveMultiLineComments(const char* szCommentStart,
|
||||
const char* szCommentEnd,char* szBuffer,
|
||||
char chReplacement) {
|
||||
// validate parameters
|
||||
ai_assert(nullptr != szCommentStart);
|
||||
ai_assert(nullptr != szCommentEnd);
|
||||
ai_assert(nullptr != szBuffer);
|
||||
ai_assert(*szCommentStart);
|
||||
ai_assert(*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
|
||||
160
assimp/code/Common/SGSpatialSort.cpp
Normal file
160
assimp/code/Common/SGSpatialSort.cpp
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 axes
|
||||
// in the hope that no model spreads all its vertices along this plane.
|
||||
mPlaneNormal.Set( 0.8523f, 0.34321f, 0.5736f);
|
||||
mPlaneNormal.Normalize();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SGSpatialSort::Add(const aiVector3D& vPosition, unsigned int index,
|
||||
unsigned int smoothingGroup)
|
||||
{
|
||||
// store position by index and distance
|
||||
float distance = vPosition * mPlaneNormal;
|
||||
mPositions.emplace_back( 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 array
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1380
assimp/code/Common/SceneCombiner.cpp
Normal file
1380
assimp/code/Common/SceneCombiner.cpp
Normal file
File diff suppressed because it is too large
Load diff
287
assimp/code/Common/ScenePreprocessor.cpp
Normal file
287
assimp/code/Common/ScenePreprocessor.cpp
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 != nullptr);
|
||||
|
||||
// Process all meshes
|
||||
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
||||
if (nullptr == scene->mMeshes[i]) {
|
||||
continue;
|
||||
}
|
||||
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) {
|
||||
if (nullptr == scene->mAnimations[i]) {
|
||||
continue;
|
||||
}
|
||||
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) {
|
||||
if (nullptr == scene->mMeshes[i]) {
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
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) {
|
||||
ai_assert(mesh->mFaces != nullptr);
|
||||
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 nullptr
|
||||
{
|
||||
// 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) {
|
||||
if (channel->mRotationKeys) {
|
||||
delete[] channel->mRotationKeys;
|
||||
channel->mRotationKeys = nullptr;
|
||||
}
|
||||
ai_assert(!channel->mRotationKeys);
|
||||
channel->mNumRotationKeys = 1;
|
||||
channel->mRotationKeys = new aiQuatKey[1];
|
||||
aiQuatKey &q = channel->mRotationKeys[0];
|
||||
|
||||
q.mTime = 0.;
|
||||
q.mValue = rotation;
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Dummy rotation track has been generated");
|
||||
} else {
|
||||
ai_assert(channel->mRotationKeys);
|
||||
}
|
||||
|
||||
// No scaling keys? Generate a dummy track
|
||||
if (!channel->mNumScalingKeys) {
|
||||
if (channel->mScalingKeys) {
|
||||
delete[] channel->mScalingKeys;
|
||||
channel->mScalingKeys = nullptr;
|
||||
}
|
||||
ai_assert(!channel->mScalingKeys);
|
||||
channel->mNumScalingKeys = 1;
|
||||
channel->mScalingKeys = new aiVectorKey[1];
|
||||
aiVectorKey &q = channel->mScalingKeys[0];
|
||||
|
||||
q.mTime = 0.;
|
||||
q.mValue = scaling;
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Dummy scaling track has been generated");
|
||||
} else {
|
||||
ai_assert(channel->mScalingKeys);
|
||||
}
|
||||
|
||||
// No position keys? Generate a dummy track
|
||||
if (!channel->mNumPositionKeys) {
|
||||
if (channel->mPositionKeys) {
|
||||
delete[] channel->mPositionKeys;
|
||||
channel->mPositionKeys = nullptr;
|
||||
}
|
||||
ai_assert(!channel->mPositionKeys);
|
||||
channel->mNumPositionKeys = 1;
|
||||
channel->mPositionKeys = new aiVectorKey[1];
|
||||
aiVectorKey &q = channel->mPositionKeys[0];
|
||||
|
||||
q.mTime = 0.;
|
||||
q.mValue = position;
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Dummy position track has been generated");
|
||||
} else {
|
||||
ai_assert(channel->mPositionKeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (anim->mDuration == -1.) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Setting animation duration");
|
||||
anim->mDuration = last - std::min(first, 0.);
|
||||
}
|
||||
}
|
||||
120
assimp/code/Common/ScenePreprocessor.h
Normal file
120
assimp/code/Common/ScenePreprocessor.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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: Pre-process 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(nullptr) {}
|
||||
|
||||
/** Constructs the object and assigns a specific scene to it
|
||||
*/
|
||||
ScenePreprocessor(aiScene *_scene) :
|
||||
scene(_scene) {}
|
||||
|
||||
/// @brief The class destructor.
|
||||
~ScenePreprocessor() = default;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
/** 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;
|
||||
};
|
||||
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // include guard
|
||||
104
assimp/code/Common/ScenePrivate.h
Normal file
104
assimp/code/Common/ScenePrivate.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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
|
||||
265
assimp/code/Common/SkeletonMeshBuilder.cpp
Normal file
265
assimp/code/Common/SkeletonMeshBuilder.cpp
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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/SkeletonMeshBuilder.h>
|
||||
#include <assimp/scene.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 == nullptr) {
|
||||
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 < ai_epsilon) {
|
||||
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.emplace_back(localVertexStart + 0, localVertexStart + 1, localVertexStart + 2);
|
||||
mFaces.emplace_back(localVertexStart + 3, localVertexStart + 4, localVertexStart + 5);
|
||||
mFaces.emplace_back(localVertexStart + 6, localVertexStart + 7, localVertexStart + 8);
|
||||
mFaces.emplace_back(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);
|
||||
const ai_real zero(0.0);
|
||||
|
||||
mVertices.emplace_back(-sizeEstimate, zero, zero);
|
||||
mVertices.emplace_back(zero, sizeEstimate, zero);
|
||||
mVertices.emplace_back(zero, zero, -sizeEstimate);
|
||||
mVertices.emplace_back(zero, sizeEstimate, zero);
|
||||
mVertices.emplace_back(sizeEstimate, zero, zero);
|
||||
mVertices.emplace_back(zero, zero, -sizeEstimate);
|
||||
mVertices.emplace_back(sizeEstimate, zero, zero);
|
||||
mVertices.emplace_back(zero, -sizeEstimate, zero);
|
||||
mVertices.emplace_back(zero, zero, -sizeEstimate);
|
||||
mVertices.emplace_back(zero, -sizeEstimate, zero);
|
||||
mVertices.emplace_back(-sizeEstimate, zero, zero);
|
||||
mVertices.emplace_back(zero, zero, -sizeEstimate);
|
||||
|
||||
mVertices.emplace_back(-sizeEstimate, zero, zero);
|
||||
mVertices.emplace_back(zero, zero, sizeEstimate);
|
||||
mVertices.emplace_back(zero, sizeEstimate, zero);
|
||||
mVertices.emplace_back(zero, sizeEstimate, zero);
|
||||
mVertices.emplace_back(zero, zero, sizeEstimate);
|
||||
mVertices.emplace_back(sizeEstimate, zero, zero);
|
||||
mVertices.emplace_back(sizeEstimate, zero, zero);
|
||||
mVertices.emplace_back(zero, zero, sizeEstimate);
|
||||
mVertices.emplace_back(zero, -sizeEstimate, zero);
|
||||
mVertices.emplace_back(zero, -sizeEstimate, zero);
|
||||
mVertices.emplace_back(zero, zero, sizeEstimate);
|
||||
mVertices.emplace_back(-sizeEstimate, zero, zero);
|
||||
|
||||
mFaces.emplace_back(vertexStartIndex + 0, vertexStartIndex + 1, vertexStartIndex + 2);
|
||||
mFaces.emplace_back(vertexStartIndex + 3, vertexStartIndex + 4, vertexStartIndex + 5);
|
||||
mFaces.emplace_back(vertexStartIndex + 6, vertexStartIndex + 7, vertexStartIndex + 8);
|
||||
mFaces.emplace_back(vertexStartIndex + 9, vertexStartIndex + 10, vertexStartIndex + 11);
|
||||
mFaces.emplace_back(vertexStartIndex + 12, vertexStartIndex + 13, vertexStartIndex + 14);
|
||||
mFaces.emplace_back(vertexStartIndex + 15, vertexStartIndex + 16, vertexStartIndex + 17);
|
||||
mFaces.emplace_back(vertexStartIndex + 18, vertexStartIndex + 19, vertexStartIndex + 20);
|
||||
mFaces.emplace_back(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 != nullptr; 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;
|
||||
}
|
||||
338
assimp/code/Common/SpatialSort.cpp
Normal file
338
assimp/code/Common/SpatialSort.cpp
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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
|
||||
|
||||
const aiVector3D PlaneInit(0.8523f, 0.34321f, 0.5736f);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructs a spatially sorted representation from the given position array.
|
||||
// define the reference plane. We choose some arbitrary vector away from all basic axes
|
||||
// in the hope that no model spreads all its vertices along this plane.
|
||||
SpatialSort::SpatialSort(const aiVector3D *pPositions, unsigned int pNumPositions, unsigned int pElementOffset) :
|
||||
mPlaneNormal(PlaneInit),
|
||||
mFinalized(false) {
|
||||
mPlaneNormal.Normalize();
|
||||
Fill(pPositions, pNumPositions, pElementOffset);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SpatialSort::SpatialSort() :
|
||||
mPlaneNormal(PlaneInit),
|
||||
mFinalized(false) {
|
||||
mPlaneNormal.Normalize();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SpatialSort::Fill(const aiVector3D *pPositions, unsigned int pNumPositions,
|
||||
unsigned int pElementOffset,
|
||||
bool pFinalize /*= true */) {
|
||||
mPositions.clear();
|
||||
mFinalized = false;
|
||||
Append(pPositions, pNumPositions, pElementOffset, pFinalize);
|
||||
mFinalized = pFinalize;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ai_real SpatialSort::CalculateDistance(const aiVector3D &pPosition) const {
|
||||
return (pPosition - mCentroid) * mPlaneNormal;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SpatialSort::Finalize() {
|
||||
const ai_real scale = 1.0f / mPositions.size();
|
||||
for (unsigned int i = 0; i < mPositions.size(); i++) {
|
||||
mCentroid += scale * mPositions[i].mPosition;
|
||||
}
|
||||
for (unsigned int i = 0; i < mPositions.size(); i++) {
|
||||
mPositions[i].mDistance = CalculateDistance(mPositions[i].mPosition);
|
||||
}
|
||||
std::sort(mPositions.begin(), mPositions.end());
|
||||
mFinalized = true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SpatialSort::Append(const aiVector3D *pPositions, unsigned int pNumPositions,
|
||||
unsigned int pElementOffset,
|
||||
bool pFinalize /*= true */) {
|
||||
ai_assert(!mFinalized && "You cannot add positions to the SpatialSort object after it has been finalized.");
|
||||
// store references to all given positions along with their distance to the reference plane
|
||||
const size_t initial = mPositions.size();
|
||||
mPositions.reserve(initial + pNumPositions);
|
||||
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);
|
||||
mPositions.emplace_back(static_cast<unsigned int>(a + initial), *vec);
|
||||
}
|
||||
|
||||
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 {
|
||||
ai_assert(mFinalized && "The SpatialSort object must be finalized before FindPositions can be called.");
|
||||
const ai_real dist = CalculateDistance(pPosition);
|
||||
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 array
|
||||
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);
|
||||
//::memcpy(&binValue, &pValue, sizeof(pValue));
|
||||
//return binValue;
|
||||
#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.
|
||||
const BinFloat mask = BinFloat(1) << (CHAR_BIT * sizeof(BinFloat) - 1);
|
||||
|
||||
// Two's complement?
|
||||
const bool DefaultValue = ((-42 == (~42 + 1)) && (binValue & mask));
|
||||
const bool OneComplement = ((-42 == ~42) && (binValue & mask));
|
||||
|
||||
if (DefaultValue)
|
||||
return mask - binValue;
|
||||
// One's complement?
|
||||
else if (OneComplement)
|
||||
return BinFloat(-0) - binValue;
|
||||
// Sign-magnitude? -0 = 1000... binary
|
||||
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 {
|
||||
ai_assert(mFinalized && "The SpatialSort object must be finalized before FindIdenticalPositions can be called.");
|
||||
// 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(CalculateDistance(pPosition)) - 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 {
|
||||
ai_assert(mFinalized && "The SpatialSort object must be finalized before GenerateMappingTable can be called.");
|
||||
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 - mCentroid) * 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;
|
||||
}
|
||||
98
assimp/code/Common/StackAllocator.h
Normal file
98
assimp/code/Common/StackAllocator.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 StackAllocator.h
|
||||
* @brief A very bare-bone allocator class that is suitable when
|
||||
* allocating many small objects, e.g. during parsing.
|
||||
* Individual objects are not freed, instead only the whole memory
|
||||
* can be deallocated.
|
||||
*/
|
||||
#ifndef AI_STACK_ALLOCATOR_H_INC
|
||||
#define AI_STACK_ALLOCATOR_H_INC
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/** @brief A very bare-bone allocator class that is suitable when
|
||||
* allocating many small objects, e.g. during parsing.
|
||||
* Individual objects are not freed, instead only the whole memory
|
||||
* can be deallocated.
|
||||
*/
|
||||
class StackAllocator {
|
||||
public:
|
||||
/// @brief Constructs the allocator
|
||||
StackAllocator();
|
||||
|
||||
/// @brief Destructs the allocator and frees all memory
|
||||
~StackAllocator();
|
||||
|
||||
// non copyable
|
||||
StackAllocator(const StackAllocator &) = delete;
|
||||
StackAllocator &operator=(const StackAllocator &) = delete;
|
||||
|
||||
/// @brief Returns a pointer to byteSize bytes of heap memory that persists
|
||||
/// for the lifetime of the allocator (or until FreeAll is called).
|
||||
inline void *Allocate(size_t byteSize);
|
||||
|
||||
/// @brief Releases all the memory owned by this allocator.
|
||||
// Memory provided through function Allocate is not valid anymore after this function has been called.
|
||||
inline void FreeAll();
|
||||
|
||||
private:
|
||||
constexpr const static size_t g_maxBytesPerBlock = 64 * 1024 * 1024; // The maximum size (in bytes) of a block
|
||||
constexpr const static size_t g_startBytesPerBlock = 16 * 1024; // Size of the first block. Next blocks will double in size until maximum size of g_maxBytesPerBlock
|
||||
size_t m_blockAllocationSize = g_startBytesPerBlock; // Block size of the current block
|
||||
size_t m_subIndex = g_maxBytesPerBlock; // The current byte offset in the current block
|
||||
std::vector<uint8_t *> m_storageBlocks; // A list of blocks
|
||||
};
|
||||
|
||||
} // namespace Assimp
|
||||
|
||||
/// @brief Fixes an undefined reference error when linking in certain build environments.
|
||||
// May throw warnings about needing stdc++17, but should compile without issues on modern compilers.
|
||||
inline const size_t Assimp::StackAllocator::g_maxBytesPerBlock;
|
||||
inline const size_t Assimp::StackAllocator::g_startBytesPerBlock;
|
||||
|
||||
#include "StackAllocator.inl"
|
||||
|
||||
#endif // include guard
|
||||
82
assimp/code/Common/StackAllocator.inl
Normal file
82
assimp/code/Common/StackAllocator.inl
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 "StackAllocator.h"
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
inline StackAllocator::StackAllocator() : m_storageBlocks() {}
|
||||
|
||||
inline StackAllocator::~StackAllocator() {
|
||||
FreeAll();
|
||||
}
|
||||
|
||||
inline void *StackAllocator::Allocate(size_t byteSize) {
|
||||
if (m_subIndex + byteSize > m_blockAllocationSize) // start a new block
|
||||
{
|
||||
// double block size every time, up to maximum of g_maxBytesPerBlock.
|
||||
// Block size must be at least as large as byteSize, but we want to use this for small allocations anyway.
|
||||
m_blockAllocationSize = std::max<std::size_t>(std::min<std::size_t>(m_blockAllocationSize * 2, g_maxBytesPerBlock), byteSize);
|
||||
uint8_t *data = new uint8_t[m_blockAllocationSize];
|
||||
m_storageBlocks.emplace_back(data);
|
||||
m_subIndex = byteSize;
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t *data = m_storageBlocks.back();
|
||||
data += m_subIndex;
|
||||
m_subIndex += byteSize;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
inline void StackAllocator::FreeAll() {
|
||||
for (size_t i = 0; i < m_storageBlocks.size(); i++) {
|
||||
delete [] m_storageBlocks[i];
|
||||
}
|
||||
std::vector<uint8_t *> empty;
|
||||
m_storageBlocks.swap(empty);
|
||||
// start over:
|
||||
m_blockAllocationSize = g_startBytesPerBlock;
|
||||
m_subIndex = g_maxBytesPerBlock;
|
||||
}
|
||||
482
assimp/code/Common/StandardShapes.cpp
Normal file
482
assimp/code/Common/StandardShapes.cpp
Normal file
|
|
@ -0,0 +1,482 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 <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 nullptr;
|
||||
}
|
||||
|
||||
// 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; j < numIndices; ++j, ++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) {
|
||||
const ai_real zero(0.0);
|
||||
|
||||
// generate the end 'cap'
|
||||
positions.emplace_back(s * radius2, halfHeight, t * radius2);
|
||||
positions.emplace_back(s2 * radius2, halfHeight, t2 * radius2);
|
||||
positions.emplace_back(zero, halfHeight, zero);
|
||||
|
||||
if (radius1) {
|
||||
// generate the other end 'cap'
|
||||
positions.emplace_back(s * radius1, -halfHeight, t * radius1);
|
||||
positions.emplace_back(s2 * radius1, -halfHeight, t2 * radius1);
|
||||
positions.emplace_back(zero, -halfHeight, zero);
|
||||
}
|
||||
}
|
||||
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;) {
|
||||
const ai_real zero(0.0);
|
||||
positions.emplace_back(s * radius, zero, t * radius);
|
||||
angle += angle_delta;
|
||||
s = std::cos(angle);
|
||||
t = std::sin(angle);
|
||||
positions.emplace_back(s * radius, zero, t * radius);
|
||||
|
||||
positions.emplace_back(zero, zero, zero);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
||||
126
assimp/code/Common/StbCommon.h
Normal file
126
assimp/code/Common/StbCommon.h
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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
|
||||
|
||||
#if _MSC_VER // "unreferenced function has been removed" (SSE2 detection routine in x64 builds)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4505)
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
#ifndef STB_USE_HUNTER
|
||||
/* Use prefixed names for the symbols from stb_image as it is a very commonly embedded library.
|
||||
Including vanilla stb_image symbols causes duplicate symbol problems if assimp is linked
|
||||
statically together with another library or executable that also embeds stb_image.
|
||||
|
||||
Symbols are not prefixed if using Hunter because in such case there exists a single true
|
||||
stb_image library on the system that is used by assimp and can be used by all the other
|
||||
libraries and executables.
|
||||
|
||||
The list can be regenerated using the following:
|
||||
|
||||
cat "path/to/stb/stb_image.h" | fgrep STBIDEF | fgrep '(' | sed -E 's/\*|\(.+//g' | \
|
||||
awk '{print "#define " $(NF) " assimp_" $(NF) }' | sort | uniq
|
||||
*/
|
||||
#define stbi_convert_iphone_png_to_rgb assimp_stbi_convert_iphone_png_to_rgb
|
||||
#define stbi_convert_iphone_png_to_rgb_thread assimp_stbi_convert_iphone_png_to_rgb_thread
|
||||
#define stbi_convert_wchar_to_utf8 assimp_stbi_convert_wchar_to_utf8
|
||||
#define stbi_failure_reason assimp_stbi_failure_reason
|
||||
#define stbi_hdr_to_ldr_gamma assimp_stbi_hdr_to_ldr_gamma
|
||||
#define stbi_hdr_to_ldr_scale assimp_stbi_hdr_to_ldr_scale
|
||||
#define stbi_image_free assimp_stbi_image_free
|
||||
#define stbi_info assimp_stbi_info
|
||||
#define stbi_info_from_callbacks assimp_stbi_info_from_callbacks
|
||||
#define stbi_info_from_file assimp_stbi_info_from_file
|
||||
#define stbi_info_from_memory assimp_stbi_info_from_memory
|
||||
#define stbi_is_16_bit assimp_stbi_is_16_bit
|
||||
#define stbi_is_16_bit_from_callbacks assimp_stbi_is_16_bit_from_callbacks
|
||||
#define stbi_is_16_bit_from_file assimp_stbi_is_16_bit_from_file
|
||||
#define stbi_is_16_bit_from_memory assimp_stbi_is_16_bit_from_memory
|
||||
#define stbi_is_hdr assimp_stbi_is_hdr
|
||||
#define stbi_is_hdr_from_callbacks assimp_stbi_is_hdr_from_callbacks
|
||||
#define stbi_is_hdr_from_file assimp_stbi_is_hdr_from_file
|
||||
#define stbi_is_hdr_from_memory assimp_stbi_is_hdr_from_memory
|
||||
#define stbi_ldr_to_hdr_gamma assimp_stbi_ldr_to_hdr_gamma
|
||||
#define stbi_ldr_to_hdr_scale assimp_stbi_ldr_to_hdr_scale
|
||||
#define stbi_load assimp_stbi_load
|
||||
#define stbi_load_16 assimp_stbi_load_16
|
||||
#define stbi_load_16_from_callbacks assimp_stbi_load_16_from_callbacks
|
||||
#define stbi_load_16_from_memory assimp_stbi_load_16_from_memory
|
||||
#define stbi_load_from_callbacks assimp_stbi_load_from_callbacks
|
||||
#define stbi_load_from_file assimp_stbi_load_from_file
|
||||
#define stbi_load_from_file_16 assimp_stbi_load_from_file_16
|
||||
#define stbi_load_from_memory assimp_stbi_load_from_memory
|
||||
#define stbi_load_gif_from_memory assimp_stbi_load_gif_from_memory
|
||||
#define stbi_loadf assimp_stbi_loadf
|
||||
#define stbi_loadf_from_callbacks assimp_stbi_loadf_from_callbacks
|
||||
#define stbi_loadf_from_file assimp_stbi_loadf_from_file
|
||||
#define stbi_loadf_from_memory assimp_stbi_loadf_from_memory
|
||||
#define stbi_set_flip_vertically_on_load assimp_stbi_set_flip_vertically_on_load
|
||||
#define stbi_set_flip_vertically_on_load_thread assimp_stbi_set_flip_vertically_on_load_thread
|
||||
#define stbi_set_unpremultiply_on_load assimp_stbi_set_unpremultiply_on_load
|
||||
#define stbi_set_unpremultiply_on_load_thread assimp_stbi_set_unpremultiply_on_load_thread
|
||||
#define stbi_zlib_decode_buffer assimp_stbi_zlib_decode_buffer
|
||||
#define stbi_zlib_decode_malloc assimp_stbi_zlib_decode_malloc
|
||||
#define stbi_zlib_decode_malloc_guesssize assimp_stbi_zlib_decode_malloc_guesssize
|
||||
#define stbi_zlib_decode_malloc_guesssize_headerflag assimp_stbi_zlib_decode_malloc_guesssize_headerflag
|
||||
#define stbi_zlib_decode_noheader_buffer assimp_stbi_zlib_decode_noheader_buffer
|
||||
#define stbi_zlib_decode_noheader_malloc assimp_stbi_zlib_decode_noheader_malloc
|
||||
#endif
|
||||
|
||||
#include "stb/stb_image.h"
|
||||
|
||||
#if _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
99
assimp/code/Common/StdOStreamLogStream.h
Normal file
99
assimp/code/Common/StdOStreamLogStream.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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
|
||||
587
assimp/code/Common/Subdivision.cpp
Normal file
587
assimp/code/Common/Subdivision.cpp
Normal file
|
|
@ -0,0 +1,587 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
void mydummy() {}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4709)
|
||||
#endif // _MSC_VER
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** 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::unordered_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 nullptr; // 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(nullptr != smesh);
|
||||
ai_assert(nullptr != 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] = nullptr;
|
||||
}
|
||||
} 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_VERBOSE_DEBUG("Catmull-Clark Subdivider: Skipping pure line/point mesh");
|
||||
|
||||
if (discard_input) {
|
||||
out[s] = i;
|
||||
smesh[s] = nullptr;
|
||||
} else {
|
||||
SceneCombiner::Copy(out + s, i);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
outmeshes.push_back(nullptr);
|
||||
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());
|
||||
ai_assert(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(nullptr != smesh);
|
||||
ai_assert(nullptr != 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_VERBOSE_DEBUG("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_VERBOSE_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 = nullptr;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mp == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
225
assimp/code/Common/TargetAnimation.cpp
Normal file
225
assimp/code/Common/TargetAnimation.cpp
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 <assimp/ai_assert.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
KeyIterator::KeyIterator(const std::vector<aiVectorKey> *_objPos,
|
||||
const std::vector<aiVectorKey> *_targetObjPos,
|
||||
const aiVector3D *defaultObjectPos /*= nullptr*/,
|
||||
const aiVector3D *defaultTargetPos /*= nullptr*/) :
|
||||
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(nullptr != _targetPositions);
|
||||
|
||||
targetPositions = _targetPositions;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TargetAnimationHelper::SetMainAnimationChannel(
|
||||
const std::vector<aiVectorKey> *_objectPositions) {
|
||||
ai_assert(nullptr != _objectPositions);
|
||||
|
||||
objectPositions = _objectPositions;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TargetAnimationHelper::SetFixedMainAnimationChannel(
|
||||
const aiVector3D &fixed) {
|
||||
objectPositions = nullptr; // just to avoid confusion
|
||||
fixedMain = fixed;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TargetAnimationHelper::Process(std::vector<aiVectorKey> *distanceTrack) {
|
||||
ai_assert(nullptr != targetPositions);
|
||||
ai_assert(nullptr != 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;
|
||||
}
|
||||
}
|
||||
164
assimp/code/Common/TargetAnimation.h
Normal file
164
assimp/code/Common/TargetAnimation.h
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 nullptr.
|
||||
* @param _targetObjPos Target object position track. May be nullptr.
|
||||
* @param defaultObjectPos Default object position to be used if
|
||||
* no animated track is available. May be nullptr.
|
||||
* @param defaultTargetPos Default target position to be used if
|
||||
* no animated track is available. May be nullptr.
|
||||
*/
|
||||
KeyIterator(const std::vector<aiVectorKey> *_objPos,
|
||||
const std::vector<aiVectorKey> *_targetObjPos,
|
||||
const aiVector3D *defaultObjectPos = nullptr,
|
||||
const aiVector3D *defaultTargetPos = nullptr);
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
/** 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:
|
||||
/// @brief The class constructor.
|
||||
TargetAnimationHelper() :
|
||||
targetPositions(nullptr),
|
||||
objectPositions(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
/// @brief The class destructor.
|
||||
~TargetAnimationHelper() = default;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
/** 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 ... != nullptr. */
|
||||
void Process(std::vector<aiVectorKey> *distanceTrack);
|
||||
|
||||
private:
|
||||
const std::vector<aiVectorKey> *targetPositions, *objectPositions;
|
||||
aiVector3D fixedMain;
|
||||
};
|
||||
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // include guard
|
||||
119
assimp/code/Common/Version.cpp
Normal file
119
assimp/code/Common/Version.cpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 pre-compiled header.
|
||||
|
||||
#include "ScenePrivate.h"
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/version.h>
|
||||
#include <assimp/revision.h>
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Legal information string - don't remove this.
|
||||
static constexpr 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) 2006-2026, Assimp team\n"
|
||||
"License under the terms and conditions of the 3-clause BSD license\n"
|
||||
"https://www.assimp.org\n";
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get legal string
|
||||
ASSIMP_API const char *aiGetLegalString() {
|
||||
return LEGAL_INFORMATION;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get Assimp patch version
|
||||
ASSIMP_API unsigned int aiGetVersionPatch() {
|
||||
return VER_PATCH;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get Assimp minor version
|
||||
ASSIMP_API unsigned int aiGetVersionMinor() {
|
||||
return VER_MINOR;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get Assimp major version
|
||||
ASSIMP_API unsigned int aiGetVersionMajor() {
|
||||
return VER_MAJOR;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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
|
||||
#ifdef ASSIMP_DOUBLE_PRECISION
|
||||
flags |= ASSIMP_CFLAGS_DOUBLE_SUPPORT;
|
||||
#endif
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API unsigned int aiGetVersionRevision() {
|
||||
return GitVersion;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API const char *aiGetBranchName() {
|
||||
return GitBranch;
|
||||
}
|
||||
|
||||
129
assimp/code/Common/VertexTriangleAdjacency.cpp
Normal file
129
assimp/code/Common/VertexTriangleAdjacency.cpp
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 (0 == 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 + 1;
|
||||
|
||||
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 = nullptr; // 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;
|
||||
}
|
||||
116
assimp/code/Common/VertexTriangleAdjacency.h
Normal file
116
assimp/code/Common/VertexTriangleAdjacency.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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
|
||||
93
assimp/code/Common/Win32DebugLogStream.h
Normal file
93
assimp/code/Common/Win32DebugLogStream.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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
|
||||
602
assimp/code/Common/ZipArchiveIOSystem.cpp
Normal file
602
assimp/code/Common/ZipArchiveIOSystem.cpp
Normal file
|
|
@ -0,0 +1,602 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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/BaseImporter.h>
|
||||
#include <assimp/ZipArchiveIOSystem.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 {
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// A read-only file inside a ZIP
|
||||
|
||||
class ZipFile final : public IOStream {
|
||||
friend class ZipFileInfo;
|
||||
explicit ZipFile(std::string &filename, size_t size);
|
||||
|
||||
public:
|
||||
std::string m_Filename;
|
||||
~ZipFile() override = default;
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Wraps an existing Assimp::IOSystem for unzip
|
||||
class IOSystem2Unzip {
|
||||
public:
|
||||
IOSystem2Unzip() = default;
|
||||
~IOSystem2Unzip() = default;
|
||||
static voidpf open(voidpf opaque, const char *filename, int mode);
|
||||
static voidpf opendisk(voidpf opaque, voidpf stream, uint32_t number_disk, 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);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
voidpf IOSystem2Unzip::opendisk(voidpf opaque, voidpf stream, uint32_t number_disk, int mode) {
|
||||
ZipFile *io_stream = (ZipFile *)stream;
|
||||
voidpf ret = nullptr;
|
||||
int i;
|
||||
|
||||
char *disk_filename = (char*)malloc(io_stream->m_Filename.length() + 1);
|
||||
strncpy(disk_filename, io_stream->m_Filename.c_str(), io_stream->m_Filename.length() + 1);
|
||||
for (i = (int)io_stream->m_Filename.length() - 1; i >= 0; i -= 1)
|
||||
{
|
||||
if (disk_filename[i] != '.')
|
||||
continue;
|
||||
snprintf(&disk_filename[i], io_stream->m_Filename.length() - size_t(i), ".z%02u", number_disk + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= 0)
|
||||
ret = open(opaque, disk_filename, mode);
|
||||
|
||||
free(disk_filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
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;
|
||||
|
||||
mapping.zopen_file = (open_file_func)open;
|
||||
#ifdef _UNZ_H
|
||||
mapping.zopendisk_file = (opendisk_file_func)opendisk;
|
||||
#endif
|
||||
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 = testerror;
|
||||
|
||||
mapping.opaque = reinterpret_cast<voidpf>(pIOHandler);
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Info about a read-only file inside a ZIP
|
||||
class ZipFileInfo final {
|
||||
public:
|
||||
explicit ZipFileInfo(unzFile zip_handle, size_t size);
|
||||
~ZipFileInfo() = default;
|
||||
|
||||
// Allocate and Extract data from the ZIP
|
||||
ZipFile *Extract(std::string &filename, 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(std::string &filename, 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(filename, m_Size);
|
||||
|
||||
// Unzip has a limit of UINT16_MAX bytes buffer
|
||||
uint16_t unzipBufferSize = zip_file->m_Size <= UINT16_MAX ? static_cast<uint16_t>(zip_file->m_Size) : UINT16_MAX;
|
||||
std::unique_ptr<uint8_t[]> unzipBuffer = std::unique_ptr<uint8_t[]>(new uint8_t[unzipBufferSize]);
|
||||
size_t readCount = 0;
|
||||
while (readCount < zip_file->m_Size)
|
||||
{
|
||||
size_t bufferSize = zip_file->m_Size - readCount;
|
||||
if (bufferSize > UINT16_MAX) {
|
||||
bufferSize = UINT16_MAX;
|
||||
}
|
||||
|
||||
int ret = unzReadCurrentFile(zip_handle, unzipBuffer.get(), static_cast<unsigned int>(bufferSize));
|
||||
if (ret != static_cast<int>(bufferSize))
|
||||
{
|
||||
// Failed, release the memory
|
||||
delete zip_file;
|
||||
zip_file = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
std::memcpy(zip_file->m_Buffer.get() + readCount, unzipBuffer.get(), ret);
|
||||
readCount += ret;
|
||||
}
|
||||
|
||||
ai_assert(unzCloseCurrentFile(zip_handle) == UNZ_OK);
|
||||
return zip_file;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
ZipFile::ZipFile(std::string &filename, size_t size) :
|
||||
m_Filename(filename), m_Size(size) {
|
||||
ai_assert(m_Size != 0);
|
||||
m_Buffer = std::unique_ptr<uint8_t[]>(new uint8_t[m_Size]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
size_t ZipFile::Read(void *pvBuffer, size_t pSize, size_t pCount) {
|
||||
// Should be impossible
|
||||
ai_assert(m_Buffer != nullptr);
|
||||
ai_assert(nullptr != pvBuffer);
|
||||
ai_assert(0 != pSize);
|
||||
ai_assert(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 || nullptr == pMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
|
||||
m_ZipFileHandle = unzOpen2(pFilename, &mapping);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
ZipArchiveIOSystem::Implement::~Implement() {
|
||||
if (m_ZipFileHandle != nullptr) {
|
||||
unzClose(m_ZipFileHandle);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
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 && fileInfo.size_filename <= FileNameSize) {
|
||||
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(filename, 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());
|
||||
}
|
||||
|
||||
} // namespace Assimp
|
||||
196
assimp/code/Common/assbin_chunks.h
Normal file
196
assimp/code/Common/assbin_chunks.h
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/WriteDump.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
|
||||
112
assimp/code/Common/material.cpp
Normal file
112
assimp/code/Common/material.cpp
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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 material.cpp
|
||||
/** Implement common material related functions. */
|
||||
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/material.h>
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
const char *aiTextureTypeToString(aiTextureType in) {
|
||||
switch (in) {
|
||||
case aiTextureType_NONE:
|
||||
return "n/a";
|
||||
case aiTextureType_DIFFUSE:
|
||||
return "Diffuse";
|
||||
case aiTextureType_SPECULAR:
|
||||
return "Specular";
|
||||
case aiTextureType_AMBIENT:
|
||||
return "Ambient";
|
||||
case aiTextureType_EMISSIVE:
|
||||
return "Emissive";
|
||||
case aiTextureType_OPACITY:
|
||||
return "Opacity";
|
||||
case aiTextureType_NORMALS:
|
||||
return "Normals";
|
||||
case aiTextureType_HEIGHT:
|
||||
return "Height";
|
||||
case aiTextureType_SHININESS:
|
||||
return "Shininess";
|
||||
case aiTextureType_DISPLACEMENT:
|
||||
return "Displacement";
|
||||
case aiTextureType_LIGHTMAP:
|
||||
return "Lightmap";
|
||||
case aiTextureType_REFLECTION:
|
||||
return "Reflection";
|
||||
case aiTextureType_BASE_COLOR:
|
||||
return "BaseColor";
|
||||
case aiTextureType_NORMAL_CAMERA:
|
||||
return "NormalCamera";
|
||||
case aiTextureType_EMISSION_COLOR:
|
||||
return "EmissionColor";
|
||||
case aiTextureType_METALNESS:
|
||||
return "Metalness";
|
||||
case aiTextureType_DIFFUSE_ROUGHNESS:
|
||||
return "DiffuseRoughness";
|
||||
case aiTextureType_AMBIENT_OCCLUSION:
|
||||
return "AmbientOcclusion";
|
||||
case aiTextureType_SHEEN:
|
||||
return "Sheen";
|
||||
case aiTextureType_CLEARCOAT:
|
||||
return "Clearcoat";
|
||||
case aiTextureType_TRANSMISSION:
|
||||
return "Transmission";
|
||||
case aiTextureType_MAYA_BASE:
|
||||
return "MayaBase";
|
||||
case aiTextureType_MAYA_SPECULAR:
|
||||
return "MayaSpecular";
|
||||
case aiTextureType_MAYA_SPECULAR_COLOR:
|
||||
return "MayaSpecularColor";
|
||||
case aiTextureType_MAYA_SPECULAR_ROUGHNESS:
|
||||
return "MayaSpecularRoughness";
|
||||
case aiTextureType_ANISOTROPY:
|
||||
return "Anisotropy";
|
||||
case aiTextureType_GLTF_METALLIC_ROUGHNESS:
|
||||
return "glTFMetallicRoughness";
|
||||
case aiTextureType_UNKNOWN:
|
||||
return "Unknown";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ai_assert(false);
|
||||
return "BUG";
|
||||
}
|
||||
216
assimp/code/Common/scene.cpp
Normal file
216
assimp/code/Common/scene.cpp
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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>
|
||||
|
||||
#include "ScenePrivate.h"
|
||||
|
||||
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),
|
||||
mName(),
|
||||
mNumSkeletons(0),
|
||||
mSkeletons(nullptr),
|
||||
mPrivate(new Assimp::ScenePrivateData()) {
|
||||
// empty
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
delete[] mSkeletons;
|
||||
|
||||
delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
|
||||
}
|
||||
|
||||
aiNode::aiNode() :
|
||||
mName(""),
|
||||
mParent(nullptr),
|
||||
mNumChildren(0),
|
||||
mChildren(nullptr),
|
||||
mNumMeshes(0),
|
||||
mMeshes(nullptr),
|
||||
mMetaData(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
aiNode::aiNode(const std::string &name) :
|
||||
mName(name),
|
||||
mParent(nullptr),
|
||||
mNumChildren(0),
|
||||
mChildren(nullptr),
|
||||
mNumMeshes(0),
|
||||
mMeshes(nullptr),
|
||||
mMetaData(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
/** Destructor */
|
||||
aiNode::~aiNode() {
|
||||
// delete all children recursively
|
||||
// to make sure we won't crash if the data is invalid ...
|
||||
if (mNumChildren && mChildren) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
77
assimp/code/Common/simd.cpp
Normal file
77
assimp/code/Common/simd.cpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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
|
||||
51
assimp/code/Common/simd.h
Normal file
51
assimp/code/Common/simd.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2026, 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue