Fix empty mesh handling

kimkulling/allow_empty_meshes_issue-797
Kim Kulling 2023-11-09 22:28:15 +01:00
parent e673d1fd9e
commit 518c26ede6
9 changed files with 145 additions and 138 deletions

View File

@ -103,10 +103,6 @@ Discreet3DSImporter::Discreet3DSImporter() :
// empty // empty
} }
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
Discreet3DSImporter::~Discreet3DSImporter() = default;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {

View File

@ -59,7 +59,6 @@ struct aiNode;
namespace Assimp { namespace Assimp {
using namespace D3DS; using namespace D3DS;
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
@ -68,7 +67,7 @@ using namespace D3DS;
class Discreet3DSImporter : public BaseImporter { class Discreet3DSImporter : public BaseImporter {
public: public:
Discreet3DSImporter(); Discreet3DSImporter();
~Discreet3DSImporter() override; ~Discreet3DSImporter() override = default;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.

View File

@ -95,7 +95,7 @@ FBXImporter::FBXImporter() = default;
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool FBXImporter::CanRead(const std::string & pFile, IOSystem * pIOHandler, bool /*checkSig*/) const { bool FBXImporter::CanRead(const std::string & pFile, IOSystem * pIOHandler, bool /*checkSig*/) const {
// at least ASCII-FBX files usually have a 'FBX' somewhere in their head // at least ASCII-FBX files usually have a 'FBX' somewhere in their head
static const char *tokens[] = { "fbx" }; static const char *tokens[] = { " \n\r\n " };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens)); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
} }

View File

@ -100,13 +100,6 @@ bool IQMImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool c
if (!pIOHandler) { if (!pIOHandler) {
return true; return true;
} }
/*
* don't use CheckMagicToken because that checks with swapped bytes too, leading to false
* positives. This magic is not uint32_t, but char[4], so memcmp is the best way
const char* tokens[] = {"3DMO", "3dmo"};
return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4);
*/
std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb")); std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
unsigned char data[15]; unsigned char data[15];
if (!pStream || 15 != pStream->Read(data, 1, 15)) { if (!pStream || 15 != pStream->Read(data, 1, 15)) {

View File

@ -78,7 +78,9 @@ using namespace std;
ObjFileImporter::ObjFileImporter() : ObjFileImporter::ObjFileImporter() :
m_Buffer(), m_Buffer(),
m_pRootObject(nullptr), m_pRootObject(nullptr),
m_strAbsPath(std::string(1, DefaultIOSystem().getOsSeparator())) {} m_strAbsPath(std::string(1, DefaultIOSystem().getOsSeparator())) {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor. // Destructor.
@ -102,7 +104,7 @@ const aiImporterDesc *ObjFileImporter::GetInfo() const {
// Obj-file import implementation // Obj-file import implementation
void ObjFileImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) { void ObjFileImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) {
// Read file into memory // Read file into memory
static const std::string mode = "rb"; static constexpr char mode[] = "rb";
auto streamCloser = [&](IOStream *pStream) { auto streamCloser = [&](IOStream *pStream) {
pIOHandler->Close(pStream); pIOHandler->Close(pStream);
}; };

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2023, assimp team
All rights reserved. All rights reserved.
@ -56,62 +56,43 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory> #include <memory>
#include <utility> #include <utility>
//#include <cctype>
//#include <memory>
using namespace Assimp; namespace Assimp {
namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp static constexpr uint32_t ErrorId = ~0u;
template <> template <>
const char *LogFunctions<XGLImporter>::Prefix() { const char *LogFunctions<XGLImporter>::Prefix() {
return "XGL: "; return "XGL: ";
} }
} // namespace Assimp static constexpr aiImporterDesc desc = {
"XGL Importer", "", "", "",
static const aiImporterDesc desc = {
"XGL Importer",
"",
"",
"",
aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportCompressedFlavour, aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportCompressedFlavour,
0, 0, 0, 0, 0, "xgl zgl"};
0,
0,
0,
"xgl zgl"
};
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer XGLImporter::XGLImporter() : mXmlParser(nullptr), m_scene(nullptr) {
XGLImporter::XGLImporter() :
mXmlParser(nullptr),
m_scene(nullptr) {
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well
XGLImporter::~XGLImporter() { XGLImporter::~XGLImporter() {
delete mXmlParser; delete mXmlParser;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool XGLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { bool XGLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
static const char *tokens[] = { "<world>", "<World>", "<WORLD>" }; static const char *tokens[] = { "<world>", "<World>", "<WORLD>" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens)); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a list of all file extensions which are handled by this class
const aiImporterDesc *XGLImporter::GetInfo() const { const aiImporterDesc *XGLImporter::GetInfo() const {
return &desc; return &desc;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL #ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
std::vector<char> uncompressed; std::vector<char> uncompressed;
@ -159,7 +140,7 @@ void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
std::vector<aiMesh *> &meshes = scope.meshes_linear; std::vector<aiMesh *> &meshes = scope.meshes_linear;
std::vector<aiMaterial *> &materials = scope.materials_linear; std::vector<aiMaterial *> &materials = scope.materials_linear;
if (!meshes.size() || !materials.size()) { if (meshes.empty() || materials.empty()) {
ThrowException("failed to extract data from XGL file, no meshes loaded"); ThrowException("failed to extract data from XGL file, no meshes loaded");
} }
@ -199,9 +180,10 @@ void XGLImporter::ReadWorld(XmlNode &node, TempScope &scope) {
} }
aiNode *const nd = ReadObject(node, scope); aiNode *const nd = ReadObject(node, scope);
if (!nd) { if (nd == nullptr) {
ThrowException("failure reading <world>"); ThrowException("failure reading <world>");
} }
if (nd->mName.length == 0) { if (nd->mName.length == 0) {
nd->mName.Set("WORLD"); nd->mName.Set("WORLD");
} }
@ -254,15 +236,19 @@ aiNode *XGLImporter::ReadObject(XmlNode &node, TempScope &scope) {
const std::string &s = ai_stdStrToLower(child.name()); const std::string &s = ai_stdStrToLower(child.name());
if (s == "mesh") { if (s == "mesh") {
const size_t prev = scope.meshes_linear.size(); const size_t prev = scope.meshes_linear.size();
bool empty; if (ReadMesh(child, scope)) {
if (ReadMesh(child, scope, empty)) {
const size_t newc = scope.meshes_linear.size(); const size_t newc = scope.meshes_linear.size();
for (size_t i = 0; i < newc - prev; ++i) { for (size_t i = 0; i < newc - prev; ++i) {
meshes.push_back(static_cast<unsigned int>(i + prev)); meshes.push_back(static_cast<unsigned int>(i + prev));
} }
} else {
printf("skipping empty mesh\n");
} }
} else if (s == "mat") { } else if (s == "mat") {
ReadMaterial(child, scope); const uint32_t matId = ReadMaterial(child, scope);
if (matId == ErrorId) {
ThrowException("Invalid material id detected.");
}
} else if (s == "object") { } else if (s == "object") {
children.push_back(ReadObject(child, scope)); children.push_back(ReadObject(child, scope));
} else if (s == "objectref") { } else if (s == "objectref") {
@ -438,18 +424,25 @@ aiMesh *XGLImporter::ToOutputMesh(const TempMaterialMesh &m) {
return mesh.release(); return mesh.release();
} }
// ------------------------------------------------------------------------------------------------
bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope, bool &empty) {
TempMesh t;
// ------------------------------------------------------------------------------------------------
inline static unsigned int generateMeshId(unsigned int meshId, bool nor, bool uv) {
unsigned int currentMeshId = meshId | ((nor ? 1 : 0) << 31) | ((uv ? 1 : 0) << 30);
return currentMeshId;
}
// ------------------------------------------------------------------------------------------------
bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope) {
TempMesh t;
uint32_t matId = 99999;
bool mesh_created = false;
std::map<unsigned int, TempMaterialMesh> bymat; std::map<unsigned int, TempMaterialMesh> bymat;
const unsigned int mesh_id = ReadIDAttr(node); const unsigned int mesh_id = ReadIDAttr(node);
bool empty_mesh = true;
for (XmlNode &child : node.children()) { for (XmlNode &child : node.children()) {
const std::string &s = ai_stdStrToLower(child.name()); const std::string &s = ai_stdStrToLower(child.name());
if (s == "mat") { if (s == "mat") {
ReadMaterial(child, scope); matId = ReadMaterial(child, scope);
} else if (s == "p") { } else if (s == "p") {
pugi::xml_attribute attr = child.attribute("ID"); pugi::xml_attribute attr = child.attribute("ID");
if (attr.empty()) { if (attr.empty()) {
@ -477,9 +470,79 @@ bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope, bool &empty) {
} else if (s == "f" || s == "l" || s == "p") { } else if (s == "f" || s == "l" || s == "p") {
const unsigned int vcount = s == "f" ? 3 : (s == "l" ? 2 : 1); const unsigned int vcount = s == "f" ? 3 : (s == "l" ? 2 : 1);
unsigned int mid = ~0u; unsigned int meshId = ErrorId;
TempFace tf[3]; TempFace tempFace[3] = {};
bool has[3] = { false }; bool has[3] = { false };
meshId = ReadVertices(child, t, tempFace, has, meshId, scope);
if (meshId == ErrorId) {
ThrowException("missing material index");
}
bool nor = false, uv = false;
for (unsigned int i = 0; i < vcount; ++i) {
if (!has[i]) {
ThrowException("missing face vertex data");
}
nor = nor || tempFace[i].has_normal;
uv = uv || tempFace[i].has_uv;
}
if (meshId >= (1 << 30)) {
LogWarn("material indices exhausted, this may cause errors in the output");
}
const unsigned int currentMeshId = generateMeshId(meshId, nor, uv);
// Generate the temp mesh
TempMaterialMesh &mesh = bymat[currentMeshId];
mesh.matid = meshId;
mesh_created = true;
for (unsigned int i = 0; i < vcount; ++i) {
mesh.positions.push_back(tempFace[i].pos);
if (nor) {
mesh.normals.push_back(tempFace[i].normal);
}
if (uv) {
mesh.uvs.push_back(tempFace[i].uv);
}
mesh.pflags |= 1 << (vcount - 1);
}
mesh.vcounts.push_back(vcount);
}
}
if (!mesh_created) {
TempMaterialMesh &mesh = bymat[mesh_id];
mesh.matid = matId;
}
// finally extract output meshes and add them to the scope
AppendOutputMeshes(bymat, scope, mesh_id);
// no id == not a reference, insert this mesh right *here*
return mesh_id == ErrorId;
}
// ----------------------------------------------------------------------------------------------
void XGLImporter::AppendOutputMeshes(std::map<unsigned int, TempMaterialMesh> bymat, TempScope &scope,
const unsigned int mesh_id) {
using pairt = std::pair<const unsigned int, TempMaterialMesh>;
for (const pairt &p : bymat) {
aiMesh *const m = ToOutputMesh(p.second);
scope.meshes_linear.push_back(m);
// if this is a definition, keep it on the stack
if (mesh_id != ErrorId) {
scope.meshes.insert(std::pair<unsigned int, aiMesh *>(mesh_id, m));
}
}
}
// ----------------------------------------------------------------------------------------------
unsigned int XGLImporter::ReadVertices(XmlNode &child, TempMesh t, TempFace *tf, bool *has, unsigned int mid, TempScope &scope) {
for (XmlNode &sub_child : child.children()) { for (XmlNode &sub_child : child.children()) {
const std::string &scn = ai_stdStrToLower(sub_child.name()); const std::string &scn = ai_stdStrToLower(sub_child.name());
if (scn == "fv1" || scn == "lv1" || scn == "pv1") { if (scn == "fv1" || scn == "lv1" || scn == "pv1") {
@ -492,79 +555,18 @@ bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope, bool &empty) {
ReadFaceVertex(sub_child, t, tf[2]); ReadFaceVertex(sub_child, t, tf[2]);
has[2] = true; has[2] = true;
} else if (scn == "mat") { } else if (scn == "mat") {
if (mid != ~0u) { if (mid != ErrorId) {
LogWarn("only one material tag allowed per <f>"); LogWarn("only one material tag allowed per <f>");
} }
mid = ResolveMaterialRef(sub_child, scope); mid = ResolveMaterialRef(sub_child, scope);
} else if (scn == "matref") { } else if (scn == "matref") {
if (mid != ~0u) { if (mid != ErrorId) {
LogWarn("only one material tag allowed per <f>"); LogWarn("only one material tag allowed per <f>");
} }
mid = ResolveMaterialRef(sub_child, scope); mid = ResolveMaterialRef(sub_child, scope);
} }
} }
if (has[0] || has[1] || has[2]) { return mid;
empty_mesh = false;
}
if (mid == ~0u) {
ThrowException("missing material index");
}
bool nor = false;
bool uv = false;
for (unsigned int i = 0; i < vcount; ++i) {
if (!has[i]) {
ThrowException("missing face vertex data");
}
nor = nor || tf[i].has_normal;
uv = uv || tf[i].has_uv;
}
if (mid >= (1 << 30)) {
LogWarn("material indices exhausted, this may cause errors in the output");
}
unsigned int meshId = mid | ((nor ? 1 : 0) << 31) | ((uv ? 1 : 0) << 30);
TempMaterialMesh &mesh = bymat[meshId];
mesh.matid = mid;
for (unsigned int i = 0; i < vcount; ++i) {
mesh.positions.push_back(tf[i].pos);
if (nor) {
mesh.normals.push_back(tf[i].normal);
}
if (uv) {
mesh.uvs.push_back(tf[i].uv);
}
mesh.pflags |= 1 << (vcount - 1);
}
mesh.vcounts.push_back(vcount);
}
}
// finally extract output meshes and add them to the scope
using pairt = std::pair<const unsigned int, TempMaterialMesh>;
for (const pairt &p : bymat) {
aiMesh *const m = ToOutputMesh(p.second);
scope.meshes_linear.push_back(m);
// if this is a definition, keep it on the stack
if (mesh_id != ~0u) {
scope.meshes.insert(std::pair<unsigned int, aiMesh *>(mesh_id, m));
}
}
if (empty_mesh) {
LogWarn("Mesh is empty, skipping.");
empty = empty_mesh;
return false;
}
// no id == not a reference, insert this mesh right *here*
return mesh_id == ~0u;
} }
// ---------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------
@ -598,10 +600,10 @@ unsigned int XGLImporter::ResolveMaterialRef(XmlNode &node, TempScope &scope) {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void XGLImporter::ReadMaterial(XmlNode &node, TempScope &scope) { unsigned int XGLImporter::ReadMaterial(XmlNode &node, TempScope &scope) {
const unsigned int mat_id = ReadIDAttr(node); const unsigned int mat_id = ReadIDAttr(node);
auto *mat(new aiMaterial); auto *mat = new aiMaterial;
for (XmlNode &child : node.children()) { for (XmlNode &child : node.children()) {
const std::string &s = ai_stdStrToLower(child.name()); const std::string &s = ai_stdStrToLower(child.name());
if (s == "amb") { if (s == "amb") {
@ -627,6 +629,8 @@ void XGLImporter::ReadMaterial(XmlNode &node, TempScope &scope) {
scope.materials[mat_id] = mat; scope.materials[mat_id] = mat;
scope.materials_linear.push_back(mat); scope.materials_linear.push_back(mat);
return mat_id;
} }
// ---------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------
@ -683,7 +687,7 @@ unsigned int XGLImporter::ReadIDAttr(XmlNode &node) {
} }
} }
return ~0u; return ErrorId;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -712,14 +716,14 @@ unsigned int XGLImporter::ReadIndexFromText(XmlNode &node) {
const char *s = v.c_str(); const char *s = v.c_str();
if (!SkipSpaces(&s)) { if (!SkipSpaces(&s)) {
LogError("unexpected EOL, failed to parse index element"); LogError("unexpected EOL, failed to parse index element");
return ~0u; return ErrorId;
} }
const char *se; const char *se = nullptr;
const unsigned int t = strtoul10(s, &se); const unsigned int t = strtoul10(s, &se);
if (se == s) { if (se == s) {
LogError("failed to read index"); LogError("failed to read index");
return ~0u; return ErrorId;
} }
return t; return t;
@ -786,4 +790,6 @@ aiColor3D XGLImporter::ReadCol3(XmlNode &node) {
return aiColor3D(v.x, v.y, v.z); return aiColor3D(v.x, v.y, v.z);
} }
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_XGL_IMPORTER #endif // ASSIMP_BUILD_NO_XGL_IMPORTER

View File

@ -69,12 +69,14 @@ namespace Assimp {
*/ */
class XGLImporter : public BaseImporter, public LogFunctions<XGLImporter> { class XGLImporter : public BaseImporter, public LogFunctions<XGLImporter> {
public: public:
/// @brief The class constructor.
XGLImporter(); XGLImporter();
/// @brief The class destructor.
~XGLImporter() override; ~XGLImporter() override;
// ------------------------------------------------------------------- /// @brief Returns whether the class can handle the format of the given file.
/** Returns whether the class can handle the format of the given file. /// @see BaseImporter::CanRead() for details. */
* See BaseImporter::CanRead() for details. */
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
bool checkSig) const override; bool checkSig) const override;
@ -92,10 +94,7 @@ protected:
private: private:
struct TempScope { struct TempScope {
TempScope() : TempScope() : light() {}
light() {
// empty
}
~TempScope() { ~TempScope() {
for (aiMesh *m : meshes_linear) { for (aiMesh *m : meshes_linear) {
@ -145,9 +144,7 @@ private:
}; };
struct TempMaterialMesh { struct TempMaterialMesh {
TempMaterialMesh() : TempMaterialMesh() : pflags(), matid() {
pflags(),
matid() {
// empty // empty
} }
@ -160,9 +157,7 @@ private:
}; };
struct TempFace { struct TempFace {
TempFace() : TempFace() : has_uv(), has_normal() {
has_uv(),
has_normal() {
// empty // empty
} }
@ -175,26 +170,25 @@ private:
private: private:
void Cleanup(); void Cleanup();
std::string GetElementName(); std::string GetElementName();
bool ReadElement(); bool ReadElement();
bool ReadElementUpToClosing(const char *closetag); bool ReadElementUpToClosing(const char *closetag);
bool SkipToText(); bool SkipToText();
unsigned int ReadIDAttr(XmlNode &node); unsigned int ReadIDAttr(XmlNode &node);
void ReadWorld(XmlNode &node, TempScope &scope); void ReadWorld(XmlNode &node, TempScope &scope);
void ReadLighting(XmlNode &node, TempScope &scope); void ReadLighting(XmlNode &node, TempScope &scope);
aiLight *ReadDirectionalLight(XmlNode &node); aiLight *ReadDirectionalLight(XmlNode &node);
aiNode *ReadObject(XmlNode &node, TempScope &scope); aiNode *ReadObject(XmlNode &node, TempScope &scope);
bool ReadMesh(XmlNode &node, TempScope &scope, bool &empty); bool ReadMesh(XmlNode &node, TempScope &scope);
void ReadMaterial(XmlNode &node, TempScope &scope); void AppendOutputMeshes(std::map<unsigned int, TempMaterialMesh> bymat, TempScope &scope, const unsigned int mesh_id);
unsigned int ReadVertices(XmlNode &child, TempMesh t, TempFace *tf, bool *has, unsigned int mid, TempScope &scope);
unsigned int ReadMaterial(XmlNode &node, TempScope &scope);
aiVector2D ReadVec2(XmlNode &node); aiVector2D ReadVec2(XmlNode &node);
aiVector3D ReadVec3(XmlNode &node); aiVector3D ReadVec3(XmlNode &node);
aiColor3D ReadCol3(XmlNode &node); aiColor3D ReadCol3(XmlNode &node);
aiMatrix4x4 ReadTrafo(XmlNode &node); aiMatrix4x4 ReadTrafo(XmlNode &node);
unsigned int ReadIndexFromText(XmlNode &node); unsigned int ReadIndexFromText(XmlNode &node);
float ReadFloat(XmlNode &node); float ReadFloat(XmlNode &node);
aiMesh *ToOutputMesh(const TempMaterialMesh &m); aiMesh *ToOutputMesh(const TempMaterialMesh &m);
void ReadFaceVertex(XmlNode &node, const TempMesh &t, TempFace &out); void ReadFaceVertex(XmlNode &node, const TempMesh &t, TempFace &out);
unsigned int ResolveMaterialRef(XmlNode &node, TempScope &scope); unsigned int ResolveMaterialRef(XmlNode &node, TempScope &scope);

View File

@ -66,6 +66,10 @@ Compression::Compression() :
Compression::~Compression() { Compression::~Compression() {
ai_assert(mImpl != nullptr); ai_assert(mImpl != nullptr);
if (mImpl->mOpen) {
close();
}
delete mImpl; delete mImpl;
} }
@ -124,7 +128,7 @@ static int getFlushMode(Compression::FlushMode flush) {
return z_flush; return z_flush;
} }
constexpr size_t MYBLOCK = 32786; static constexpr size_t MYBLOCK = 32786;
size_t Compression::decompress(const void *data, size_t in, std::vector<char> &uncompressed) { size_t Compression::decompress(const void *data, size_t in, std::vector<char> &uncompressed) {
ai_assert(mImpl != nullptr); ai_assert(mImpl != nullptr);

View File

@ -40,6 +40,9 @@
# define crc32 z_crc32 # define crc32 z_crc32
# define crc32_combine z_crc32_combine # define crc32_combine z_crc32_combine
# define crc32_combine64 z_crc32_combine64 # define crc32_combine64 z_crc32_combine64
# define crc32_combine_gen z_crc32_combine_gen
# define crc32_combine_gen64 z_crc32_combine_gen64
# define crc32_combine_op z_crc32_combine_op
# define crc32_z z_crc32_z # define crc32_z z_crc32_z
# define deflate z_deflate # define deflate z_deflate
# define deflateBound z_deflateBound # define deflateBound z_deflateBound
@ -351,6 +354,9 @@
# ifdef FAR # ifdef FAR
# undef FAR # undef FAR
# endif # endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h> # include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */ /* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
@ -469,11 +475,18 @@ typedef uLong FAR uLongf;
# undef _LARGEFILE64_SOURCE # undef _LARGEFILE64_SOURCE
#endif #endif
#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) #ifndef Z_HAVE_UNISTD_H
# ifdef __WATCOMC__
# define Z_HAVE_UNISTD_H # define Z_HAVE_UNISTD_H
# endif # endif
#endif
#ifndef Z_HAVE_UNISTD_H
# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32)
# define Z_HAVE_UNISTD_H
# endif
#endif
#ifndef Z_SOLO #ifndef Z_SOLO
# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) # if defined(Z_HAVE_UNISTD_H)
# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
# ifdef VMS # ifdef VMS
# include <unixio.h> /* for off_t */ # include <unixio.h> /* for off_t */