Merge branch 'master' into warning-level-max

pull/2776/head
Kim Kulling 2019-12-03 21:57:04 +01:00 committed by GitHub
commit b10b8b2f1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 2523 additions and 1154 deletions

View File

@ -257,7 +257,7 @@ ELSEIF(MSVC)
IF(MSVC12) IF(MSVC12)
ADD_COMPILE_OPTIONS(/wd4351) ADD_COMPILE_OPTIONS(/wd4351)
ENDIF() ENDIF()
SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2 /Zi") SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2 /Zi /O0")
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
IF(NOT HUNTER_ENABLED) IF(NOT HUNTER_ENABLED)
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}") SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")

View File

@ -60,14 +60,19 @@ __Importers__:
- ENFF - ENFF
- [FBX](https://en.wikipedia.org/wiki/FBX) - [FBX](https://en.wikipedia.org/wiki/FBX)
- [glTF 1.0](https://en.wikipedia.org/wiki/GlTF#glTF_1.0) + GLB - [glTF 1.0](https://en.wikipedia.org/wiki/GlTF#glTF_1.0) + GLB
- [glTF 2.0](https://en.wikipedia.org/wiki/GlTF#glTF_2.0) - [glTF 2.0](https://en.wikipedia.org/wiki/GlTF#glTF_2.0):
At the moment for glTF2.0 the following extensions are supported:
+ KHR_lights_punctual ( 5.0 )
+ KHR_materials_pbrSpecularGlossiness ( 5.0 )
+ KHR_materials_unlit ( 5.0 )
+ KHR_texture_transform ( 5.1 under test )
- HMB - HMB
- IFC-STEP - IFC-STEP
- IRR / IRRMESH - IRR / IRRMESH
- [LWO](https://en.wikipedia.org/wiki/LightWave_3D) - [LWO](https://en.wikipedia.org/wiki/LightWave_3D)
- LWS - LWS
- LXO - LXO
- [M3D](https://gitlab.com/bztsrc/model3d) - [M3D](https://bztsrc.gitlab.io/model3d)
- MD2 - MD2
- MD3 - MD3
- MD5 - MD5

View File

@ -3234,13 +3234,12 @@ void ColladaParser::ReadScene()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception // Aborts the file reading with an exception
AI_WONT_RETURN void ColladaParser::ThrowException(const std::string& pError) const AI_WONT_RETURN void ColladaParser::ThrowException(const std::string& pError) const {
{
throw DeadlyImportError(format() << "Collada: " << mFileName << " - " << pError); throw DeadlyImportError(format() << "Collada: " << mFileName << " - " << pError);
} }
void ColladaParser::ReportWarning(const char* msg, ...)
{ void ColladaParser::ReportWarning(const char* msg, ...) {
ai_assert(NULL != msg); ai_assert(nullptr != msg);
va_list args; va_list args;
va_start(args, msg); va_start(args, msg);
@ -3255,11 +3254,11 @@ void ColladaParser::ReportWarning(const char* msg, ...)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Skips all data until the end node of the current element // Skips all data until the end node of the current element
void ColladaParser::SkipElement() void ColladaParser::SkipElement() {
{
// nothing to skip if it's an <element /> // nothing to skip if it's an <element />
if (mReader->isEmptyElement()) if (mReader->isEmptyElement()) {
return; return;
}
// reroute // reroute
SkipElement(mReader->getNodeName()); SkipElement(mReader->getNodeName());
@ -3267,63 +3266,75 @@ void ColladaParser::SkipElement()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Skips all data until the end node of the given element // Skips all data until the end node of the given element
void ColladaParser::SkipElement(const char* pElement) void ColladaParser::SkipElement(const char* pElement) {
{
// copy the current node's name because it'a pointer to the reader's internal buffer, // copy the current node's name because it'a pointer to the reader's internal buffer,
// which is going to change with the upcoming parsing // which is going to change with the upcoming parsing
std::string element = pElement; std::string element = pElement;
while (mReader->read()) while (mReader->read()) {
{ if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) if (mReader->getNodeName() == element) {
if (mReader->getNodeName() == element)
break; break;
}
}
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Tests for an opening element of the given name, throws an exception if not found // Tests for an opening element of the given name, throws an exception if not found
void ColladaParser::TestOpening(const char* pName) void ColladaParser::TestOpening(const char* pName) {
{
// read element start // read element start
if (!mReader->read()) if (!mReader->read()) {
ThrowException(format() << "Unexpected end of file while beginning of <" << pName << "> element."); ThrowException(format() << "Unexpected end of file while beginning of <" << pName << "> element.");
}
// whitespace in front is ok, just read again if found // whitespace in front is ok, just read again if found
if (mReader->getNodeType() == irr::io::EXN_TEXT) if (mReader->getNodeType() == irr::io::EXN_TEXT) {
if (!mReader->read()) if (!mReader->read()) {
ThrowException(format() << "Unexpected end of file while reading beginning of <" << pName << "> element."); ThrowException(format() << "Unexpected end of file while reading beginning of <" << pName << "> element.");
}
}
if (mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp(mReader->getNodeName(), pName) != 0) if (mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp(mReader->getNodeName(), pName) != 0) {
ThrowException(format() << "Expected start of <" << pName << "> element."); ThrowException(format() << "Expected start of <" << pName << "> element.");
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Tests for the closing tag of the given element, throws an exception if not found // Tests for the closing tag of the given element, throws an exception if not found
void ColladaParser::TestClosing(const char* pName) void ColladaParser::TestClosing(const char* pName) {
{ // check if we have an empty (self-closing) element
// check if we're already on the closing tag and return right away if (mReader->isEmptyElement()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp(mReader->getNodeName(), pName) == 0)
return; return;
}
// check if we're already on the closing tag and return right away
if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp(mReader->getNodeName(), pName) == 0) {
return;
}
// if not, read some more // if not, read some more
if (!mReader->read()) if (!mReader->read()) {
ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element."); ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element.");
}
// whitespace in front is ok, just read again if found // whitespace in front is ok, just read again if found
if (mReader->getNodeType() == irr::io::EXN_TEXT) if (mReader->getNodeType() == irr::io::EXN_TEXT) {
if (!mReader->read()) if (!mReader->read()) {
ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element."); ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element.");
}
}
// but this has the be the closing tag, or we're lost // but this has the be the closing tag, or we're lost
if (mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp(mReader->getNodeName(), pName) != 0) if (mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp(mReader->getNodeName(), pName) != 0) {
ThrowException(format() << "Expected end of <" << pName << "> element."); ThrowException(format() << "Expected end of <" << pName << "> element.");
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes // Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes
int ColladaParser::GetAttribute(const char* pAttr) const int ColladaParser::GetAttribute(const char* pAttr) const {
{
int index = TestAttribute(pAttr); int index = TestAttribute(pAttr);
if (index != -1) if (index != -1) {
return index; return index;
}
// attribute not found -> throw an exception // attribute not found -> throw an exception
ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">."); ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">.");

View File

@ -445,8 +445,7 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry. ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry.
ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties; ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties;
pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again); pProp->SetPropertyBool("bJoinIdenticalVertices", pp & aiProcess_JoinIdenticalVertices);
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
pimpl->mProgressHandler->UpdateFileWrite(4, 4); pimpl->mProgressHandler->UpdateFileWrite(4, 4);

View File

@ -493,7 +493,7 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
ReadFile(fbuff,pFlags); ReadFile(fbuff,pFlags);
SetIOHandler(io); SetIOHandler(io);
ASSIMP_END_EXCEPTION_REGION(const aiScene*); ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString);
return pimpl->mScene; return pimpl->mScene;
} }
@ -710,7 +710,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
// either successful or failure - the pointer expresses it anyways // either successful or failure - the pointer expresses it anyways
ASSIMP_END_EXCEPTION_REGION(const aiScene*); ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString);
return pimpl->mScene; return pimpl->mScene;
} }

View File

@ -66,6 +66,12 @@ ASSIMP_API const char* aiGetLegalString () {
return LEGAL_INFORMATION; return LEGAL_INFORMATION;
} }
// ------------------------------------------------------------------------------------------------
// Get Assimp patch version
ASSIMP_API unsigned int aiGetVersionPatch() {
return VER_PATCH;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get Assimp minor version // Get Assimp minor version
ASSIMP_API unsigned int aiGetVersionMinor () { ASSIMP_API unsigned int aiGetVersionMinor () {

View File

@ -1860,6 +1860,7 @@ void FBXExporter::WriteObjects ()
sdnode.AddChild("Version", int32_t(100)); sdnode.AddChild("Version", int32_t(100));
sdnode.AddChild("UserData", "", ""); sdnode.AddChild("UserData", "", "");
std::set<int32_t> setWeightedVertex;
// add indices and weights, if any // add indices and weights, if any
if (b) { if (b) {
std::vector<int32_t> subdef_indices; std::vector<int32_t> subdef_indices;
@ -1867,7 +1868,8 @@ void FBXExporter::WriteObjects ()
int32_t last_index = -1; int32_t last_index = -1;
for (size_t wi = 0; wi < b->mNumWeights; ++wi) { for (size_t wi = 0; wi < b->mNumWeights; ++wi) {
int32_t vi = vertex_indices[b->mWeights[wi].mVertexId]; int32_t vi = vertex_indices[b->mWeights[wi].mVertexId];
if (vi == last_index) { bool bIsWeightedAlready = (setWeightedVertex.find(vi) != setWeightedVertex.end());
if (vi == last_index || bIsWeightedAlready) {
// only for vertices we exported to fbx // only for vertices we exported to fbx
// TODO, FIXME: this assumes identically-located vertices // TODO, FIXME: this assumes identically-located vertices
// will always deform in the same way. // will always deform in the same way.
@ -1877,6 +1879,7 @@ void FBXExporter::WriteObjects ()
// identical vertex. // identical vertex.
continue; continue;
} }
setWeightedVertex.insert(vi);
subdef_indices.push_back(vi); subdef_indices.push_back(vi);
subdef_weights.push_back(b->mWeights[wi].mWeight); subdef_weights.push_back(b->mWeights[wi].mWeight);
last_index = vi; last_index = vi;

View File

@ -169,6 +169,33 @@ void M3DExporter::doExport (
outfile.reset(); outfile.reset();
} }
// ------------------------------------------------------------------------------------------------
// helper to add a vertex (private to NodeWalk)
m3dv_t *M3DExporter::AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx)
{
if(v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0;
if(v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0;
if(v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0;
if(v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0;
vrtx = (m3dv_t*)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t));
memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t));
*idx = *numvrtx;
(*numvrtx)++;
return vrtx;
}
// ------------------------------------------------------------------------------------------------
// helper to add a tmap (private to NodeWalk)
m3dti_t *M3DExporter::AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx)
{
tmap = (m3dti_t*)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t));
memcpy(&tmap[*numtmap], ti, sizeof(m3dti_t));
*idx = *numtmap;
(*numtmap)++;
return tmap;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// recursive node walker // recursive node walker
void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m) void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
@ -221,25 +248,23 @@ void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
if(mesh->HasVertexColors(0)) if(mesh->HasVertexColors(0))
vertex.color = mkColor(&mesh->mColors[0][l]); vertex.color = mkColor(&mesh->mColors[0][l]);
// save the vertex to the output // save the vertex to the output
m3d->vertex = _m3d_addvrtx(m3d->vertex, &m3d->numvertex, m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex,
&vertex, &idx); &vertex, &idx);
m3d->face[n].vertex[k] = (M3D_INDEX)idx; m3d->face[n].vertex[k] = (M3D_INDEX)idx;
// do we have texture coordinates? // do we have texture coordinates?
if(mesh->HasTextureCoords(0)) { if(mesh->HasTextureCoords(0)) {
ti.u = mesh->mTextureCoords[0][l].x; ti.u = mesh->mTextureCoords[0][l].x;
ti.v = mesh->mTextureCoords[0][l].y; ti.v = mesh->mTextureCoords[0][l].y;
m3d->tmap = _m3d_addtmap(m3d->tmap, &m3d->numtmap, &ti, m3d->tmap = AddTmap(m3d->tmap, &m3d->numtmap, &ti, &idx);
&idx);
m3d->face[n].texcoord[k] = (M3D_INDEX)idx; m3d->face[n].texcoord[k] = (M3D_INDEX)idx;
} }
// do we have normal vectors? // do we have normal vectors?
if(mesh->HasNormals()) { if(mesh->HasNormals()) {
vertex.color = 0;
vertex.x = mesh->mNormals[l].x; vertex.x = mesh->mNormals[l].x;
vertex.y = mesh->mNormals[l].y; vertex.y = mesh->mNormals[l].y;
vertex.z = mesh->mNormals[l].z; vertex.z = mesh->mNormals[l].z;
m3d->vertex = _m3d_addnorm(m3d->vertex, &m3d->numvertex, vertex.color = 0;
&vertex, &idx); m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex, &vertex, &idx);
m3d->face[n].normal[k] = (M3D_INDEX)idx; m3d->face[n].normal[k] = (M3D_INDEX)idx;
} }
} }

View File

@ -87,6 +87,8 @@ namespace Assimp
// helper to do the recursive walking // helper to do the recursive walking
void NodeWalk(const aiNode* pNode, aiMatrix4x4 m); void NodeWalk(const aiNode* pNode, aiMatrix4x4 m);
m3dv_t *AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx);
m3dti_t *AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx);
uint32_t mkColor(aiColor4D* c); uint32_t mkColor(aiColor4D* c);
M3D_INDEX addMaterial(const aiMaterial *mat); M3D_INDEX addMaterial(const aiMaterial *mat);
void addProp(m3dm_t *m, uint8_t type, uint32_t value); void addProp(m3dm_t *m, uint8_t type, uint32_t value);

View File

@ -44,6 +44,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define M3D_IMPLEMENTATION #define M3D_IMPLEMENTATION
#define M3D_ASCII #define M3D_ASCII
#define M3D_NONORMALS /* leave the post-processing to Assimp */
#define M3D_NOWEIGHTS
#define M3D_NOANIMATION
#include <assimp/IOStreamBuffer.h> #include <assimp/IOStreamBuffer.h>
#include <memory> #include <memory>
@ -104,16 +107,21 @@ extern "C" {
std::string file(fn); std::string file(fn);
std::unique_ptr<Assimp::IOStream> pStream( std::unique_ptr<Assimp::IOStream> pStream(
(reinterpret_cast<Assimp::IOSystem*>(m3dimporter_pIOHandler))->Open( file, "rb")); (reinterpret_cast<Assimp::IOSystem*>(m3dimporter_pIOHandler))->Open( file, "rb"));
size_t fileSize = pStream->FileSize(); size_t fileSize = 0;
// should be allocated with malloc(), because the library will call free() to deallocate unsigned char *data = NULL;
unsigned char *data = (unsigned char*)malloc(fileSize); // sometimes pStream is nullptr for some reason (should be an empty object returning nothing I guess)
if( !data || !pStream.get() || !fileSize || fileSize != pStream->Read(data,1,fileSize)) { if(pStream) {
fileSize = pStream->FileSize();
// should be allocated with malloc(), because the library will call free() to deallocate
data = (unsigned char*)malloc(fileSize);
if( !data || !pStream.get() || !fileSize || fileSize != pStream->Read(data,1,fileSize)) {
pStream.reset();
*size = 0;
// don't throw a deadly exception, it's not fatal if we can't read an external asset
return nullptr;
}
pStream.reset(); pStream.reset();
*size = 0;
// don't throw a deadly exception, it's not fatal if we can't read an external asset
return nullptr;
} }
pStream.reset();
*size = (int)fileSize; *size = (int)fileSize;
return data; return data;
} }
@ -307,7 +315,7 @@ void M3DImporter::importMaterials()
m->prop[j].value.textureid < m3d->numtexture && m->prop[j].value.textureid < m3d->numtexture &&
m3d->texture[m->prop[j].value.textureid].name) { m3d->texture[m->prop[j].value.textureid].name) {
name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png")); name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png"));
mat->AddProperty(&name, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); mat->AddProperty(&name, aiTxProps[k].pKey, aiTxProps[k].type, aiTxProps[k].index);
n = 0; n = 0;
mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index); mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index);
} }
@ -321,6 +329,7 @@ void M3DImporter::importMaterials()
void M3DImporter::importTextures() void M3DImporter::importTextures()
{ {
unsigned int i; unsigned int i;
const char *formatHint[] = { "rgba0800", "rgba0808", "rgba8880", "rgba8888" };
m3dtx_t *t; m3dtx_t *t;
ai_assert(mScene != nullptr); ai_assert(mScene != nullptr);
@ -334,14 +343,29 @@ void M3DImporter::importTextures()
mScene->mTextures = new aiTexture*[m3d->numtexture]; mScene->mTextures = new aiTexture*[m3d->numtexture];
for(i = 0; i < m3d->numtexture; i++) { for(i = 0; i < m3d->numtexture; i++) {
unsigned int j, k;
t = &m3d->texture[i]; t = &m3d->texture[i];
if(!t->w || !t->h || !t->f || !t->d) continue;
aiTexture *tx = new aiTexture; aiTexture *tx = new aiTexture;
strcpy(tx->achFormatHint, "rgba8888"); strcpy(tx->achFormatHint, formatHint[t->f - 1]);
tx->mFilename = aiString(std::string(t->name) + ".png"); tx->mFilename = aiString(std::string(t->name) + ".png");
tx->mWidth = t->w; tx->mWidth = t->w;
tx->mHeight = t->h; tx->mHeight = t->h;
tx->pcData = new aiTexel[ tx->mWidth*tx->mHeight ]; tx->pcData = new aiTexel[ tx->mWidth*tx->mHeight ];
memcpy(tx->pcData, t->d, tx->mWidth*tx->mHeight*4); for(j = k = 0; j < tx->mWidth*tx->mHeight; j++) {
switch(t->f) {
case 1: tx->pcData[j].g = t->d[k++]; break;
case 2: tx->pcData[j].g = t->d[k++]; tx->pcData[j].a = t->d[k++]; break;
case 3:
tx->pcData[j].r = t->d[k++]; tx->pcData[j].g = t->d[k++];
tx->pcData[j].b = t->d[k++]; tx->pcData[j].a = 255;
break;
case 4:
tx->pcData[j].r = t->d[k++]; tx->pcData[j].g = t->d[k++];
tx->pcData[j].b = t->d[k++]; tx->pcData[j].a = t->d[k++];
break;
}
}
mScene->mTextures[i] = tx; mScene->mTextures[i] = tx;
} }
} }
@ -372,9 +396,14 @@ void M3DImporter::importMeshes()
// we must switch mesh if material changes // we must switch mesh if material changes
if(lastMat != m3d->face[i].materialid) { if(lastMat != m3d->face[i].materialid) {
lastMat = m3d->face[i].materialid; lastMat = m3d->face[i].materialid;
if(pMesh && vertices->size() && faces->size()) { if(pMesh && vertices && vertices->size() && faces && faces->size()) {
populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids); populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids);
meshes->push_back(pMesh); meshes->push_back(pMesh);
delete faces;
delete vertices;
delete normals;
delete texcoords;
delete colors;
delete vertexids; // this is not stored in pMesh, just to collect bone vertices delete vertexids; // this is not stored in pMesh, just to collect bone vertices
} }
pMesh = new aiMesh; pMesh = new aiMesh;
@ -574,15 +603,15 @@ void M3DImporter::convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int o
m->a2 = m->a3 = m->b1 = m->b3 = m->c1 = m->c2 = 0.0; m->a2 = m->a3 = m->b1 = m->b3 = m->c1 = m->c2 = 0.0;
m->a1 = m->b2 = m->c3 = -1.0; m->a1 = m->b2 = m->c3 = -1.0;
} else { } else {
m->a1 = 1 - 2 * (q->y * q->y + q->z * q->z); if(m->a1 > -1e-7 && m->a1 < 1e-7) m->a1 = 0.0; m->a1 = 1 - 2 * (q->y * q->y + q->z * q->z); if(m->a1 > -M3D_EPSILON && m->a1 < M3D_EPSILON) m->a1 = 0.0;
m->a2 = 2 * (q->x * q->y - q->z * q->w); if(m->a2 > -1e-7 && m->a2 < 1e-7) m->a2 = 0.0; m->a2 = 2 * (q->x * q->y - q->z * q->w); if(m->a2 > -M3D_EPSILON && m->a2 < M3D_EPSILON) m->a2 = 0.0;
m->a3 = 2 * (q->x * q->z + q->y * q->w); if(m->a3 > -1e-7 && m->a3 < 1e-7) m->a3 = 0.0; m->a3 = 2 * (q->x * q->z + q->y * q->w); if(m->a3 > -M3D_EPSILON && m->a3 < M3D_EPSILON) m->a3 = 0.0;
m->b1 = 2 * (q->x * q->y + q->z * q->w); if(m->b1 > -1e-7 && m->b1 < 1e-7) m->b1 = 0.0; m->b1 = 2 * (q->x * q->y + q->z * q->w); if(m->b1 > -M3D_EPSILON && m->b1 < M3D_EPSILON) m->b1 = 0.0;
m->b2 = 1 - 2 * (q->x * q->x + q->z * q->z); if(m->b2 > -1e-7 && m->b2 < 1e-7) m->b2 = 0.0; m->b2 = 1 - 2 * (q->x * q->x + q->z * q->z); if(m->b2 > -M3D_EPSILON && m->b2 < M3D_EPSILON) m->b2 = 0.0;
m->b3 = 2 * (q->y * q->z - q->x * q->w); if(m->b3 > -1e-7 && m->b3 < 1e-7) m->b3 = 0.0; m->b3 = 2 * (q->y * q->z - q->x * q->w); if(m->b3 > -M3D_EPSILON && m->b3 < M3D_EPSILON) m->b3 = 0.0;
m->c1 = 2 * (q->x * q->z - q->y * q->w); if(m->c1 > -1e-7 && m->c1 < 1e-7) m->c1 = 0.0; m->c1 = 2 * (q->x * q->z - q->y * q->w); if(m->c1 > -M3D_EPSILON && m->c1 < M3D_EPSILON) m->c1 = 0.0;
m->c2 = 2 * (q->y * q->z + q->x * q->w); if(m->c2 > -1e-7 && m->c2 < 1e-7) m->c2 = 0.0; m->c2 = 2 * (q->y * q->z + q->x * q->w); if(m->c2 > -M3D_EPSILON && m->c2 < M3D_EPSILON) m->c2 = 0.0;
m->c3 = 1 - 2 * (q->x * q->x + q->y * q->y); if(m->c3 > -1e-7 && m->c3 < 1e-7) m->c3 = 0.0; m->c3 = 1 - 2 * (q->x * q->x + q->y * q->y); if(m->c3 > -M3D_EPSILON && m->c3 < M3D_EPSILON) m->c3 = 0.0;
} }
/* set translation */ /* set translation */

View File

@ -75,7 +75,7 @@ static const aiMatProp aiProps[] = {
{ AI_MATKEY_REFLECTIVITY }, /* m3dp_Pm */ { AI_MATKEY_REFLECTIVITY }, /* m3dp_Pm */
{ NULL, 0, 0 }, /* m3dp_Ps */ { NULL, 0, 0 }, /* m3dp_Ps */
{ AI_MATKEY_REFRACTI }, /* m3dp_Ni */ { AI_MATKEY_REFRACTI }, /* m3dp_Ni */
{ NULL, 0, 0 }, { NULL, 0, 0 }, /* m3dp_Nt */
{ NULL, 0, 0 }, { NULL, 0, 0 },
{ NULL, 0, 0 }, { NULL, 0, 0 },
{ NULL, 0, 0 } { NULL, 0, 0 }
@ -97,7 +97,7 @@ static const aiMatProp aiTxProps[] = {
{ AI_MATKEY_TEXTURE(aiTextureType_METALNESS,0) }, /* m3dp_map_Pm */ { AI_MATKEY_TEXTURE(aiTextureType_METALNESS,0) }, /* m3dp_map_Pm */
{ NULL, 0, 0 }, /* m3dp_map_Ps */ { NULL, 0, 0 }, /* m3dp_map_Ps */
{ AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION,0) },/* m3dp_map_Ni */ { AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION,0) },/* m3dp_map_Ni */
{ NULL, 0, 0 }, { NULL, 0, 0 }, /* m3dp_map_Nt */
{ NULL, 0, 0 }, { NULL, 0, 0 },
{ NULL, 0, 0 }, { NULL, 0, 0 },
{ NULL, 0, 0 } { NULL, 0, 0 }

File diff suppressed because it is too large Load Diff

View File

@ -273,14 +273,14 @@ aiReturn aiGetMaterialColor(const aiMaterial* pMat,
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a aiUVTransform (4 floats) from the material // Get a aiUVTransform (5 floats) from the material
aiReturn aiGetMaterialUVTransform(const aiMaterial* pMat, aiReturn aiGetMaterialUVTransform(const aiMaterial* pMat,
const char* pKey, const char* pKey,
unsigned int type, unsigned int type,
unsigned int index, unsigned int index,
aiUVTransform* pOut) aiUVTransform* pOut)
{ {
unsigned int iMax = 4; unsigned int iMax = 5;
return aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax); return aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax);
} }

View File

@ -1034,6 +1034,12 @@ namespace glTF2
bool KHR_texture_transform; bool KHR_texture_transform;
} extensionsUsed; } extensionsUsed;
//! Keeps info about the required extensions
struct RequiredExtensions
{
bool KHR_draco_mesh_compression;
} extensionsRequired;
AssetMetadata asset; AssetMetadata asset;
@ -1076,6 +1082,7 @@ namespace glTF2
, textures (*this, "textures") , textures (*this, "textures")
{ {
memset(&extensionsUsed, 0, sizeof(extensionsUsed)); memset(&extensionsUsed, 0, sizeof(extensionsUsed));
memset(&extensionsRequired, 0, sizeof(extensionsRequired));
} }
//! Main function //! Main function
@ -1094,6 +1101,7 @@ namespace glTF2
void ReadBinaryHeader(IOStream& stream, std::vector<char>& sceneData); void ReadBinaryHeader(IOStream& stream, std::vector<char>& sceneData);
void ReadExtensionsUsed(Document& doc); void ReadExtensionsUsed(Document& doc);
void ReadExtensionsRequired(Document& doc);
IOStream* OpenFile(std::string path, const char* mode, bool absolute = false); IOStream* OpenFile(std::string path, const char* mode, bool absolute = false);
}; };

View File

@ -270,13 +270,14 @@ Ref<T> LazyDict<T>::Retrieve(unsigned int i)
throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" is not a JSON object"); throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" is not a JSON object");
} }
T* inst = new T(); // Unique ptr prevents memory leak in case of Read throws an exception
auto inst = std::unique_ptr<T>(new T());
inst->id = std::string(mDictId) + "_" + to_string(i); inst->id = std::string(mDictId) + "_" + to_string(i);
inst->oIndex = i; inst->oIndex = i;
ReadMember(obj, "name", inst->name); ReadMember(obj, "name", inst->name);
inst->Read(obj, mAsset); inst->Read(obj, mAsset);
return Add(inst); return Add(inst.release());
} }
template<class T> template<class T>
@ -1432,6 +1433,12 @@ inline void Asset::Load(const std::string& pFile, bool isBinary)
// Load the metadata // Load the metadata
asset.Read(doc); asset.Read(doc);
ReadExtensionsUsed(doc); ReadExtensionsUsed(doc);
ReadExtensionsRequired(doc);
// Currently Draco is not supported
if (extensionsRequired.KHR_draco_mesh_compression) {
throw DeadlyImportError("GLTF: Draco mesh compression not currently supported.");
}
// Prepare the dictionaries // Prepare the dictionaries
for (size_t i = 0; i < mDicts.size(); ++i) { for (size_t i = 0; i < mDicts.size(); ++i) {
@ -1478,6 +1485,29 @@ inline void Asset::SetAsBinary()
} }
} }
// As required extensions are only a concept in glTF 2.0, this is here
// instead of glTFCommon.h
#define CHECK_REQUIRED_EXT(EXT) \
if (exts.find(#EXT) != exts.end()) extensionsRequired.EXT = true;
inline void Asset::ReadExtensionsRequired(Document& doc)
{
Value* extsRequired = FindArray(doc, "extensionsRequired");
if (nullptr == extsRequired) {
return;
}
std::gltf_unordered_map<std::string, bool> exts;
for (unsigned int i = 0; i < extsRequired->Size(); ++i) {
if ((*extsRequired)[i].IsString()) {
exts[(*extsRequired)[i].GetString()] = true;
}
}
CHECK_REQUIRED_EXT(KHR_draco_mesh_compression);
#undef CHECK_REQUIRED_EXT
}
inline void Asset::ReadExtensionsUsed(Document& doc) inline void Asset::ReadExtensionsUsed(Document& doc)
{ {

View File

@ -204,11 +204,21 @@ inline void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset
if (prop.textureTransformSupported) { if (prop.textureTransformSupported) {
aiUVTransform transform; aiUVTransform transform;
transform.mTranslation.x = prop.TextureTransformExt_t.offset[0];
transform.mTranslation.y = prop.TextureTransformExt_t.offset[0];
transform.mRotation = prop.TextureTransformExt_t.rotation;
transform.mScaling.x = prop.TextureTransformExt_t.scale[0]; transform.mScaling.x = prop.TextureTransformExt_t.scale[0];
transform.mScaling.y = prop.TextureTransformExt_t.scale[1]; transform.mScaling.y = prop.TextureTransformExt_t.scale[1];
transform.mRotation = -prop.TextureTransformExt_t.rotation; // must be negated
// A change of coordinates is required to map glTF UV transformations into the space used by
// Assimp. In glTF all UV origins are at 0,1 (top left of texture) in Assimp space. In Assimp
// rotation occurs around the image center (0.5,0.5) where as in glTF rotation is around the
// texture origin. All three can be corrected for solely by a change of the translation since
// the transformations available are shape preserving. Note the importer already flips the V
// coordinate of the actual meshes during import.
const ai_real rcos(cos(-transform.mRotation));
const ai_real rsin(sin(-transform.mRotation));
transform.mTranslation.x = (0.5 * transform.mScaling.x) * (-rcos + rsin + 1) + prop.TextureTransformExt_t.offset[0];
transform.mTranslation.y = ((0.5 * transform.mScaling.y) * (rsin + rcos - 1)) + 1 - transform.mScaling.y - prop.TextureTransformExt_t.offset[1];;
mat->AddProperty(&transform, 1, _AI_MATKEY_UVTRANSFORM_BASE, texType, texSlot); mat->AddProperty(&transform, 1, _AI_MATKEY_UVTRANSFORM_BASE, texType, texSlot);
} }

View File

@ -119,6 +119,16 @@ struct ExceptionSwallower<void> {
{\ {\
try { try {
#define ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(type, ASSIMP_END_EXCEPTION_REGION_errorString)\
} catch(const DeadlyImportError& e) {\
ASSIMP_END_EXCEPTION_REGION_errorString = e.what();\
return ExceptionSwallower<type>()();\
} catch(...) {\
ASSIMP_END_EXCEPTION_REGION_errorString = "Unknown exception";\
return ExceptionSwallower<type>()();\
}\
}
#define ASSIMP_END_EXCEPTION_REGION(type)\ #define ASSIMP_END_EXCEPTION_REGION(type)\
} catch(...) {\ } catch(...) {\
return ExceptionSwallower<type>()();\ return ExceptionSwallower<type>()();\

View File

@ -62,6 +62,13 @@ extern "C" {
*/ */
ASSIMP_API const char* aiGetLegalString (void); ASSIMP_API const char* aiGetLegalString (void);
// ---------------------------------------------------------------------------
/** @brief Returns the current patch version number of Assimp.
* @return Patch version of the Assimp runtime the application was
* linked/built against
*/
ASSIMP_API unsigned int aiGetVersionPatch(void);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Returns the current minor version number of Assimp. /** @brief Returns the current minor version number of Assimp.
* @return Minor version of the Assimp runtime the application was * @return Minor version of the Assimp runtime the application was

View File

@ -0,0 +1,181 @@
{
"asset": {
"generator": "COLLADA2GLTF",
"version": "2.0"
},
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"nodes": [
{
"children": [
1
],
"matrix": [
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
-1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0
]
},
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 1,
"POSITION": 2,
"TEXCOORD_0": 3
},
"indices": 0,
"mode": 4,
"material": 0
}
],
"name": "Mesh"
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 36,
"max": [
23
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"max": [
1.0,
1.0,
1.0
],
"min": [
-1.0,
-1.0,
-1.0
],
"type": "VEC3"
},
{
"bufferView": 1,
"byteOffset": 288,
"componentType": 5126,
"count": 24,
"max": [
0.5,
0.5,
0.5
],
"min": [
-0.5,
-0.5,
-0.5
],
"type": "VEC3"
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"max": [
6.0,
1.0
],
"min": [
0.0,
0.0
],
"type": "VEC2"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicFactor": 0.0
},
"name": "Texture"
}
],
"textures": [
{
"sampler": 0,
"source": 0
}
],
"images": [
{
"uri": "CesiumLogoFlat.png"
}
],
"samplers": [
{
"magFilter": 9729,
"minFilter": 9986,
"wrapS": 33648,
"wrapT": 33071
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 768,
"byteLength": 72,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 576,
"byteStride": 12,
"target": 34962
},
{
"buffer": 0,
"byteOffset": 576,
"byteLength": 192,
"byteStride": 8,
"target": 34962
}
],
"buffers": [
{
"byteLength": 840,
"uri": "BoxTextured0.bin"
}
]
}

View File

@ -54,7 +54,7 @@ class utM3DImportExport : public AbstractImportExportBase {
public: public:
virtual bool importerTest() { virtual bool importerTest() {
Assimp::Importer importer; Assimp::Importer importer;
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/M3D/WusonBlitz0.m3d", aiProcess_ValidateDataStructure ); const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/M3D/cube_normals.m3d", aiProcess_ValidateDataStructure );
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
return nullptr != scene; return nullptr != scene;
#else #else

View File

@ -426,4 +426,13 @@ TEST_F( utglTF2ImportExport, crash_in_anim_mesh_destructor ) {
ASSERT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube_out.glTF")); ASSERT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube_out.glTF"));
} }
TEST_F(utglTF2ImportExport, error_string_preserved) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/MissingBin/BoxTextured.gltf",
aiProcess_ValidateDataStructure);
ASSERT_EQ(nullptr, scene);
std::string error = importer.GetErrorString();
ASSERT_NE(error.find("BoxTextured0.bin"), std::string::npos) << "Error string should contain an error about missing .bin file";
}
#endif // ASSIMP_BUILD_NO_EXPORT #endif // ASSIMP_BUILD_NO_EXPORT