diff --git a/.gitignore b/.gitignore
index 65a54aaeb..e975976bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
build
.project
*.kdev4*
+.DS_Store
# build artefacts
*.o
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 693d6f16a..4caaaf4a4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -253,7 +253,7 @@ ELSEIF(MSVC)
IF(MSVC12)
ADD_COMPILE_OPTIONS(/wd4351)
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" )
IF(NOT HUNTER_ENABLED)
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")
diff --git a/Readme.md b/Readme.md
index f02a3b617..863e64f08 100644
--- a/Readme.md
+++ b/Readme.md
@@ -60,14 +60,19 @@ __Importers__:
- ENFF
- [FBX](https://en.wikipedia.org/wiki/FBX)
- [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
- IFC-STEP
- IRR / IRRMESH
- [LWO](https://en.wikipedia.org/wiki/LightWave_3D)
- LWS
- LXO
-- [M3D](https://gitlab.com/bztsrc/model3d)
+- [M3D](https://bztsrc.gitlab.io/model3d)
- MD2
- MD3
- MD5
diff --git a/code/Collada/ColladaParser.cpp b/code/Collada/ColladaParser.cpp
index 1a7b96189..e2e6626c3 100644
--- a/code/Collada/ColladaParser.cpp
+++ b/code/Collada/ColladaParser.cpp
@@ -3234,13 +3234,12 @@ void ColladaParser::ReadScene()
// ------------------------------------------------------------------------------------------------
// 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);
}
-void ColladaParser::ReportWarning(const char* msg, ...)
-{
- ai_assert(NULL != msg);
+
+void ColladaParser::ReportWarning(const char* msg, ...) {
+ ai_assert(nullptr != msg);
va_list args;
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
-void ColladaParser::SkipElement()
-{
+void ColladaParser::SkipElement() {
// nothing to skip if it's an
- if (mReader->isEmptyElement())
+ if (mReader->isEmptyElement()) {
return;
+ }
// reroute
SkipElement(mReader->getNodeName());
@@ -3267,63 +3266,75 @@ void ColladaParser::SkipElement()
// ------------------------------------------------------------------------------------------------
// 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,
// which is going to change with the upcoming parsing
std::string element = pElement;
- while (mReader->read())
- {
- if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
- if (mReader->getNodeName() == element)
+ while (mReader->read()) {
+ if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
+ if (mReader->getNodeName() == element) {
break;
+ }
+ }
}
}
// ------------------------------------------------------------------------------------------------
// 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
- if (!mReader->read())
+ if (!mReader->read()) {
ThrowException(format() << "Unexpected end of file while beginning of <" << pName << "> element.");
+ }
// whitespace in front is ok, just read again if found
- if (mReader->getNodeType() == irr::io::EXN_TEXT)
- if (!mReader->read())
+ if (mReader->getNodeType() == irr::io::EXN_TEXT) {
+ if (!mReader->read()) {
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.");
+ }
}
// ------------------------------------------------------------------------------------------------
// Tests for the closing tag of the given element, throws an exception if not found
-void ColladaParser::TestClosing(const char* pName)
-{
- // 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)
+void ColladaParser::TestClosing(const char* pName) {
+ // check if we have an empty (self-closing) element
+ if (mReader->isEmptyElement()) {
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 (!mReader->read())
+ if (!mReader->read()) {
ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element.");
+ }
// whitespace in front is ok, just read again if found
- if (mReader->getNodeType() == irr::io::EXN_TEXT)
- if (!mReader->read())
+ if (mReader->getNodeType() == irr::io::EXN_TEXT) {
+ if (!mReader->read()) {
ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element.");
+ }
+ }
// 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.");
+ }
}
// ------------------------------------------------------------------------------------------------
// 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);
- if (index != -1)
+ if (index != -1) {
return index;
+ }
// attribute not found -> throw an exception
ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">.");
diff --git a/code/Common/DefaultLogger.cpp b/code/Common/DefaultLogger.cpp
index de3528d2b..eee53bd7c 100644
--- a/code/Common/DefaultLogger.cpp
+++ b/code/Common/DefaultLogger.cpp
@@ -107,7 +107,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
return nullptr;
#endif
- // Platform-independent default streams
+ // Platform-independent default streams
case aiDefaultLogStream_STDERR:
return new StdOStreamLogStream(std::cerr);
case aiDefaultLogStream_STDOUT:
@@ -121,7 +121,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
};
// For compilers without dead code path detection
- return NULL;
+ return nullptr;
}
// ----------------------------------------------------------------------------------
diff --git a/code/Common/Exporter.cpp b/code/Common/Exporter.cpp
index 8a95ceae5..b9bd0409b 100644
--- a/code/Common/Exporter.cpp
+++ b/code/Common/Exporter.cpp
@@ -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* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties;
- pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again);
- exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
+ pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again);
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
pimpl->mProgressHandler->UpdateFileWrite(4, 4);
diff --git a/code/Common/Version.cpp b/code/Common/Version.cpp
index cf1da7d5b..ea4c996f0 100644
--- a/code/Common/Version.cpp
+++ b/code/Common/Version.cpp
@@ -66,6 +66,12 @@ 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 () {
diff --git a/code/M3D/M3DExporter.cpp b/code/M3D/M3DExporter.cpp
index c22943396..b1c7ebdba 100644
--- a/code/M3D/M3DExporter.cpp
+++ b/code/M3D/M3DExporter.cpp
@@ -169,6 +169,33 @@ void M3DExporter::doExport (
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
void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
@@ -221,25 +248,23 @@ void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
if(mesh->HasVertexColors(0))
vertex.color = mkColor(&mesh->mColors[0][l]);
// save the vertex to the output
- m3d->vertex = _m3d_addvrtx(m3d->vertex, &m3d->numvertex,
+ m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex,
&vertex, &idx);
m3d->face[n].vertex[k] = (M3D_INDEX)idx;
// do we have texture coordinates?
if(mesh->HasTextureCoords(0)) {
ti.u = mesh->mTextureCoords[0][l].x;
ti.v = mesh->mTextureCoords[0][l].y;
- m3d->tmap = _m3d_addtmap(m3d->tmap, &m3d->numtmap, &ti,
- &idx);
+ m3d->tmap = AddTmap(m3d->tmap, &m3d->numtmap, &ti, &idx);
m3d->face[n].texcoord[k] = (M3D_INDEX)idx;
}
// do we have normal vectors?
if(mesh->HasNormals()) {
- vertex.color = 0;
vertex.x = mesh->mNormals[l].x;
vertex.y = mesh->mNormals[l].y;
vertex.z = mesh->mNormals[l].z;
- m3d->vertex = _m3d_addnorm(m3d->vertex, &m3d->numvertex,
- &vertex, &idx);
+ vertex.color = 0;
+ m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex, &vertex, &idx);
m3d->face[n].normal[k] = (M3D_INDEX)idx;
}
}
diff --git a/code/M3D/M3DExporter.h b/code/M3D/M3DExporter.h
index dfcff8bc9..58d8d597e 100644
--- a/code/M3D/M3DExporter.h
+++ b/code/M3D/M3DExporter.h
@@ -87,6 +87,8 @@ namespace Assimp
// helper to do the recursive walking
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);
M3D_INDEX addMaterial(const aiMaterial *mat);
void addProp(m3dm_t *m, uint8_t type, uint32_t value);
diff --git a/code/M3D/M3DImporter.cpp b/code/M3D/M3DImporter.cpp
index fcff49df7..9371e2228 100644
--- a/code/M3D/M3DImporter.cpp
+++ b/code/M3D/M3DImporter.cpp
@@ -44,6 +44,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define M3D_IMPLEMENTATION
#define M3D_ASCII
+#define M3D_NONORMALS /* leave the post-processing to Assimp */
+#define M3D_NOWEIGHTS
+#define M3D_NOANIMATION
#include
#include
@@ -104,16 +107,21 @@ extern "C" {
std::string file(fn);
std::unique_ptr pStream(
(reinterpret_cast(m3dimporter_pIOHandler))->Open( file, "rb"));
- size_t fileSize = pStream->FileSize();
- // should be allocated with malloc(), because the library will call free() to deallocate
- unsigned char *data = (unsigned char*)malloc(fileSize);
- if( !data || !pStream.get() || !fileSize || fileSize != pStream->Read(data,1,fileSize)) {
+ size_t fileSize = 0;
+ unsigned char *data = NULL;
+ // sometimes pStream is nullptr for some reason (should be an empty object returning nothing I guess)
+ 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();
- *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;
return data;
}
@@ -307,7 +315,7 @@ void M3DImporter::importMaterials()
m->prop[j].value.textureid < m3d->numtexture &&
m3d->texture[m->prop[j].value.textureid].name) {
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;
mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index);
}
@@ -321,6 +329,7 @@ void M3DImporter::importMaterials()
void M3DImporter::importTextures()
{
unsigned int i;
+ const char *formatHint[] = { "rgba0800", "rgba0808", "rgba8880", "rgba8888" };
m3dtx_t *t;
ai_assert(mScene != nullptr);
@@ -334,14 +343,29 @@ void M3DImporter::importTextures()
mScene->mTextures = new aiTexture*[m3d->numtexture];
for(i = 0; i < m3d->numtexture; i++) {
+ unsigned int j, k;
t = &m3d->texture[i];
+ if(!t->w || !t->h || !t->f || !t->d) continue;
aiTexture *tx = new aiTexture;
- strcpy(tx->achFormatHint, "rgba8888");
+ strcpy(tx->achFormatHint, formatHint[t->f - 1]);
tx->mFilename = aiString(std::string(t->name) + ".png");
tx->mWidth = t->w;
tx->mHeight = t->h;
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;
}
}
@@ -372,9 +396,14 @@ void M3DImporter::importMeshes()
// we must switch mesh if material changes
if(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);
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
}
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->a1 = m->b2 = m->c3 = -1.0;
} 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->a2 = 2 * (q->x * q->y - q->z * q->w); if(m->a2 > -1e-7 && m->a2 < 1e-7) 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->b1 = 2 * (q->x * q->y + q->z * q->w); if(m->b1 > -1e-7 && m->b1 < 1e-7) 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->b3 = 2 * (q->y * q->z - q->x * q->w); if(m->b3 > -1e-7 && m->b3 < 1e-7) 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->c2 = 2 * (q->y * q->z + q->x * q->w); if(m->c2 > -1e-7 && m->c2 < 1e-7) 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->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 > -M3D_EPSILON && m->a2 < M3D_EPSILON) m->a2 = 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 > -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 > -M3D_EPSILON && m->b2 < M3D_EPSILON) m->b2 = 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 > -M3D_EPSILON && m->c1 < M3D_EPSILON) m->c1 = 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 > -M3D_EPSILON && m->c3 < M3D_EPSILON) m->c3 = 0.0;
}
/* set translation */
diff --git a/code/M3D/M3DMaterials.h b/code/M3D/M3DMaterials.h
index fa02cf42b..3d6fe246d 100644
--- a/code/M3D/M3DMaterials.h
+++ b/code/M3D/M3DMaterials.h
@@ -75,7 +75,7 @@ static const aiMatProp aiProps[] = {
{ AI_MATKEY_REFLECTIVITY }, /* m3dp_Pm */
{ NULL, 0, 0 }, /* m3dp_Ps */
{ AI_MATKEY_REFRACTI }, /* m3dp_Ni */
- { NULL, 0, 0 },
+ { NULL, 0, 0 }, /* m3dp_Nt */
{ 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 */
{ NULL, 0, 0 }, /* m3dp_map_Ps */
{ 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 }
diff --git a/code/M3D/m3d.h b/code/M3D/m3d.h
index 9ace802ef..c1d690bcc 100644
--- a/code/M3D/m3d.h
+++ b/code/M3D/m3d.h
@@ -58,8 +58,15 @@ extern "C" {
#define M3D_APIVERSION 0x0100
#ifndef M3D_DOUBLE
typedef float M3D_FLOAT;
+#ifndef M3D_EPSILON
+/* carefully choosen for IEEE 754 don't change */
+#define M3D_EPSILON ((M3D_FLOAT)1e-7)
+#endif
#else
typedef double M3D_FLOAT;
+#ifndef M3D_EPSILON
+#define M3D_EPSILON ((M3D_FLOAT)1e-14)
+#endif
#endif
#if !defined(M3D_SMALLINDEX)
typedef uint32_t M3D_INDEX;
@@ -96,23 +103,35 @@ typedef uint16_t M3D_INDEX;
* 3DMO m3dchunk_t file header chunk, may followed by compressed data
* HEAD m3dhdr_t model header chunk
* n x m3dchunk_t more chunks follow
+ * PRVW preview chunk (optional)
* CMAP color map chunk (optional)
* TMAP texture map chunk (optional)
* VRTS vertex data chunk (optional if it's a material library)
* BONE bind-pose skeleton, bone hierarchy chunk (optional)
* n x m3db_t contains propably more, but at least one bone
+ * n x m3ds_t skin group records
* MTRL* material chunk(s), can be more (optional)
* n x m3dp_t each material contains propapbly more, but at least one property
* the properties are configurable with a static array, see m3d_propertytypes
* n x m3dchunk_t at least one, but maybe more face chunks
* PROC* procedural face, or
- * MESH* triangle mesh (vertex index list)
+ * MESH* triangle mesh (vertex index list) or
+ * SHPE* mathematical shapes like parameterized surfaces
+ * LBLS* annotation label chunks, can be more (optional)
* ACTN* action chunk(s), animation-pose skeletons, can be more (optional)
* n x m3dfr_t each action contains probably more, but at least one frame
* n x m3dtr_t each frame contains probably more, but at least one transformation
* ASET* inlined asset chunk(s), can be more (optional)
* OMD3 end chunk
+ *
+ * Typical chunks for a game engine: 3DMO, HEAD, CMAP, TMAP, VRTS, BONE, MTRL, MESH, ACTN, OMD3
+ * Typical chunks for CAD software: 3DMO, HEAD, PRVW, CMAP, TMAP, VRTS, MTRL, SHPE, LBLS, OMD3
*/
+#ifdef _MSC_VER
+#pragma pack(push)
+#pragma pack(1)
+#endif
+
typedef struct {
char magic[4];
uint32_t length;
@@ -125,6 +144,10 @@ typedef struct {
uint32_t length;
} _pack m3dchunk_t;
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif
+
/*** in-memory model structure ***/
/* textmap entry */
@@ -132,19 +155,23 @@ typedef struct {
M3D_FLOAT u;
M3D_FLOAT v;
} m3dti_t;
+#define m3d_textureindex_t m3dti_t
/* texture */
typedef struct {
char *name; /* texture name */
- uint32_t *d; /* pixels data */
+ uint8_t *d; /* pixels data */
uint16_t w; /* width */
uint16_t h; /* height */
-} _pack m3dtx_t;
+ uint8_t f; /* format, 1 = grayscale, 2 = grayscale+alpha, 3 = rgb, 4 = rgba */
+} m3dtx_t;
+#define m3d_texturedata_t m3dtx_t
typedef struct {
M3D_INDEX vertexid;
M3D_FLOAT weight;
} m3dw_t;
+#define m3d_weight_t m3dw_t
/* bone entry */
typedef struct {
@@ -156,12 +183,14 @@ typedef struct {
m3dw_t *weight; /* weights for those vertices */
M3D_FLOAT mat4[16]; /* transformation matrix */
} m3db_t;
+#define m3d_bone_t m3db_t
/* skin: bone per vertex entry */
typedef struct {
M3D_INDEX boneid[M3D_NUMBONE];
M3D_FLOAT weight[M3D_NUMBONE];
} m3ds_t;
+#define m3d_skin_t m3ds_t
/* vertex entry */
typedef struct {
@@ -171,7 +200,11 @@ typedef struct {
M3D_FLOAT w;
uint32_t color; /* default vertex color */
M3D_INDEX skinid; /* skin index */
+#ifdef M3D_VERTEXTYPE
+ uint8_t type;
+#endif
} m3dv_t;
+#define m3d_vertex_t m3dv_t
/* material property formats */
enum {
@@ -210,6 +243,7 @@ enum {
m3dp_Pm,
m3dp_Ps,
m3dp_Ni,
+ m3dp_Nt,
m3dp_map_Kd = 128, /* textured display map properties */
m3dp_map_Ka,
@@ -224,7 +258,8 @@ enum {
m3dp_map_Pr = 192, /* textured physical map properties */
m3dp_map_Pm,
m3dp_map_Ps,
- m3dp_map_Ni
+ m3dp_map_Ni,
+ m3dp_map_Nt
};
enum { /* aliases */
m3dp_bump = m3dp_map_Km,
@@ -241,6 +276,7 @@ typedef struct {
M3D_INDEX textureid; /* if value is a texture, m3dpf_map */
} value;
} m3dp_t;
+#define m3d_property_t m3dp_t
/* material entry */
typedef struct {
@@ -248,6 +284,7 @@ typedef struct {
uint8_t numprop; /* number of properties */
m3dp_t *prop; /* properties array */
} m3dm_t;
+#define m3d_material_t m3dm_t
/* face entry */
typedef struct {
@@ -256,6 +293,108 @@ typedef struct {
M3D_INDEX normal[3]; /* normal vectors */
M3D_INDEX texcoord[3]; /* UV coordinates */
} m3df_t;
+#define m3d_face_t m3df_t
+
+/* shape command types. must match the row in m3d_commandtypes */
+enum {
+ /* special commands */
+ m3dc_use = 0, /* use material */
+ m3dc_inc, /* include another shape */
+ m3dc_mesh, /* include part of polygon mesh */
+ /* approximations */
+ m3dc_div, /* subdivision by constant resolution for both u, v */
+ m3dc_sub, /* subdivision by constant, different for u and v */
+ m3dc_len, /* spacial subdivision by maxlength */
+ m3dc_dist, /* subdivision by maxdistance and maxangle */
+ /* modifiers */
+ m3dc_degu, /* degree for both u, v */
+ m3dc_deg, /* separate degree for u and v */
+ m3dc_rangeu, /* range for u */
+ m3dc_range, /* range for u and v */
+ m3dc_paru, /* u parameters (knots) */
+ m3dc_parv, /* v parameters */
+ m3dc_trim, /* outer trimming curve */
+ m3dc_hole, /* inner trimming curve */
+ m3dc_scrv, /* spacial curve */
+ m3dc_sp, /* special points */
+ /* helper curves */
+ m3dc_bez1, /* Bezier 1D */
+ m3dc_bsp1, /* B-spline 1D */
+ m3dc_bez2, /* bezier 2D */
+ m3dc_bsp2, /* B-spline 2D */
+ /* surfaces */
+ m3dc_bezun, /* Bezier 3D with control, UV, normal */
+ m3dc_bezu, /* with control and UV */
+ m3dc_bezn, /* with control and normal */
+ m3dc_bez, /* control points only */
+ m3dc_nurbsun, /* B-spline 3D */
+ m3dc_nurbsu,
+ m3dc_nurbsn,
+ m3dc_nurbs,
+ m3dc_conn, /* connect surfaces */
+ /* geometrical */
+ m3dc_line,
+ m3dc_polygon,
+ m3dc_circle,
+ m3dc_cylinder,
+ m3dc_shpere,
+ m3dc_torus,
+ m3dc_cone,
+ m3dc_cube
+};
+
+/* shape command argument types */
+enum {
+ m3dcp_mi_t = 1, /* material index */
+ m3dcp_hi_t, /* shape index */
+ m3dcp_fi_t, /* face index */
+ m3dcp_ti_t, /* texture map index */
+ m3dcp_vi_t, /* vertex index */
+ m3dcp_qi_t, /* vertex index for quaternions */
+ m3dcp_vc_t, /* coordinate or radius, float scalar */
+ m3dcp_i1_t, /* int8 scalar */
+ m3dcp_i2_t, /* int16 scalar */
+ m3dcp_i4_t, /* int32 scalar */
+ m3dcp_va_t /* variadic arguments */
+};
+
+#define M3D_CMDMAXARG 8 /* if you increase this, add more arguments to the macro below */
+typedef struct {
+#ifdef M3D_ASCII
+#define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (char*)(n), (p), { (a), (b), (c), (d), (e), (f), (g), (h) } }
+ char *key;
+#else
+#define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (p), { (a), (b), (c), (d), (e), (f), (g), (h) } }
+#endif
+ uint8_t p;
+ uint8_t a[M3D_CMDMAXARG];
+} m3dcd_t;
+
+/* shape command */
+typedef struct {
+ uint16_t type; /* shape type */
+ uint32_t *arg; /* arguments array */
+} m3dc_t;
+#define m3d_shapecommand_t m3dc_t
+
+/* shape entry */
+typedef struct {
+ char *name; /* name of the mathematical shape */
+ M3D_INDEX group; /* group this shape belongs to or -1 */
+ uint32_t numcmd; /* number of commands */
+ m3dc_t *cmd; /* commands array */
+} m3dh_t;
+#define m3d_shape_t m3dh_t
+
+/* label entry */
+typedef struct {
+ char *name; /* name of the annotation layer or NULL */
+ char *lang; /* language code or NULL */
+ char *text; /* the label text */
+ uint32_t color; /* color */
+ M3D_INDEX vertexid; /* the vertex the label refers to */
+} m3dl_t;
+#define m3d_label_t m3dl_t
/* frame transformations / working copy skeleton entry */
typedef struct {
@@ -263,6 +402,7 @@ typedef struct {
M3D_INDEX pos; /* vertex index new position */
M3D_INDEX ori; /* vertex index new orientation (quaternion) */
} m3dtr_t;
+#define m3d_transform_t m3dtr_t
/* animation frame entry */
typedef struct {
@@ -270,6 +410,7 @@ typedef struct {
M3D_INDEX numtransform; /* number of transformations in this frame */
m3dtr_t *transform; /* transformations */
} m3dfr_t;
+#define m3d_frame_t m3dfr_t
/* model action entry */
typedef struct {
@@ -278,6 +419,7 @@ typedef struct {
M3D_INDEX numframe; /* number of frames in this animation */
m3dfr_t *frame; /* frames array */
} m3da_t;
+#define m3d_action_t m3da_t
/* inlined asset */
typedef struct {
@@ -285,17 +427,19 @@ typedef struct {
uint8_t *data; /* compressed asset data */
uint32_t length; /* compressed data length */
} m3di_t;
+#define m3d_inlinedasset_t m3di_t
/*** in-memory model structure ***/
#define M3D_FLG_FREERAW (1<<0)
#define M3D_FLG_FREESTR (1<<1)
#define M3D_FLG_MTLLIB (1<<2)
+#define M3D_FLG_GENNORM (1<<3)
typedef struct {
m3dhdr_t *raw; /* pointer to raw data */
char flags; /* internal flags */
- char errcode; /* returned error code */
- char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fi_s; /* decoded sizes for types */
+ signed char errcode; /* returned error code */
+ char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s,fi_s; /* decoded sizes for types */
char *name; /* name of the model, like "Utah teapot" */
char *license; /* usage condition or license, like "MIT", "LGPL" or "BSD-3clause" */
char *author; /* nickname, email, homepage or github URL etc. */
@@ -316,13 +460,18 @@ typedef struct {
M3D_INDEX nummaterial;
m3dm_t *material; /* material list */
M3D_INDEX numface;
- m3df_t *face; /* model face, triangle mesh */
+ m3df_t *face; /* model face, polygon (triangle) mesh */
+ M3D_INDEX numshape;
+ m3dh_t *shape; /* model face, shape commands */
+ M3D_INDEX numlabel;
+ m3dl_t *label; /* annotation labels */
M3D_INDEX numaction;
m3da_t *action; /* action animations */
M3D_INDEX numinlined;
m3di_t *inlined; /* inlined assets */
- M3D_INDEX numunknown;
- m3dchunk_t **unknown; /* unknown chunks, application / engine specific data probably */
+ M3D_INDEX numextra;
+ m3dchunk_t **extra; /* unknown chunks, application / engine specific data probably */
+ m3di_t preview; /* preview chunk */
} m3d_t;
/*** export parameters ***/
@@ -355,12 +504,14 @@ typedef struct {
#define M3D_ERR_UNKMESH -67
#define M3D_ERR_UNKIMG -68
#define M3D_ERR_UNKFRAME -69
-#define M3D_ERR_TRUNC -70
-#define M3D_ERR_CMAP -71
-#define M3D_ERR_TMAP -72
-#define M3D_ERR_VRTS -73
-#define M3D_ERR_BONE -74
-#define M3D_ERR_MTRL -75
+#define M3D_ERR_UNKCMD -70
+#define M3D_ERR_TRUNC -71
+#define M3D_ERR_CMAP -72
+#define M3D_ERR_TMAP -73
+#define M3D_ERR_VRTS -74
+#define M3D_ERR_BONE -75
+#define M3D_ERR_MTRL -76
+#define M3D_ERR_SHPE -77
#define M3D_ERR_ISFATAL(x) ((x) < 0 && (x) > -65)
@@ -381,8 +532,6 @@ m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t
m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec);
/* private prototypes used by both importer and exporter */
-m3ds_t *_m3d_addskin(m3ds_t *skin, uint32_t *numskin, m3ds_t *s, uint32_t *idx);
-m3dv_t *_m3d_addnorm(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx);
char *_m3d_safestr(char *in, int morelines);
/*** C implementation ***/
@@ -404,11 +553,59 @@ static m3dpd_t m3d_propertytypes[] = {
M3D_PROPERTYDEF(m3dpf_float, m3dp_Pm, "Pm"), /* metallic, also reflection */
M3D_PROPERTYDEF(m3dpf_float, m3dp_Ps, "Ps"), /* sheen */
M3D_PROPERTYDEF(m3dpf_float, m3dp_Ni, "Ni"), /* index of refraction (optical density) */
+ M3D_PROPERTYDEF(m3dpf_float, m3dp_Nt, "Nt"), /* thickness of face in millimeter, for printing */
/* aliases, note that "map_*" aliases are handled automatically */
M3D_PROPERTYDEF(m3dpf_map, m3dp_map_Km, "bump"),
M3D_PROPERTYDEF(m3dpf_map, m3dp_map_Pm, "refl")
};
+/* shape command definitions. if more commands start with the same string, the longer must come first */
+static m3dcd_t m3d_commandtypes[] = {
+ /* technical */
+ M3D_CMDDEF(m3dc_use, "use", 1, m3dcp_mi_t, 0, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_inc, "inc", 3, m3dcp_hi_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vi_t, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_mesh, "mesh", 1, m3dcp_fi_t, m3dcp_fi_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vi_t, 0, 0, 0),
+ /* approximations */
+ M3D_CMDDEF(m3dc_div, "div", 1, m3dcp_vc_t, 0, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_sub, "sub", 2, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_len, "len", 1, m3dcp_vc_t, 0, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_dist, "dist", 2, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0),
+ /* modifiers */
+ M3D_CMDDEF(m3dc_degu, "degu", 1, m3dcp_i1_t, 0, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_deg, "deg", 2, m3dcp_i1_t, m3dcp_i1_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_rangeu, "rangeu", 1, m3dcp_ti_t, 0, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_range, "range", 2, m3dcp_ti_t, m3dcp_ti_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_paru, "paru", 2, m3dcp_va_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_parv, "parv", 2, m3dcp_va_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_trim, "trim", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_hole, "hole", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_scrv, "scrv", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_sp, "sp", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
+ /* helper curves */
+ M3D_CMDDEF(m3dc_bez1, "bez1", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_bsp1, "bsp1", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_bez2, "bez2", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_bsp2, "bsp2", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
+ /* surfaces */
+ M3D_CMDDEF(m3dc_bezun, "bezun", 4, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, m3dcp_vi_t, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_bezu, "bezu", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_bezn, "bezn", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_bez, "bez", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_nurbsun, "nurbsun", 4, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, m3dcp_vi_t, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_nurbsu, "nurbsu", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_nurbsn, "nurbsn", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_nurbs, "nurbs", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_conn, "conn", 6, m3dcp_i2_t, m3dcp_ti_t, m3dcp_i2_t, m3dcp_i2_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0),
+ /* geometrical */
+ M3D_CMDDEF(m3dc_line, "line", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_polygon, "polygon", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_circle, "circle", 3, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_cylinder,"cylinder",6, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, 0, 0),
+ M3D_CMDDEF(m3dc_shpere, "shpere", 2, m3dcp_vi_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_torus, "torus", 4, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_cone, "cone", 3, m3dcp_vi_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0),
+ M3D_CMDDEF(m3dc_cube, "cube", 3, m3dcp_vi_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0)
+};
#endif
#include
@@ -419,7 +616,7 @@ static m3dpd_t m3d_propertytypes[] = {
stb_image - v2.23 - public domain image loader - http://nothings.org/stb_image.h
*/
-static const char *stbi__g_failure_reason;
+static const char *_m3dstbi__g_failure_reason;
enum
{
@@ -438,57 +635,56 @@ enum
STBI__SCAN_header
};
-typedef unsigned char stbi_uc;
-typedef unsigned short stbi_us;
+typedef unsigned short _m3dstbi_us;
-typedef uint16_t stbi__uint16;
-typedef int16_t stbi__int16;
-typedef uint32_t stbi__uint32;
-typedef int32_t stbi__int32;
+typedef uint16_t _m3dstbi__uint16;
+typedef int16_t _m3dstbi__int16;
+typedef uint32_t _m3dstbi__uint32;
+typedef int32_t _m3dstbi__int32;
typedef struct
{
- stbi__uint32 img_x, img_y;
+ _m3dstbi__uint32 img_x, img_y;
int img_n, img_out_n;
void *io_user_data;
int read_from_callbacks;
int buflen;
- stbi_uc buffer_start[128];
+ unsigned char buffer_start[128];
- stbi_uc *img_buffer, *img_buffer_end;
- stbi_uc *img_buffer_original, *img_buffer_original_end;
-} stbi__context;
+ unsigned char *img_buffer, *img_buffer_end;
+ unsigned char *img_buffer_original, *img_buffer_original_end;
+} _m3dstbi__context;
typedef struct
{
int bits_per_channel;
int num_channels;
int channel_order;
-} stbi__result_info;
+} _m3dstbi__result_info;
#define STBI_ASSERT(v)
#define STBI_NOTUSED(v) (void)sizeof(v)
-#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255))
+#define STBI__BYTECAST(x) ((unsigned char) ((x) & 255))
#define STBI_MALLOC(sz) M3D_MALLOC(sz)
#define STBI_REALLOC(p,newsz) M3D_REALLOC(p,newsz)
#define STBI_FREE(p) M3D_FREE(p)
#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
-_inline static stbi_uc stbi__get8(stbi__context *s)
+_inline static unsigned char _m3dstbi__get8(_m3dstbi__context *s)
{
if (s->img_buffer < s->img_buffer_end)
return *s->img_buffer++;
return 0;
}
-_inline static int stbi__at_eof(stbi__context *s)
+_inline static int _m3dstbi__at_eof(_m3dstbi__context *s)
{
return s->img_buffer >= s->img_buffer_end;
}
-static void stbi__skip(stbi__context *s, int n)
+static void _m3dstbi__skip(_m3dstbi__context *s, int n)
{
if (n < 0) {
s->img_buffer = s->img_buffer_end;
@@ -497,7 +693,7 @@ static void stbi__skip(stbi__context *s, int n)
s->img_buffer += n;
}
-static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
+static int _m3dstbi__getn(_m3dstbi__context *s, unsigned char *buffer, int n)
{
if (s->img_buffer+n <= s->img_buffer_end) {
memcpy(buffer, s->img_buffer, n);
@@ -507,72 +703,72 @@ static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
return 0;
}
-static int stbi__get16be(stbi__context *s)
+static int _m3dstbi__get16be(_m3dstbi__context *s)
{
- int z = stbi__get8(s);
- return (z << 8) + stbi__get8(s);
+ int z = _m3dstbi__get8(s);
+ return (z << 8) + _m3dstbi__get8(s);
}
-static stbi__uint32 stbi__get32be(stbi__context *s)
+static _m3dstbi__uint32 _m3dstbi__get32be(_m3dstbi__context *s)
{
- stbi__uint32 z = stbi__get16be(s);
- return (z << 16) + stbi__get16be(s);
+ _m3dstbi__uint32 z = _m3dstbi__get16be(s);
+ return (z << 16) + _m3dstbi__get16be(s);
}
-#define stbi__err(x,y) stbi__errstr(y)
-static int stbi__errstr(const char *str)
+#define _m3dstbi__err(x,y) _m3dstbi__errstr(y)
+static int _m3dstbi__errstr(const char *str)
{
- stbi__g_failure_reason = str;
+ _m3dstbi__g_failure_reason = str;
return 0;
}
-_inline static void *stbi__malloc(size_t size)
+_inline static void *_m3dstbi__malloc(size_t size)
{
return STBI_MALLOC(size);
}
-static int stbi__addsizes_valid(int a, int b)
+static int _m3dstbi__addsizes_valid(int a, int b)
{
if (b < 0) return 0;
return a <= 2147483647 - b;
}
-static int stbi__mul2sizes_valid(int a, int b)
+static int _m3dstbi__mul2sizes_valid(int a, int b)
{
if (a < 0 || b < 0) return 0;
if (b == 0) return 1;
return a <= 2147483647/b;
}
-static int stbi__mad2sizes_valid(int a, int b, int add)
+static int _m3dstbi__mad2sizes_valid(int a, int b, int add)
{
- return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
+ return _m3dstbi__mul2sizes_valid(a, b) && _m3dstbi__addsizes_valid(a*b, add);
}
-static int stbi__mad3sizes_valid(int a, int b, int c, int add)
+static int _m3dstbi__mad3sizes_valid(int a, int b, int c, int add)
{
- return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
- stbi__addsizes_valid(a*b*c, add);
+ return _m3dstbi__mul2sizes_valid(a, b) && _m3dstbi__mul2sizes_valid(a*b, c) &&
+ _m3dstbi__addsizes_valid(a*b*c, add);
}
-static void *stbi__malloc_mad2(int a, int b, int add)
+static void *_m3dstbi__malloc_mad2(int a, int b, int add)
{
- if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
- return stbi__malloc(a*b + add);
+ if (!_m3dstbi__mad2sizes_valid(a, b, add)) return NULL;
+ return _m3dstbi__malloc(a*b + add);
}
-static void *stbi__malloc_mad3(int a, int b, int c, int add)
+static void *_m3dstbi__malloc_mad3(int a, int b, int c, int add)
{
- if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;
- return stbi__malloc(a*b*c + add);
+ if (!_m3dstbi__mad3sizes_valid(a, b, c, add)) return NULL;
+ return _m3dstbi__malloc(a*b*c + add);
}
-static stbi_uc stbi__compute_y(int r, int g, int b)
+static unsigned char _m3dstbi__compute_y(int r, int g, int b)
{
- return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8);
+ return (unsigned char) (((r*77) + (g*150) + (29*b)) >> 8);
}
-static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+static unsigned char *_m3dstbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
{
int i,j;
unsigned char *good;
@@ -580,10 +776,10 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
if (req_comp == img_n) return data;
STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
- good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);
+ good = (unsigned char *) _m3dstbi__malloc_mad3(req_comp, x, y, 0);
if (good == NULL) {
STBI_FREE(data);
- stbi__err("outofmem", "Out of memory");
+ _m3dstbi__err("outofmem", "Out of memory");
return NULL;
}
@@ -601,10 +797,10 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break;
- STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
- STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break;
- STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
- STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break;
+ STBI__CASE(3,1) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]); } break;
+ STBI__CASE(3,2) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break;
+ STBI__CASE(4,1) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]); } break;
+ STBI__CASE(4,2) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break;
STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
default: STBI_ASSERT(0);
}
@@ -615,29 +811,29 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
return good;
}
-static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
+static _m3dstbi__uint16 _m3dstbi__compute_y_16(int r, int g, int b)
{
- return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8);
+ return (_m3dstbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8);
}
-static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+static _m3dstbi__uint16 *_m3dstbi__convert_format16(_m3dstbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
{
int i,j;
- stbi__uint16 *good;
+ _m3dstbi__uint16 *good;
if (req_comp == img_n) return data;
STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
- good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);
+ good = (_m3dstbi__uint16 *) _m3dstbi__malloc(req_comp * x * y * 2);
if (good == NULL) {
STBI_FREE(data);
- stbi__err("outofmem", "Out of memory");
+ _m3dstbi__err("outofmem", "Out of memory");
return NULL;
}
for (j=0; j < (int) y; ++j) {
- stbi__uint16 *src = data + j * x * img_n ;
- stbi__uint16 *dest = good + j * x * req_comp;
+ _m3dstbi__uint16 *src = data + j * x * img_n ;
+ _m3dstbi__uint16 *dest = good + j * x * req_comp;
#define STBI__COMBO(a,b) ((a)*8+(b))
#define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
@@ -649,10 +845,10 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r
STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break;
- STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
- STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break;
- STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
- STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break;
+ STBI__CASE(3,1) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]); } break;
+ STBI__CASE(3,2) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break;
+ STBI__CASE(4,1) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]); } break;
+ STBI__CASE(4,2) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break;
STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
default: STBI_ASSERT(0);
}
@@ -668,15 +864,15 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r
typedef struct
{
- stbi__uint16 fast[1 << STBI__ZFAST_BITS];
- stbi__uint16 firstcode[16];
+ _m3dstbi__uint16 fast[1 << STBI__ZFAST_BITS];
+ _m3dstbi__uint16 firstcode[16];
int maxcode[17];
- stbi__uint16 firstsymbol[16];
- stbi_uc size[288];
- stbi__uint16 value[288];
-} stbi__zhuffman;
+ _m3dstbi__uint16 firstsymbol[16];
+ unsigned char size[288];
+ _m3dstbi__uint16 value[288];
+} _m3dstbi__zhuffman;
-_inline static int stbi__bitreverse16(int n)
+_inline static int _m3dstbi__bitreverse16(int n)
{
n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1);
n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2);
@@ -685,13 +881,13 @@ _inline static int stbi__bitreverse16(int n)
return n;
}
-_inline static int stbi__bit_reverse(int v, int bits)
+_inline static int _m3dstbi__bit_reverse(int v, int bits)
{
STBI_ASSERT(bits <= 16);
- return stbi__bitreverse16(v) >> (16-bits);
+ return _m3dstbi__bitreverse16(v) >> (16-bits);
}
-static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)
+static int _m3dstbi__zbuild_huffman(_m3dstbi__zhuffman *z, unsigned char *sizelist, int num)
{
int i,k=0;
int code, next_code[16], sizes[17];
@@ -703,15 +899,15 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)
sizes[0] = 0;
for (i=1; i < 16; ++i)
if (sizes[i] > (1 << i))
- return stbi__err("bad sizes", "Corrupt PNG");
+ return _m3dstbi__err("bad sizes", "Corrupt PNG");
code = 0;
for (i=1; i < 16; ++i) {
next_code[i] = code;
- z->firstcode[i] = (stbi__uint16) code;
- z->firstsymbol[i] = (stbi__uint16) k;
+ z->firstcode[i] = (_m3dstbi__uint16) code;
+ z->firstsymbol[i] = (_m3dstbi__uint16) k;
code = (code + sizes[i]);
if (sizes[i])
- if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG");
+ if (code-1 >= (1 << i)) return _m3dstbi__err("bad codelengths","Corrupt PNG");
z->maxcode[i] = code << (16-i);
code <<= 1;
k += sizes[i];
@@ -721,11 +917,11 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)
int s = sizelist[i];
if (s) {
int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
- stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);
- z->size [c] = (stbi_uc ) s;
- z->value[c] = (stbi__uint16) i;
+ _m3dstbi__uint16 fastv = (_m3dstbi__uint16) ((s << 9) | i);
+ z->size [c] = (unsigned char ) s;
+ z->value[c] = (_m3dstbi__uint16) i;
if (s <= STBI__ZFAST_BITS) {
- int j = stbi__bit_reverse(next_code[s],s);
+ int j = _m3dstbi__bit_reverse(next_code[s],s);
while (j < (1 << STBI__ZFAST_BITS)) {
z->fast[j] = fastv;
j += (1 << s);
@@ -739,47 +935,47 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)
typedef struct
{
- stbi_uc *zbuffer, *zbuffer_end;
+ unsigned char *zbuffer, *zbuffer_end;
int num_bits;
- stbi__uint32 code_buffer;
+ _m3dstbi__uint32 code_buffer;
char *zout;
char *zout_start;
char *zout_end;
int z_expandable;
- stbi__zhuffman z_length, z_distance;
-} stbi__zbuf;
+ _m3dstbi__zhuffman z_length, z_distance;
+} _m3dstbi__zbuf;
-_inline static stbi_uc stbi__zget8(stbi__zbuf *z)
+_inline static unsigned char _m3dstbi__zget8(_m3dstbi__zbuf *z)
{
if (z->zbuffer >= z->zbuffer_end) return 0;
return *z->zbuffer++;
}
-static void stbi__fill_bits(stbi__zbuf *z)
+static void _m3dstbi__fill_bits(_m3dstbi__zbuf *z)
{
do {
STBI_ASSERT(z->code_buffer < (1U << z->num_bits));
- z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;
+ z->code_buffer |= (unsigned int) _m3dstbi__zget8(z) << z->num_bits;
z->num_bits += 8;
} while (z->num_bits <= 24);
}
-_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)
+_inline static unsigned int _m3dstbi__zreceive(_m3dstbi__zbuf *z, int n)
{
unsigned int k;
- if (z->num_bits < n) stbi__fill_bits(z);
+ if (z->num_bits < n) _m3dstbi__fill_bits(z);
k = z->code_buffer & ((1 << n) - 1);
z->code_buffer >>= n;
z->num_bits -= n;
return k;
}
-static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
+static int _m3dstbi__zhuffman_decode_slowpath(_m3dstbi__zbuf *a, _m3dstbi__zhuffman *z)
{
int b,s,k;
- k = stbi__bit_reverse(a->code_buffer, 16);
+ k = _m3dstbi__bit_reverse(a->code_buffer, 16);
for (s=STBI__ZFAST_BITS+1; ; ++s)
if (k < z->maxcode[s])
break;
@@ -791,10 +987,10 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
return z->value[b];
}
-_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
+_inline static int _m3dstbi__zhuffman_decode(_m3dstbi__zbuf *a, _m3dstbi__zhuffman *z)
{
int b,s;
- if (a->num_bits < 16) stbi__fill_bits(a);
+ if (a->num_bits < 16) _m3dstbi__fill_bits(a);
b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
if (b) {
s = b >> 9;
@@ -802,76 +998,76 @@ _inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
a->num_bits -= s;
return b & 511;
}
- return stbi__zhuffman_decode_slowpath(a, z);
+ return _m3dstbi__zhuffman_decode_slowpath(a, z);
}
-static int stbi__zexpand(stbi__zbuf *z, char *zout, int n)
+static int _m3dstbi__zexpand(_m3dstbi__zbuf *z, char *zout, int n)
{
char *q;
int cur, limit, old_limit;
z->zout = zout;
- if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
+ if (!z->z_expandable) return _m3dstbi__err("output buffer limit","Corrupt PNG");
cur = (int) (z->zout - z->zout_start);
limit = old_limit = (int) (z->zout_end - z->zout_start);
while (cur + n > limit)
limit *= 2;
q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
STBI_NOTUSED(old_limit);
- if (q == NULL) return stbi__err("outofmem", "Out of memory");
+ if (q == NULL) return _m3dstbi__err("outofmem", "Out of memory");
z->zout_start = q;
z->zout = q + cur;
z->zout_end = q + limit;
return 1;
}
-static int stbi__zlength_base[31] = {
+static int _m3dstbi__zlength_base[31] = {
3,4,5,6,7,8,9,10,11,13,
15,17,19,23,27,31,35,43,51,59,
67,83,99,115,131,163,195,227,258,0,0 };
-static int stbi__zlength_extra[31]=
+static int _m3dstbi__zlength_extra[31]=
{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
-static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
+static int _m3dstbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
-static int stbi__zdist_extra[32] =
+static int _m3dstbi__zdist_extra[32] =
{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
-static int stbi__parse_huffman_block(stbi__zbuf *a)
+static int _m3dstbi__parse_huffman_block(_m3dstbi__zbuf *a)
{
char *zout = a->zout;
for(;;) {
- int z = stbi__zhuffman_decode(a, &a->z_length);
+ int z = _m3dstbi__zhuffman_decode(a, &a->z_length);
if (z < 256) {
- if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
+ if (z < 0) return _m3dstbi__err("bad huffman code","Corrupt PNG");
if (zout >= a->zout_end) {
- if (!stbi__zexpand(a, zout, 1)) return 0;
+ if (!_m3dstbi__zexpand(a, zout, 1)) return 0;
zout = a->zout;
}
*zout++ = (char) z;
} else {
- stbi_uc *p;
+ unsigned char *p;
int len,dist;
if (z == 256) {
a->zout = zout;
return 1;
}
z -= 257;
- len = stbi__zlength_base[z];
- if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
- z = stbi__zhuffman_decode(a, &a->z_distance);
- if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
- dist = stbi__zdist_base[z];
- if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
- if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
+ len = _m3dstbi__zlength_base[z];
+ if (_m3dstbi__zlength_extra[z]) len += _m3dstbi__zreceive(a, _m3dstbi__zlength_extra[z]);
+ z = _m3dstbi__zhuffman_decode(a, &a->z_distance);
+ if (z < 0) return _m3dstbi__err("bad huffman code","Corrupt PNG");
+ dist = _m3dstbi__zdist_base[z];
+ if (_m3dstbi__zdist_extra[z]) dist += _m3dstbi__zreceive(a, _m3dstbi__zdist_extra[z]);
+ if (zout - a->zout_start < dist) return _m3dstbi__err("bad dist","Corrupt PNG");
if (zout + len > a->zout_end) {
- if (!stbi__zexpand(a, zout, len)) return 0;
+ if (!_m3dstbi__zexpand(a, zout, len)) return 0;
zout = a->zout;
}
- p = (stbi_uc *) (zout - dist);
+ p = (unsigned char *) (zout - dist);
if (dist == 1) {
- stbi_uc v = *p;
+ unsigned char v = *p;
if (len) { do *zout++ = v; while (--len); }
} else {
if (len) { do *zout++ = *p++; while (--len); }
@@ -880,152 +1076,151 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
}
}
-static int stbi__compute_huffman_codes(stbi__zbuf *a)
+static int _m3dstbi__compute_huffman_codes(_m3dstbi__zbuf *a)
{
- static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
- stbi__zhuffman z_codelength;
- stbi_uc lencodes[286+32+137];
- stbi_uc codelength_sizes[19];
+ static unsigned char length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+ _m3dstbi__zhuffman z_codelength;
+ unsigned char lencodes[286+32+137];
+ unsigned char codelength_sizes[19];
int i,n;
- int hlit = stbi__zreceive(a,5) + 257;
- int hdist = stbi__zreceive(a,5) + 1;
- int hclen = stbi__zreceive(a,4) + 4;
+ int hlit = _m3dstbi__zreceive(a,5) + 257;
+ int hdist = _m3dstbi__zreceive(a,5) + 1;
+ int hclen = _m3dstbi__zreceive(a,4) + 4;
int ntot = hlit + hdist;
memset(codelength_sizes, 0, sizeof(codelength_sizes));
for (i=0; i < hclen; ++i) {
- int s = stbi__zreceive(a,3);
- codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;
+ int s = _m3dstbi__zreceive(a,3);
+ codelength_sizes[length_dezigzag[i]] = (unsigned char) s;
}
- if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
+ if (!_m3dstbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
n = 0;
while (n < ntot) {
- int c = stbi__zhuffman_decode(a, &z_codelength);
- if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
+ int c = _m3dstbi__zhuffman_decode(a, &z_codelength);
+ if (c < 0 || c >= 19) return _m3dstbi__err("bad codelengths", "Corrupt PNG");
if (c < 16)
- lencodes[n++] = (stbi_uc) c;
+ lencodes[n++] = (unsigned char) c;
else {
- stbi_uc fill = 0;
+ unsigned char fill = 0;
if (c == 16) {
- c = stbi__zreceive(a,2)+3;
- if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG");
+ c = _m3dstbi__zreceive(a,2)+3;
+ if (n == 0) return _m3dstbi__err("bad codelengths", "Corrupt PNG");
fill = lencodes[n-1];
} else if (c == 17)
- c = stbi__zreceive(a,3)+3;
+ c = _m3dstbi__zreceive(a,3)+3;
else {
STBI_ASSERT(c == 18);
- c = stbi__zreceive(a,7)+11;
+ c = _m3dstbi__zreceive(a,7)+11;
}
- if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG");
+ if (ntot - n < c) return _m3dstbi__err("bad codelengths", "Corrupt PNG");
memset(lencodes+n, fill, c);
n += c;
}
}
- if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG");
- if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
- if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
+ if (n != ntot) return _m3dstbi__err("bad codelengths","Corrupt PNG");
+ if (!_m3dstbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
+ if (!_m3dstbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
return 1;
}
-_inline static int stbi__parse_uncompressed_block(stbi__zbuf *a)
+_inline static int _m3dstbi__parse_uncompressed_block(_m3dstbi__zbuf *a)
{
- stbi_uc header[4];
+ unsigned char header[4];
int len,nlen,k;
if (a->num_bits & 7)
- stbi__zreceive(a, a->num_bits & 7);
+ _m3dstbi__zreceive(a, a->num_bits & 7);
k = 0;
while (a->num_bits > 0) {
- header[k++] = (stbi_uc) (a->code_buffer & 255);
+ header[k++] = (unsigned char) (a->code_buffer & 255);
a->code_buffer >>= 8;
a->num_bits -= 8;
}
STBI_ASSERT(a->num_bits == 0);
while (k < 4)
- header[k++] = stbi__zget8(a);
+ header[k++] = _m3dstbi__zget8(a);
len = header[1] * 256 + header[0];
nlen = header[3] * 256 + header[2];
- if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG");
- if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG");
+ if (nlen != (len ^ 0xffff)) return _m3dstbi__err("zlib corrupt","Corrupt PNG");
+ if (a->zbuffer + len > a->zbuffer_end) return _m3dstbi__err("read past buffer","Corrupt PNG");
if (a->zout + len > a->zout_end)
- if (!stbi__zexpand(a, a->zout, len)) return 0;
+ if (!_m3dstbi__zexpand(a, a->zout, len)) return 0;
memcpy(a->zout, a->zbuffer, len);
a->zbuffer += len;
a->zout += len;
return 1;
}
-static int stbi__parse_zlib_header(stbi__zbuf *a)
+static int _m3dstbi__parse_zlib_header(_m3dstbi__zbuf *a)
{
- int cmf = stbi__zget8(a);
+ int cmf = _m3dstbi__zget8(a);
int cm = cmf & 15;
/* int cinfo = cmf >> 4; */
- int flg = stbi__zget8(a);
- if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG");
- if (flg & 32) return stbi__err("no preset dict","Corrupt PNG");
- if (cm != 8) return stbi__err("bad compression","Corrupt PNG");
+ int flg = _m3dstbi__zget8(a);
+ if ((cmf*256+flg) % 31 != 0) return _m3dstbi__err("bad zlib header","Corrupt PNG");
+ if (flg & 32) return _m3dstbi__err("no preset dict","Corrupt PNG");
+ if (cm != 8) return _m3dstbi__err("bad compression","Corrupt PNG");
return 1;
}
-static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32];
-static void stbi__init_zdefaults(void)
+static unsigned char _m3dstbi__zdefault_length[288], _m3dstbi__zdefault_distance[32];
+static void _m3dstbi__init_zdefaults(void)
{
int i;
- for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8;
- for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9;
- for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7;
- for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8;
+ for (i=0; i <= 143; ++i) _m3dstbi__zdefault_length[i] = 8;
+ for ( ; i <= 255; ++i) _m3dstbi__zdefault_length[i] = 9;
+ for ( ; i <= 279; ++i) _m3dstbi__zdefault_length[i] = 7;
+ for ( ; i <= 287; ++i) _m3dstbi__zdefault_length[i] = 8;
- for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5;
+ for (i=0; i <= 31; ++i) _m3dstbi__zdefault_distance[i] = 5;
}
-static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
+static int _m3dstbi__parse_zlib(_m3dstbi__zbuf *a, int parse_header)
{
int final, type;
if (parse_header)
- if (!stbi__parse_zlib_header(a)) return 0;
+ if (!_m3dstbi__parse_zlib_header(a)) return 0;
a->num_bits = 0;
a->code_buffer = 0;
do {
- final = stbi__zreceive(a,1);
- type = stbi__zreceive(a,2);
+ final = _m3dstbi__zreceive(a,1);
+ type = _m3dstbi__zreceive(a,2);
if (type == 0) {
- if (!stbi__parse_uncompressed_block(a)) return 0;
+ if (!_m3dstbi__parse_uncompressed_block(a)) return 0;
} else if (type == 3) {
return 0;
} else {
if (type == 1) {
- if (!stbi__zdefault_distance[31]) stbi__init_zdefaults();
- if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0;
- if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0;
+ if (!_m3dstbi__zbuild_huffman(&a->z_length , _m3dstbi__zdefault_length , 288)) return 0;
+ if (!_m3dstbi__zbuild_huffman(&a->z_distance, _m3dstbi__zdefault_distance, 32)) return 0;
} else {
- if (!stbi__compute_huffman_codes(a)) return 0;
+ if (!_m3dstbi__compute_huffman_codes(a)) return 0;
}
- if (!stbi__parse_huffman_block(a)) return 0;
+ if (!_m3dstbi__parse_huffman_block(a)) return 0;
}
} while (!final);
return 1;
}
-static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)
+static int _m3dstbi__do_zlib(_m3dstbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)
{
a->zout_start = obuf;
a->zout = obuf;
a->zout_end = obuf + olen;
a->z_expandable = exp;
-
- return stbi__parse_zlib(a, parse_header);
+ _m3dstbi__init_zdefaults();
+ return _m3dstbi__parse_zlib(a, parse_header);
}
-char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
+char *_m3dstbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
{
- stbi__zbuf a;
- char *p = (char *) stbi__malloc(initial_size);
+ _m3dstbi__zbuf a;
+ char *p = (char *) _m3dstbi__malloc(initial_size);
if (p == NULL) return NULL;
- a.zbuffer = (stbi_uc *) buffer;
- a.zbuffer_end = (stbi_uc *) buffer + len;
- if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {
+ a.zbuffer = (unsigned char *) buffer;
+ a.zbuffer_end = (unsigned char *) buffer + len;
+ if (_m3dstbi__do_zlib(&a, p, initial_size, 1, parse_header)) {
if (outlen) *outlen = (int) (a.zout - a.zout_start);
return a.zout_start;
} else {
@@ -1036,33 +1231,33 @@ char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len,
typedef struct
{
- stbi__uint32 length;
- stbi__uint32 type;
-} stbi__pngchunk;
+ _m3dstbi__uint32 length;
+ _m3dstbi__uint32 type;
+} _m3dstbi__pngchunk;
-static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
+static _m3dstbi__pngchunk _m3dstbi__get_chunk_header(_m3dstbi__context *s)
{
- stbi__pngchunk c;
- c.length = stbi__get32be(s);
- c.type = stbi__get32be(s);
+ _m3dstbi__pngchunk c;
+ c.length = _m3dstbi__get32be(s);
+ c.type = _m3dstbi__get32be(s);
return c;
}
-_inline static int stbi__check_png_header(stbi__context *s)
+_inline static int _m3dstbi__check_png_header(_m3dstbi__context *s)
{
- static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
+ static unsigned char png_sig[8] = { 137,80,78,71,13,10,26,10 };
int i;
for (i=0; i < 8; ++i)
- if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
+ if (_m3dstbi__get8(s) != png_sig[i]) return _m3dstbi__err("bad png sig","Not a PNG");
return 1;
}
typedef struct
{
- stbi__context *s;
- stbi_uc *idata, *expanded, *out;
+ _m3dstbi__context *s;
+ unsigned char *idata, *expanded, *out;
int depth;
-} stbi__png;
+} _m3dstbi__png;
enum {
@@ -1075,7 +1270,7 @@ enum {
STBI__F_paeth_first
};
-static stbi_uc first_row_filter[5] =
+static unsigned char first_row_filter[5] =
{
STBI__F_none,
STBI__F_sub,
@@ -1084,7 +1279,7 @@ static stbi_uc first_row_filter[5] =
STBI__F_paeth_first
};
-static int stbi__paeth(int a, int b, int c)
+static int _m3dstbi__paeth(int a, int b, int c)
{
int p = a + b - c;
int pa = abs(p-a);
@@ -1095,14 +1290,14 @@ static int stbi__paeth(int a, int b, int c)
return c;
}
-static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
+static unsigned char _m3dstbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
-static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
+static int _m3dstbi__create_png_image_raw(_m3dstbi__png *a, unsigned char *raw, _m3dstbi__uint32 raw_len, int out_n, _m3dstbi__uint32 x, _m3dstbi__uint32 y, int depth, int color)
{
int bytes = (depth == 16? 2 : 1);
- stbi__context *s = a->s;
- stbi__uint32 i,j,stride = x*out_n*bytes;
- stbi__uint32 img_len, img_width_bytes;
+ _m3dstbi__context *s = a->s;
+ _m3dstbi__uint32 i,j,stride = x*out_n*bytes;
+ _m3dstbi__uint32 img_len, img_width_bytes;
int k;
int img_n = s->img_n;
@@ -1111,24 +1306,25 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
int width = x;
STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
- a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0);
- if (!a->out) return stbi__err("outofmem", "Out of memory");
+ a->out = (unsigned char *) _m3dstbi__malloc_mad3(x, y, output_bytes, 0);
+ if (!a->out) return _m3dstbi__err("outofmem", "Out of memory");
+ if (!_m3dstbi__mad3sizes_valid(img_n, x, depth, 7)) return _m3dstbi__err("too large", "Corrupt PNG");
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
img_len = (img_width_bytes + 1) * y;
if (s->img_x == x && s->img_y == y) {
- if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG");
+ if (raw_len != img_len) return _m3dstbi__err("not enough pixels","Corrupt PNG");
} else {
- if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
+ if (raw_len < img_len) return _m3dstbi__err("not enough pixels","Corrupt PNG");
}
for (j=0; j < y; ++j) {
- stbi_uc *cur = a->out + stride*j;
- stbi_uc *prior = cur - stride;
+ unsigned char *cur = a->out + stride*j;
+ unsigned char *prior = cur - stride;
int filter = *raw++;
if (filter > 4)
- return stbi__err("invalid filter","Corrupt PNG");
+ return _m3dstbi__err("invalid filter","Corrupt PNG");
if (depth < 8) {
STBI_ASSERT(img_width_bytes <= x);
@@ -1136,6 +1332,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
filter_bytes = 1;
width = img_width_bytes;
}
+ prior = cur - stride;
if (j == 0) filter = first_row_filter[filter];
@@ -1145,7 +1342,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
case STBI__F_sub : cur[k] = raw[k]; break;
case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
- case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
+ case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(0,prior[k],0)); break;
case STBI__F_avg_first : cur[k] = raw[k]; break;
case STBI__F_paeth_first: cur[k] = raw[k]; break;
}
@@ -1181,9 +1378,9 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
- STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
+ STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
- STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
+ STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k-filter_bytes],0,0)); } break;
}
#undef STBI__CASE
raw += nk;
@@ -1198,9 +1395,9 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
- STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
+ STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
- STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
+ STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k- output_bytes],0,0)); } break;
}
#undef STBI__CASE
@@ -1215,9 +1412,9 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
if (depth < 8) {
for (j=0; j < y; ++j) {
- stbi_uc *cur = a->out + stride*j;
- stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes;
- stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1;
+ unsigned char *cur = a->out + stride*j;
+ unsigned char *in = a->out + stride*j + x*out_n - img_width_bytes;
+ unsigned char scale = (color == 0) ? _m3dstbi__depth_scale_table[depth] : 1;
if (depth == 4) {
for (k=x*img_n; k >= 2; k-=2, ++in) {
@@ -1274,8 +1471,8 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
}
}
} else if (depth == 16) {
- stbi_uc *cur = a->out;
- stbi__uint16 *cur16 = (stbi__uint16*)cur;
+ unsigned char *cur = a->out;
+ _m3dstbi__uint16 *cur16 = (_m3dstbi__uint16*)cur;
for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
*cur16 = (cur[0] << 8) | cur[1];
@@ -1285,16 +1482,16 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
return 1;
}
-static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
+static int _m3dstbi__create_png_image(_m3dstbi__png *a, unsigned char *image_data, _m3dstbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
{
int bytes = (depth == 16 ? 2 : 1);
int out_bytes = out_n * bytes;
- stbi_uc *final;
+ unsigned char *final;
int p;
if (!interlaced)
- return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
+ return _m3dstbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
- final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
+ final = (unsigned char *) _m3dstbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
for (p=0; p < 7; ++p) {
int xorig[] = { 0,4,0,2,0,1,0 };
int yorig[] = { 0,0,4,0,2,0,1 };
@@ -1304,8 +1501,8 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3
x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
if (x && y) {
- stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;
- if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {
+ _m3dstbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;
+ if (!_m3dstbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {
STBI_FREE(final);
return 0;
}
@@ -1327,11 +1524,11 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3
return 1;
}
-static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)
+static int _m3dstbi__compute_transparency(_m3dstbi__png *z, unsigned char tc[3], int out_n)
{
- stbi__context *s = z->s;
- stbi__uint32 i, pixel_count = s->img_x * s->img_y;
- stbi_uc *p = z->out;
+ _m3dstbi__context *s = z->s;
+ _m3dstbi__uint32 i, pixel_count = s->img_x * s->img_y;
+ unsigned char *p = z->out;
STBI_ASSERT(out_n == 2 || out_n == 4);
@@ -1350,11 +1547,11 @@ static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)
return 1;
}
-static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)
+static int _m3dstbi__compute_transparency16(_m3dstbi__png *z, _m3dstbi__uint16 tc[3], int out_n)
{
- stbi__context *s = z->s;
- stbi__uint32 i, pixel_count = s->img_x * s->img_y;
- stbi__uint16 *p = (stbi__uint16*) z->out;
+ _m3dstbi__context *s = z->s;
+ _m3dstbi__uint32 i, pixel_count = s->img_x * s->img_y;
+ _m3dstbi__uint16 *p = (_m3dstbi__uint16*) z->out;
STBI_ASSERT(out_n == 2 || out_n == 4);
@@ -1373,13 +1570,13 @@ static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int ou
return 1;
}
-static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)
+static int _m3dstbi__expand_png_palette(_m3dstbi__png *a, unsigned char *palette, int len, int pal_img_n)
{
- stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
- stbi_uc *p, *temp_out, *orig = a->out;
+ _m3dstbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
+ unsigned char *p, *temp_out, *orig = a->out;
- p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);
- if (p == NULL) return stbi__err("outofmem", "Out of memory");
+ p = (unsigned char *) _m3dstbi__malloc_mad2(pixel_count, pal_img_n, 0);
+ if (p == NULL) return _m3dstbi__err("outofmem", "Out of memory");
temp_out = p;
@@ -1409,228 +1606,177 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int
return 1;
}
-static int stbi__unpremultiply_on_load = 0;
-static int stbi__de_iphone_flag = 0;
+#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))
-void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
+static int _m3dstbi__parse_png_file(_m3dstbi__png *z, int scan, int req_comp)
{
- stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
-}
-
-void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
-{
- stbi__de_iphone_flag = flag_true_if_should_convert;
-}
-
-static void stbi__de_iphone(stbi__png *z)
-{
- stbi__context *s = z->s;
- stbi__uint32 i, pixel_count = s->img_x * s->img_y;
- stbi_uc *p = z->out;
-
- if (s->img_out_n == 3) {
- for (i=0; i < pixel_count; ++i) {
- stbi_uc t = p[0];
- p[0] = p[2];
- p[2] = t;
- p += 3;
- }
- } else {
- STBI_ASSERT(s->img_out_n == 4);
- if (stbi__unpremultiply_on_load) {
- for (i=0; i < pixel_count; ++i) {
- stbi_uc a = p[3];
- stbi_uc t = p[0];
- if (a) {
- p[0] = p[2] * 255 / a;
- p[1] = p[1] * 255 / a;
- p[2] = t * 255 / a;
- } else {
- p[0] = p[2];
- p[2] = t;
- }
- p += 4;
- }
- } else {
- for (i=0; i < pixel_count; ++i) {
- stbi_uc t = p[0];
- p[0] = p[2];
- p[2] = t;
- p += 4;
- }
- }
- }
-}
-
-#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
-
-static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
-{
- stbi_uc palette[1024], pal_img_n=0;
- stbi_uc has_trans=0, tc[3];
- stbi__uint16 tc16[3];
- stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
- int first=1,k,interlace=0, color=0, is_iphone=0;
- stbi__context *s = z->s;
+ unsigned char palette[1024], pal_img_n=0;
+ unsigned char has_trans=0, tc[3];
+ _m3dstbi__uint16 tc16[3];
+ _m3dstbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
+ int first=1,k,interlace=0, color=0;
+ _m3dstbi__context *s = z->s;
z->expanded = NULL;
z->idata = NULL;
z->out = NULL;
- if (!stbi__check_png_header(s)) return 0;
+ if (!_m3dstbi__check_png_header(s)) return 0;
if (scan == STBI__SCAN_type) return 1;
for (;;) {
- stbi__pngchunk c = stbi__get_chunk_header(s);
+ _m3dstbi__pngchunk c = _m3dstbi__get_chunk_header(s);
switch (c.type) {
case STBI__PNG_TYPE('C','g','B','I'):
- is_iphone = 1;
- stbi__skip(s, c.length);
+ _m3dstbi__skip(s, c.length);
break;
case STBI__PNG_TYPE('I','H','D','R'): {
int comp,filter;
- if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
+ if (!first) return _m3dstbi__err("multiple IHDR","Corrupt PNG");
first = 0;
- if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
- s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
- s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
- z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
- color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG");
- if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG");
- if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
- comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG");
- filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG");
- interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG");
- if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG");
+ if (c.length != 13) return _m3dstbi__err("bad IHDR len","Corrupt PNG");
+ s->img_x = _m3dstbi__get32be(s); if (s->img_x > (1 << 24)) return _m3dstbi__err("too large","Very large image (corrupt?)");
+ s->img_y = _m3dstbi__get32be(s); if (s->img_y > (1 << 24)) return _m3dstbi__err("too large","Very large image (corrupt?)");
+ z->depth = _m3dstbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return _m3dstbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
+ color = _m3dstbi__get8(s); if (color > 6) return _m3dstbi__err("bad ctype","Corrupt PNG");
+ if (color == 3 && z->depth == 16) return _m3dstbi__err("bad ctype","Corrupt PNG");
+ if (color == 3) pal_img_n = 3; else if (color & 1) return _m3dstbi__err("bad ctype","Corrupt PNG");
+ comp = _m3dstbi__get8(s); if (comp) return _m3dstbi__err("bad comp method","Corrupt PNG");
+ filter= _m3dstbi__get8(s); if (filter) return _m3dstbi__err("bad filter method","Corrupt PNG");
+ interlace = _m3dstbi__get8(s); if (interlace>1) return _m3dstbi__err("bad interlace method","Corrupt PNG");
+ if (!s->img_x || !s->img_y) return _m3dstbi__err("0-pixel image","Corrupt PNG");
if (!pal_img_n) {
s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
- if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
+ if ((1 << 30) / s->img_x / s->img_n < s->img_y) return _m3dstbi__err("too large", "Image too large to decode");
if (scan == STBI__SCAN_header) return 1;
} else {
s->img_n = 1;
- if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
+ if ((1 << 30) / s->img_x / 4 < s->img_y) return _m3dstbi__err("too large","Corrupt PNG");
}
break;
}
case STBI__PNG_TYPE('P','L','T','E'): {
- if (first) return stbi__err("first not IHDR", "Corrupt PNG");
- if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG");
+ if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG");
+ if (c.length > 256*3) return _m3dstbi__err("invalid PLTE","Corrupt PNG");
pal_len = c.length / 3;
- if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG");
+ if (pal_len * 3 != c.length) return _m3dstbi__err("invalid PLTE","Corrupt PNG");
for (i=0; i < pal_len; ++i) {
- palette[i*4+0] = stbi__get8(s);
- palette[i*4+1] = stbi__get8(s);
- palette[i*4+2] = stbi__get8(s);
+ palette[i*4+0] = _m3dstbi__get8(s);
+ palette[i*4+1] = _m3dstbi__get8(s);
+ palette[i*4+2] = _m3dstbi__get8(s);
palette[i*4+3] = 255;
}
break;
}
case STBI__PNG_TYPE('t','R','N','S'): {
- if (first) return stbi__err("first not IHDR", "Corrupt PNG");
- if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG");
+ if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG");
+ if (z->idata) return _m3dstbi__err("tRNS after IDAT","Corrupt PNG");
if (pal_img_n) {
if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }
- if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG");
- if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG");
+ if (pal_len == 0) return _m3dstbi__err("tRNS before PLTE","Corrupt PNG");
+ if (c.length > pal_len) return _m3dstbi__err("bad tRNS len","Corrupt PNG");
pal_img_n = 4;
for (i=0; i < c.length; ++i)
- palette[i*4+3] = stbi__get8(s);
+ palette[i*4+3] = _m3dstbi__get8(s);
} else {
- if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
- if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
+ if (!(s->img_n & 1)) return _m3dstbi__err("tRNS with alpha","Corrupt PNG");
+ if (c.length != (_m3dstbi__uint32) s->img_n*2) return _m3dstbi__err("bad tRNS len","Corrupt PNG");
has_trans = 1;
if (z->depth == 16) {
- for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s);
+ for (k = 0; k < s->img_n; ++k) tc16[k] = (_m3dstbi__uint16)_m3dstbi__get16be(s);
} else {
- for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth];
+ for (k = 0; k < s->img_n; ++k) tc[k] = (unsigned char)(_m3dstbi__get16be(s) & 255) * _m3dstbi__depth_scale_table[z->depth];
}
}
break;
}
case STBI__PNG_TYPE('I','D','A','T'): {
- if (first) return stbi__err("first not IHDR", "Corrupt PNG");
- if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
+ if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG");
+ if (pal_img_n && !pal_len) return _m3dstbi__err("no PLTE","Corrupt PNG");
if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
if ((int)(ioff + c.length) < (int)ioff) return 0;
if (ioff + c.length > idata_limit) {
- stbi__uint32 idata_limit_old = idata_limit;
- stbi_uc *p;
+ _m3dstbi__uint32 idata_limit_old = idata_limit;
+ unsigned char *p;
if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
while (ioff + c.length > idata_limit)
idata_limit *= 2;
STBI_NOTUSED(idata_limit_old);
- p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
+ p = (unsigned char *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return _m3dstbi__err("outofmem", "Out of memory");
z->idata = p;
}
- if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
+ if (!_m3dstbi__getn(s, z->idata+ioff,c.length)) return _m3dstbi__err("outofdata","Corrupt PNG");
ioff += c.length;
break;
}
case STBI__PNG_TYPE('I','E','N','D'): {
- stbi__uint32 raw_len, bpl;
- if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ _m3dstbi__uint32 raw_len, bpl;
+ if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG");
if (scan != STBI__SCAN_load) return 1;
- if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG");
+ if (z->idata == NULL) return _m3dstbi__err("no IDAT","Corrupt PNG");
bpl = (s->img_x * z->depth + 7) / 8;
raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;
- z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);
+ z->expanded = (unsigned char *) _m3dstbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, 1);
if (z->expanded == NULL) return 0;
STBI_FREE(z->idata); z->idata = NULL;
if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
s->img_out_n = s->img_n+1;
else
s->img_out_n = s->img_n;
- if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;
+ if (!_m3dstbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;
if (has_trans) {
if (z->depth == 16) {
- if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;
+ if (!_m3dstbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;
} else {
- if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;
+ if (!_m3dstbi__compute_transparency(z, tc, s->img_out_n)) return 0;
}
}
- if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)
- stbi__de_iphone(z);
if (pal_img_n) {
s->img_n = pal_img_n;
s->img_out_n = pal_img_n;
if (req_comp >= 3) s->img_out_n = req_comp;
- if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
+ if (!_m3dstbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
return 0;
+ } else if (has_trans) {
+ ++s->img_n;
}
STBI_FREE(z->expanded); z->expanded = NULL;
return 1;
}
default:
- if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+ if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG");
if ((c.type & (1 << 29)) == 0) {
- return stbi__err("invalid_chunk", "PNG not supported: unknown PNG chunk type");
+ return _m3dstbi__err("invalid_chunk", "PNG not supported: unknown PNG chunk type");
}
- stbi__skip(s, c.length);
+ _m3dstbi__skip(s, c.length);
break;
}
- stbi__get32be(s);
+ _m3dstbi__get32be(s);
}
}
-static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)
+static void *_m3dstbi__do_png(_m3dstbi__png *p, int *x, int *y, int *n, int req_comp, _m3dstbi__result_info *ri)
{
void *result=NULL;
- if (req_comp < 0 || req_comp > 4) { stbi__err("bad req_comp", "Internal error"); return NULL; }
- if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
- ri->bits_per_channel = p->depth;
+ if (req_comp < 0 || req_comp > 4) { _m3dstbi__err("bad req_comp", "Internal error"); return NULL; }
+ if (_m3dstbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
+ if (p->depth < 8)
+ ri->bits_per_channel = 8;
+ else
+ ri->bits_per_channel = p->depth;
result = p->out;
p->out = NULL;
if (req_comp && req_comp != p->s->img_out_n) {
if (ri->bits_per_channel == 8)
- result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+ result = _m3dstbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
else
- result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+ result = _m3dstbi__convert_format16((_m3dstbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
p->s->img_out_n = req_comp;
if (result == NULL) return result;
}
@@ -1645,12 +1791,16 @@ static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, st
return result;
}
-static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
+static void *_m3dstbi__png_load(_m3dstbi__context *s, int *x, int *y, int *comp, int req_comp, _m3dstbi__result_info *ri)
{
- stbi__png p;
+ _m3dstbi__png p;
p.s = s;
- return stbi__do_png(&p, x,y,comp,req_comp, ri);
+ return _m3dstbi__do_png(&p, x,y,comp,req_comp, ri);
}
+#define stbi__context _m3dstbi__context
+#define stbi__result_info _m3dstbi__result_info
+#define stbi__png_load _m3dstbi__png_load
+#define stbi_zlib_decode_malloc_guesssize_headerflag _m3dstbi_zlib_decode_malloc_guesssize_headerflag
#endif
#if defined(M3D_EXPORTER) && !defined(INCLUDE_STB_IMAGE_WRITE_H)
@@ -1658,13 +1808,13 @@ static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req
stb_image_write - v1.13 - public domain - http://nothings.org/stb/stb_image_write.h
*/
-typedef unsigned char stbiw_uc;
-typedef unsigned short stbiw_us;
+typedef unsigned char _m3dstbiw__uc;
+typedef unsigned short _m3dstbiw__us;
-typedef uint16_t stbiw_uint16;
-typedef int16_t stbiw_int16;
-typedef uint32_t stbiw_uint32;
-typedef int32_t stbiw_int32;
+typedef uint16_t _m3dstbiw__uint16;
+typedef int16_t _m3dstbiw__int16;
+typedef uint32_t _m3dstbiw__uint32;
+typedef int32_t _m3dstbiw__int32;
#define STBIW_MALLOC(s) M3D_MALLOC(s)
#define STBIW_REALLOC(p,ns) M3D_REALLOC(p,ns)
@@ -1673,42 +1823,42 @@ typedef int32_t stbiw_int32;
#define STBIW_MEMMOVE memmove
#define STBIW_UCHAR (uint8_t)
#define STBIW_ASSERT(x)
-#define stbiw__sbraw(a) ((int *) (a) - 2)
-#define stbiw__sbm(a) stbiw__sbraw(a)[0]
-#define stbiw__sbn(a) stbiw__sbraw(a)[1]
+#define _m3dstbiw___sbraw(a) ((int *) (a) - 2)
+#define _m3dstbiw___sbm(a) _m3dstbiw___sbraw(a)[0]
+#define _m3dstbiw___sbn(a) _m3dstbiw___sbraw(a)[1]
-#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
-#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
-#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
+#define _m3dstbiw___sbneedgrow(a,n) ((a)==0 || _m3dstbiw___sbn(a)+n >= _m3dstbiw___sbm(a))
+#define _m3dstbiw___sbmaybegrow(a,n) (_m3dstbiw___sbneedgrow(a,(n)) ? _m3dstbiw___sbgrow(a,n) : 0)
+#define _m3dstbiw___sbgrow(a,n) _m3dstbiw___sbgrowf((void **) &(a), (n), sizeof(*(a)))
-#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
-#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
-#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
+#define _m3dstbiw___sbpush(a, v) (_m3dstbiw___sbmaybegrow(a,1), (a)[_m3dstbiw___sbn(a)++] = (v))
+#define _m3dstbiw___sbcount(a) ((a) ? _m3dstbiw___sbn(a) : 0)
+#define _m3dstbiw___sbfree(a) ((a) ? STBIW_FREE(_m3dstbiw___sbraw(a)),0 : 0)
-static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
+static void *_m3dstbiw___sbgrowf(void **arr, int increment, int itemsize)
{
- int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
- void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
+ int m = *arr ? 2*_m3dstbiw___sbm(*arr)+increment : increment+1;
+ void *p = STBIW_REALLOC_SIZED(*arr ? _m3dstbiw___sbraw(*arr) : 0, *arr ? (_m3dstbiw___sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
STBIW_ASSERT(p);
if (p) {
if (!*arr) ((int *) p)[1] = 0;
*arr = (void *) ((int *) p + 2);
- stbiw__sbm(*arr) = m;
+ _m3dstbiw___sbm(*arr) = m;
}
return *arr;
}
-static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
+static unsigned char *_m3dstbiw___zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
{
while (*bitcount >= 8) {
- stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
+ _m3dstbiw___sbpush(data, STBIW_UCHAR(*bitbuffer));
*bitbuffer >>= 8;
*bitcount -= 8;
}
return data;
}
-static int stbiw__zlib_bitrev(int code, int codebits)
+static int _m3dstbiw___zlib_bitrev(int code, int codebits)
{
int res=0;
while (codebits--) {
@@ -1718,7 +1868,7 @@ static int stbiw__zlib_bitrev(int code, int codebits)
return res;
}
-static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
+static unsigned int _m3dstbiw___zlib_countm(unsigned char *a, unsigned char *b, int limit)
{
int i;
for (i=0; i < limit && i < 258; ++i)
@@ -1726,9 +1876,9 @@ static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int l
return i;
}
-static unsigned int stbiw__zhash(unsigned char *data)
+static unsigned int _m3dstbiw___zhash(unsigned char *data)
{
- stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
+ _m3dstbiw__uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
@@ -1738,20 +1888,20 @@ static unsigned int stbiw__zhash(unsigned char *data)
return hash;
}
-#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
-#define stbiw__zlib_add(code,codebits) \
- (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
-#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
-#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
-#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
-#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
-#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
-#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))
-#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
+#define _m3dstbiw___zlib_flush() (out = _m3dstbiw___zlib_flushf(out, &bitbuf, &bitcount))
+#define _m3dstbiw___zlib_add(code,codebits) \
+ (bitbuf |= (code) << bitcount, bitcount += (codebits), _m3dstbiw___zlib_flush())
+#define _m3dstbiw___zlib_huffa(b,c) _m3dstbiw___zlib_add(_m3dstbiw___zlib_bitrev(b,c),c)
+#define _m3dstbiw___zlib_huff1(n) _m3dstbiw___zlib_huffa(0x30 + (n), 8)
+#define _m3dstbiw___zlib_huff2(n) _m3dstbiw___zlib_huffa(0x190 + (n)-144, 9)
+#define _m3dstbiw___zlib_huff3(n) _m3dstbiw___zlib_huffa(0 + (n)-256,7)
+#define _m3dstbiw___zlib_huff4(n) _m3dstbiw___zlib_huffa(0xc0 + (n)-280,8)
+#define _m3dstbiw___zlib_huff(n) ((n) <= 143 ? _m3dstbiw___zlib_huff1(n) : (n) <= 255 ? _m3dstbiw___zlib_huff2(n) : (n) <= 279 ? _m3dstbiw___zlib_huff3(n) : _m3dstbiw___zlib_huff4(n))
+#define _m3dstbiw___zlib_huffb(n) ((n) <= 143 ? _m3dstbiw___zlib_huff1(n) : _m3dstbiw___zlib_huff2(n))
-#define stbiw__ZHASH 16384
+#define _m3dstbiw___ZHASH 16384
-unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
+unsigned char * _m3dstbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
@@ -1760,42 +1910,44 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
unsigned int bitbuf=0;
int i,j, bitcount=0;
unsigned char *out = NULL;
- unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
+ unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(_m3dstbiw___ZHASH * sizeof(char**));
+ if (hash_table == NULL)
+ return NULL;
if (quality < 5) quality = 5;
- stbiw__sbpush(out, 0x78);
- stbiw__sbpush(out, 0x5e);
- stbiw__zlib_add(1,1);
- stbiw__zlib_add(1,2);
+ _m3dstbiw___sbpush(out, 0x78);
+ _m3dstbiw___sbpush(out, 0x5e);
+ _m3dstbiw___zlib_add(1,1);
+ _m3dstbiw___zlib_add(1,2);
- for (i=0; i < stbiw__ZHASH; ++i)
+ for (i=0; i < _m3dstbiw___ZHASH; ++i)
hash_table[i] = NULL;
i=0;
while (i < data_len-3) {
- int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
+ int h = _m3dstbiw___zhash(data+i)&(_m3dstbiw___ZHASH-1), best=3;
unsigned char *bestloc = 0;
unsigned char **hlist = hash_table[h];
- int n = stbiw__sbcount(hlist);
+ int n = _m3dstbiw___sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32768) {
- int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
+ int d = _m3dstbiw___zlib_countm(hlist[j], data+i, data_len-i);
if (d >= best) best=d,bestloc=hlist[j];
}
}
- if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
+ if (hash_table[h] && _m3dstbiw___sbn(hash_table[h]) == 2*quality) {
STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
- stbiw__sbn(hash_table[h]) = quality;
+ _m3dstbiw___sbn(hash_table[h]) = quality;
}
- stbiw__sbpush(hash_table[h],data+i);
+ _m3dstbiw___sbpush(hash_table[h],data+i);
if (bestloc) {
- h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
+ h = _m3dstbiw___zhash(data+i+1)&(_m3dstbiw___ZHASH-1);
hlist = hash_table[h];
- n = stbiw__sbcount(hlist);
+ n = _m3dstbiw___sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32767) {
- int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
+ int e = _m3dstbiw___zlib_countm(hlist[j], data+i+1, data_len-i-1);
if (e > best) {
bestloc = NULL;
break;
@@ -1808,25 +1960,25 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
int d = (int) (data+i - bestloc);
STBIW_ASSERT(d <= 32767 && best <= 258);
for (j=0; best > lengthc[j+1]-1; ++j);
- stbiw__zlib_huff(j+257);
- if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
+ _m3dstbiw___zlib_huff(j+257);
+ if (lengtheb[j]) _m3dstbiw___zlib_add(best - lengthc[j], lengtheb[j]);
for (j=0; d > distc[j+1]-1; ++j);
- stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
- if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
+ _m3dstbiw___zlib_add(_m3dstbiw___zlib_bitrev(j,5),5);
+ if (disteb[j]) _m3dstbiw___zlib_add(d - distc[j], disteb[j]);
i += best;
} else {
- stbiw__zlib_huffb(data[i]);
+ _m3dstbiw___zlib_huffb(data[i]);
++i;
}
}
for (;i < data_len; ++i)
- stbiw__zlib_huffb(data[i]);
- stbiw__zlib_huff(256);
+ _m3dstbiw___zlib_huffb(data[i]);
+ _m3dstbiw___zlib_huff(256);
while (bitcount)
- stbiw__zlib_add(0,1);
+ _m3dstbiw___zlib_add(0,1);
- for (i=0; i < stbiw__ZHASH; ++i)
- (void) stbiw__sbfree(hash_table[i]);
+ for (i=0; i < _m3dstbiw___ZHASH; ++i)
+ (void) _m3dstbiw___sbfree(hash_table[i]);
STBIW_FREE(hash_table);
{
@@ -1839,15 +1991,18 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
j += blocklen;
blocklen = 5552;
}
- stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
- stbiw__sbpush(out, STBIW_UCHAR(s2));
- stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
- stbiw__sbpush(out, STBIW_UCHAR(s1));
+ _m3dstbiw___sbpush(out, STBIW_UCHAR(s2 >> 8));
+ _m3dstbiw___sbpush(out, STBIW_UCHAR(s2));
+ _m3dstbiw___sbpush(out, STBIW_UCHAR(s1 >> 8));
+ _m3dstbiw___sbpush(out, STBIW_UCHAR(s1));
}
- *out_len = stbiw__sbn(out);
- STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
- return (unsigned char *) stbiw__sbraw(out);
+ *out_len = _m3dstbiw___sbn(out);
+ STBIW_MEMMOVE(_m3dstbiw___sbraw(out), out, *out_len);
+ return (unsigned char *) _m3dstbiw___sbraw(out);
}
+#define stbi_zlib_compress _m3dstbi_zlib_compress
+#else
+unsigned char * _m3dstbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality);
#endif
#define M3D_CHUNKMAGIC(m, a,b,c,d) ((m)[0]==(a) && (m)[1]==(b) && (m)[2]==(c) && (m)[3]==(d))
@@ -1856,6 +2011,9 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
#include /* get sprintf */
#include /* sprintf and strtod cares about number locale */
#endif
+#ifdef M3D_PROFILING
+#include
+#endif
#if !defined(M3D_NOIMPORTER) && defined(M3D_ASCII)
/* helper functions for the ASCII parser */
@@ -1885,7 +2043,7 @@ static char *_m3d_gethex(char *s, uint32_t *ret)
static char *_m3d_getint(char *s, uint32_t *ret)
{
char *e = s;
- if(!s || !*s) return s;
+ if(!s || !*s || *s == '\r' || *s == '\n') return s;
for(; *e >= '0' && *e <= '9'; e++);
*ret = atoi(s);
return e;
@@ -1893,54 +2051,13 @@ static char *_m3d_getint(char *s, uint32_t *ret)
static char *_m3d_getfloat(char *s, M3D_FLOAT *ret)
{
char *e = s;
- if(!s || !*s) return s;
+ if(!s || !*s || *s == '\r' || *s == '\n') return s;
for(; *e == '-' || *e == '+' || *e == '.' || (*e >= '0' && *e <= '9') || *e == 'e' || *e == 'E'; e++);
*ret = (M3D_FLOAT)strtod(s, NULL);
return _m3d_findarg(e);
}
#endif
-#if !defined(M3D_NODUP) && (!defined(M3D_NONORMALS) || defined(M3D_EXPORTER))
-/* add vertex to list, only compare x,y,z */
-m3dv_t *_m3d_addnorm(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx)
-{
- uint32_t i;
- 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;
- if(vrtx) {
- for(i = 0; i < *numvrtx; i++)
- if(vrtx[i].x == v->x && vrtx[i].y == v->y && vrtx[i].z == v->z) { *idx = i; return vrtx; }
- }
- vrtx = (m3dv_t*)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t));
- memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t));
- vrtx[*numvrtx].color = 0;
- vrtx[*numvrtx].w = (M3D_FLOAT)1.0;
- *idx = *numvrtx;
- (*numvrtx)++;
- return vrtx;
-}
-#endif
#if !defined(M3D_NODUP) && (defined(M3D_ASCII) || defined(M3D_EXPORTER))
-m3ds_t *_m3d_addskin(m3ds_t *skin, uint32_t *numskin, m3ds_t *s, uint32_t *idx)
-{
- uint32_t i;
- M3D_FLOAT w = (M3D_FLOAT)0.0;
- for(i = 0; i < M3D_NUMBONE && s->weight[i] > (M3D_FLOAT)0.0; i++)
- w += s->weight[i];
- if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0)
- for(i = 0; i < M3D_NUMBONE && s->weight[i] > (M3D_FLOAT)0.0; i++)
- s->weight[i] /= w;
- if(skin) {
- for(i = 0; i < *numskin; i++)
- if(!memcmp(&skin[i], s, sizeof(m3ds_t))) { *idx = i; return skin; }
- }
- skin = (m3ds_t*)M3D_REALLOC(skin, ((*numskin) + 1) * sizeof(m3ds_t));
- memcpy(&skin[*numskin], s, sizeof(m3ds_t));
- *idx = *numskin;
- (*numskin)++;
- return skin;
-}
/* helper function to create safe strings */
char *_m3d_safestr(char *in, int morelines)
{
@@ -1973,7 +2090,7 @@ char *_m3d_safestr(char *in, int morelines)
}
for(; o > out && (*(o-1) == ' ' || *(o-1) == '\t' || *(o-1) == '\r' || *(o-1) == '\n'); o--);
*o = 0;
- out = (char*)M3D_REALLOC(out, (uint64_t)o - (uint64_t)out + 1);
+ out = (char*)M3D_REALLOC(out, (uintptr_t)o - (uintptr_t)out + 1);
}
return out;
}
@@ -1982,15 +2099,30 @@ char *_m3d_safestr(char *in, int morelines)
/* helper function to load and decode/generate a texture */
M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char *fn)
{
- unsigned int i, len = 0, w, h;
+ unsigned int i, len = 0;
unsigned char *buff = NULL;
char *fn2;
+#ifdef STBI__PNG_TYPE
+ unsigned int w, h;
stbi__context s;
stbi__result_info ri;
+#endif
+ /* do we have loaded this texture already? */
for(i = 0; i < model->numtexture; i++)
if(!strcmp(fn, model->texture[i].name)) return i;
- if(readfilecb) {
+ /* see if it's inlined in the model */
+ if(model->inlined) {
+ for(i = 0; i < model->numinlined; i++)
+ if(!strcmp(fn, model->inlined[i].name)) {
+ buff = model->inlined[i].data;
+ len = model->inlined[i].length;
+ freecb = NULL;
+ break;
+ }
+ }
+ /* try to load from external source */
+ if(!buff && readfilecb) {
i = strlen(fn);
if(i < 5 || fn[i - 4] != '.') {
fn2 = (char*)M3D_MALLOC(i + 5);
@@ -2003,32 +2135,30 @@ M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char
if(!buff)
buff = (*readfilecb)(fn, &len);
}
- if(!buff && model->inlined) {
- for(i = 0; i < model->numinlined; i++)
- if(!strcmp(fn, model->inlined[i].name)) {
- buff = model->inlined[i].data;
- len = model->inlined[i].length;
- freecb = NULL;
- break;
- }
- }
if(!buff) return (M3D_INDEX)-1U;
+ /* add to textures array */
i = model->numtexture++;
model->texture = (m3dtx_t*)M3D_REALLOC(model->texture, model->numtexture * sizeof(m3dtx_t));
if(!model->texture) {
if(freecb) (*freecb)(buff);
- model->errcode = M3D_ERR_ALLOC; return (M3D_INDEX)-1U;
+ model->errcode = M3D_ERR_ALLOC;
+ return (M3D_INDEX)-1U;
}
+ model->texture[i].name = fn;
model->texture[i].w = model->texture[i].h = 0; model->texture[i].d = NULL;
if(buff[0] == 0x89 && buff[1] == 'P' && buff[2] == 'N' && buff[3] == 'G') {
+#ifdef STBI__PNG_TYPE
s.read_from_callbacks = 0;
- s.img_buffer = s.img_buffer_original = (stbi_uc *) buff;
- s.img_buffer_end = s.img_buffer_original_end = (stbi_uc *) buff+len;
+ s.img_buffer = s.img_buffer_original = (unsigned char *) buff;
+ s.img_buffer_end = s.img_buffer_original_end = (unsigned char *) buff+len;
/* don't use model->texture[i].w directly, it's a uint16_t */
- w = h = 0;
- model->texture[i].d = (uint32_t*)stbi__png_load(&s, (int*)&w, (int*)&h, (int*)&len, STBI_rgb_alpha, &ri);
+ w = h = len = 0;
+ ri.bits_per_channel = 8;
+ model->texture[i].d = (uint8_t*)stbi__png_load(&s, (int*)&w, (int*)&h, (int*)&len, 0, &ri);
model->texture[i].w = w;
model->texture[i].h = h;
+ model->texture[i].f = (uint8_t)len;
+#endif
} else {
#ifdef M3D_TX_INTERP
if((model->errcode = M3D_TX_INTERP(fn, buff, len, &model->texture[i])) != M3D_SUCCESS) {
@@ -2041,13 +2171,8 @@ M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char
#endif
}
if(freecb) (*freecb)(buff);
- if(!model->texture[i].d) {
- M3D_FREE(model->texture[i].d);
+ if(!model->texture[i].d)
model->errcode = M3D_ERR_UNKIMG;
- model->numtexture--;
- return (M3D_INDEX)-1U;
- }
- model->texture[i].name = fn;
return i;
}
@@ -2085,8 +2210,8 @@ _inline static unsigned char *_m3d_getidx(unsigned char *data, char type, M3D_IN
{
switch(type) {
case 1: *idx = data[0] > 253 ? (int8_t)data[0] : data[0]; data++; break;
- case 2: *idx = (uint16_t)((data[1]<<8)|data[0]) > 65533 ? (int16_t)((data[1]<<8)|data[0]) : (uint16_t)((data[1]<<8)|data[0]); data += 2; break;
- case 4: *idx = (int32_t)((data[3]<<24)|(data[2]<<16)|(data[1]<<8)|data[0]); data += 4; break;
+ case 2: *idx = *((uint16_t*)data) > 65533 ? *((int16_t*)data) : *((uint16_t*)data); data += 2; break;
+ case 4: *idx = *((int32_t*)data); data += 4; break;
}
return data;
}
@@ -2144,10 +2269,6 @@ void _m3d_inv(M3D_FLOAT *m)
memcpy(m, &r, sizeof(r));
}
/* compose a coloumn major 4 x 4 matrix from vec3 position and vec4 orientation/rotation quaternion */
-#ifndef M3D_EPSILON
-/* carefully choosen for IEEE 754 don't change */
-#define M3D_EPSILON ((M3D_FLOAT)1e-7)
-#endif
void _m3d_mat(M3D_FLOAT *r, m3dv_t *p, m3dv_t *q)
{
if(q->x == (M3D_FLOAT)0.0 && q->y == (M3D_FLOAT)0.0 && q->z >=(M3D_FLOAT) 0.7071065 && q->z <= (M3D_FLOAT)0.7071075 &&
@@ -2190,30 +2311,40 @@ static M3D_FLOAT _m3d_rsq(M3D_FLOAT x)
m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d_t *mtllib)
{
unsigned char *end, *chunk, *buff, weights[8];
- unsigned int i, j, k, n, am, len = 0, reclen, offs;
- char *material;
-#ifndef M3D_NONORMALS
- unsigned int numnorm = 0;
- m3dv_t *norm = NULL, *v0, *v1, *v2, va, vb, vn;
- M3D_INDEX *ni = NULL, *vi = NULL;
-#endif
+ unsigned int i, j, k, l, n, am, len = 0, reclen, offs;
+ char *name, *lang;
+ float f;
m3d_t *model;
M3D_INDEX mi;
M3D_FLOAT w;
+ m3dcd_t *cd;
+ m3dtx_t *tx;
+ m3dh_t *h;
+ m3dm_t *m;
+ m3da_t *a;
+ m3di_t *t;
+#ifndef M3D_NONORMALS
+ char neednorm = 0;
+ m3dv_t *norm = NULL, *v0, *v1, *v2, va, vb;
+#endif
#ifndef M3D_NOANIMATION
M3D_FLOAT r[16];
#endif
- m3dtx_t *tx;
- m3dm_t *m;
- m3da_t *a;
+#if !defined(M3D_NOWEIGHTS) || !defined(M3D_NOANIMATION)
m3db_t *b;
- m3di_t *t;
+#endif
+#ifndef M3D_NOWEIGHTS
m3ds_t *sk;
+#endif
#ifdef M3D_ASCII
m3ds_t s;
M3D_INDEX bi[M3D_BONEMAXLEVEL+1], level;
const char *ol;
- char *ptr, *pe;
+ char *ptr, *pe, *fn;
+#endif
+#ifdef M3D_PROFILING
+ struct timeval tv0, tv1, tvd;
+ gettimeofday(&tv0, NULL);
#endif
if(!data || (!M3D_CHUNKMAGIC(data, '3','D','M','O')
@@ -2250,13 +2381,14 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
pe = _m3d_findnl(ptr);
model->scale = (float)strtod(ptr, NULL); ptr = pe;
if(model->scale <= (M3D_FLOAT)0.0) model->scale = (M3D_FLOAT)1.0;
- model->name = _m3d_safestr(ptr, 0); ptr = _m3d_findnl(ptr);
+ model->name = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr);
if(!*ptr) goto asciiend;
model->license = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr);
if(!*ptr) goto asciiend;
model->author = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr);
if(!*ptr) goto asciiend;
- model->desc = _m3d_safestr(ptr, 3);
+ if(*ptr != '\r' && *ptr != '\n')
+ model->desc = _m3d_safestr(ptr, 3);
while(*ptr) {
while(*ptr && *ptr!='\n') ptr++;
ptr++; if(*ptr=='\r') ptr++;
@@ -2270,6 +2402,17 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
/* make sure there's at least one data row */
pe = ptr; ptr = _m3d_findnl(ptr);
if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend;
+ /* Preview chunk */
+ if(!memcmp(pe, "Preview", 7)) {
+ if(readfilecb) {
+ pe = _m3d_safestr(ptr, 0);
+ if(!pe || !*pe) goto asciiend;
+ model->preview.data = (*readfilecb)(pe, &model->preview.length);
+ M3D_FREE(pe);
+ }
+ while(*ptr && *ptr != '\r' && *ptr != '\n')
+ ptr = _m3d_findnl(ptr);
+ } else
/* texture map chunk */
if(!memcmp(pe, "Textmap", 7)) {
if(model->tmap) { M3D_LOG("More texture map chunks, should be unique"); goto asciiend; }
@@ -2279,8 +2422,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
if(!model->tmap) goto memerr;
ptr = _m3d_getfloat(ptr, &model->tmap[i].u);
if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend;
- ptr = _m3d_getfloat(ptr, &model->tmap[i].v);
- if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend;
+ _m3d_getfloat(ptr, &model->tmap[i].v);
ptr = _m3d_findnl(ptr);
}
} else
@@ -2291,8 +2433,10 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
i = model->numvertex++;
model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t));
if(!model->vertex) goto memerr;
+ memset(&model->vertex[i], 0, sizeof(m3dv_t));
model->vertex[i].skinid = (M3D_INDEX)-1U;
model->vertex[i].color = 0;
+ model->vertex[i].w = (M3D_FLOAT)1.0;
ptr = _m3d_getfloat(ptr, &model->vertex[i].x);
if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend;
ptr = _m3d_getfloat(ptr, &model->vertex[i].y);
@@ -2300,7 +2444,6 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
ptr = _m3d_getfloat(ptr, &model->vertex[i].z);
if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend;
ptr = _m3d_getfloat(ptr, &model->vertex[i].w);
- if(model->vertex[i].w != 1.0) model->vertex[i].skinid = (M3D_INDEX)-2U;
if(!*ptr) goto asciiend;
if(*ptr == '#') {
ptr = _m3d_gethex(ptr, &model->vertex[i].color);
@@ -2308,7 +2451,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
}
/* parse skin */
memset(&s, 0, sizeof(m3ds_t));
- for(j = 0; j < M3D_NUMBONE && *ptr && *ptr != '\r' && *ptr != '\n'; j++) {
+ for(j = 0, w = (M3D_FLOAT)0.0; j < M3D_NUMBONE && *ptr && *ptr != '\r' && *ptr != '\n'; j++) {
ptr = _m3d_findarg(ptr);
if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend;
ptr = _m3d_getint(ptr, &k);
@@ -2316,12 +2459,25 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
if(*ptr == ':') {
ptr++;
ptr = _m3d_getfloat(ptr, &s.weight[j]);
+ w += s.weight[j];
} else if(!j)
s.weight[j] = (M3D_FLOAT)1.0;
if(!*ptr) goto asciiend;
}
if(s.boneid[0] != (M3D_INDEX)-1U && s.weight[0] > (M3D_FLOAT)0.0) {
- model->skin = _m3d_addskin(model->skin, &model->numskin, &s, &k);
+ if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0)
+ for(j = 0; j < M3D_NUMBONE && s.weight[j] > (M3D_FLOAT)0.0; j++)
+ s.weight[j] /= w;
+ k = -1U;
+ if(model->skin) {
+ for(j = 0; j < model->numskin; j++)
+ if(!memcmp(&model->skin[j], &s, sizeof(m3ds_t))) { k = j; break; }
+ }
+ if(k == -1U) {
+ k = model->numskin++;
+ model->skin = (m3ds_t*)M3D_REALLOC(model->skin, model->numskin * sizeof(m3ds_t));
+ memcpy(&model->skin[k], &s, sizeof(m3ds_t));
+ }
model->vertex[i].skinid = (M3D_INDEX)k;
}
ptr = _m3d_findnl(ptr);
@@ -2349,6 +2505,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
ptr = _m3d_findarg(ptr);
if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend;
model->bone[i].ori = (M3D_INDEX)k;
+ model->vertex[k].skinid = (M3D_INDEX)-2U;
pe = _m3d_safestr(ptr, 0);
if(!pe || !*pe) goto asciiend;
model->bone[i].name = pe;
@@ -2410,7 +2567,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
j = m->numprop++;
m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t));
if(!m->prop) goto memerr;
- m->prop[j].type = n;
+ m->prop[j].type = n + (k == m3dpf_map && n < 128 ? 128 : 0);
switch(k) {
case m3dpf_color: ptr = _m3d_gethex(ptr, &m->prop[j].value.color); break;
case m3dpf_uint8:
@@ -2439,7 +2596,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
}
if(!m->numprop) model->nummaterial--;
} else
- /* procedural, not implemented yet, skip chunk */
+ /* procedural */
if(!memcmp(pe, "Procedural", 10)) {
pe = _m3d_safestr(ptr, 0);
_m3d_getpr(model, readfilecb, freecb, pe);
@@ -2458,11 +2615,16 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
pe = _m3d_safestr(ptr, 0);
if(!pe || !*pe) goto asciiend;
for(j = 0; j < model->nummaterial; j++)
- if(!strcmp(pe, model->material[j].name)) {
- mi = (M3D_INDEX)j;
- break;
- }
- M3D_FREE(pe);
+ if(!strcmp(pe, model->material[j].name)) { mi = (M3D_INDEX)j; break; }
+ if(mi == (M3D_INDEX)-1U && !(model->flags & M3D_FLG_MTLLIB)) {
+ mi = model->nummaterial++;
+ model->material = (m3dm_t*)M3D_REALLOC(model->material, model->nummaterial * sizeof(m3dm_t));
+ if(!model->material) goto memerr;
+ model->material[mi].name = pe;
+ model->material[mi].numprop = 1;
+ model->material[mi].prop = NULL;
+ } else
+ M3D_FREE(pe);
}
} else {
i = model->numface++;
@@ -2492,12 +2654,146 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
if(!*ptr) goto asciiend;
}
}
+#ifndef M3D_NONORMALS
+ if(model->face[i].normal[j] == (M3D_INDEX)-1U) neednorm = 1;
+#endif
ptr = _m3d_findarg(ptr);
}
}
ptr = _m3d_findnl(ptr);
}
} else
+ /* mathematical shape */
+ if(!memcmp(pe, "Shape", 5)) {
+ pe = _m3d_findarg(pe);
+ if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend;
+ pe = _m3d_safestr(pe, 0);
+ if(!pe || !*pe) goto asciiend;
+ i = model->numshape++;
+ model->shape = (m3dh_t*)M3D_REALLOC(model->shape, model->numshape * sizeof(m3ds_t));
+ if(!model->shape) goto memerr;
+ h = &model->shape[i];
+ h->name = pe;
+ h->group = (M3D_INDEX)-1U;
+ h->numcmd = 0;
+ h->cmd = NULL;
+ while(*ptr && *ptr != '\r' && *ptr != '\n') {
+ if(!memcmp(ptr, "group", 5)) {
+ ptr = _m3d_findarg(ptr);
+ ptr = _m3d_getint(ptr, &h->group);
+ ptr = _m3d_findnl(ptr);
+ if(h->group != (M3D_INDEX)-1U && h->group >= model->numbone) {
+ M3D_LOG("Unknown bone id as shape group in shape");
+ M3D_LOG(pe);
+ h->group = (M3D_INDEX)-1U;
+ model->errcode = M3D_ERR_SHPE;
+ }
+ continue;
+ }
+ for(cd = NULL, k = 0; k < (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])); k++) {
+ j = strlen(m3d_commandtypes[k].key);
+ if(!memcmp(ptr, m3d_commandtypes[k].key, j) && (ptr[j] == ' ' || ptr[j] == '\r' || ptr[j] == '\n'))
+ { cd = &m3d_commandtypes[k]; break; }
+ }
+ if(cd) {
+ j = h->numcmd++;
+ h->cmd = (m3dc_t*)M3D_REALLOC(h->cmd, h->numcmd * sizeof(m3dc_t));
+ if(!h->cmd) goto memerr;
+ h->cmd[j].type = k;
+ h->cmd[j].arg = (uint32_t*)M3D_MALLOC(cd->p * sizeof(uint32_t));
+ if(!h->cmd[j].arg) goto memerr;
+ memset(h->cmd[j].arg, 0, cd->p * sizeof(uint32_t));
+ for(k = n = 0, l = cd->p; k < l; k++) {
+ ptr = _m3d_findarg(ptr);
+ if(!*ptr) goto asciiend;
+ if(*ptr == '[') {
+ ptr = _m3d_findarg(ptr + 1);
+ if(!*ptr) goto asciiend;
+ }
+ if(*ptr == ']' || *ptr == '\r' || *ptr == '\n') break;
+ switch(cd->a[((k - n) % (cd->p - n)) + n]) {
+ case m3dcp_mi_t:
+ mi = (M3D_INDEX)-1U;
+ if(*ptr != '\r' && *ptr != '\n') {
+ pe = _m3d_safestr(ptr, 0);
+ if(!pe || !*pe) goto asciiend;
+ for(n = 0; n < model->nummaterial; n++)
+ if(!strcmp(pe, model->material[n].name)) { mi = (M3D_INDEX)n; break; }
+ if(mi == (M3D_INDEX)-1U && !(model->flags & M3D_FLG_MTLLIB)) {
+ mi = model->nummaterial++;
+ model->material = (m3dm_t*)M3D_REALLOC(model->material,
+ model->nummaterial * sizeof(m3dm_t));
+ if(!model->material) goto memerr;
+ model->material[mi].name = pe;
+ model->material[mi].numprop = 1;
+ model->material[mi].prop = NULL;
+ } else
+ M3D_FREE(pe);
+ }
+ h->cmd[j].arg[k] = mi;
+ break;
+ case m3dcp_vc_t:
+ _m3d_getfloat(ptr, &w);
+ h->cmd[j].arg[k] = *((uint32_t*)&w);
+ break;
+ case m3dcp_va_t:
+ ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]);
+ n = k + 1; l += (h->cmd[j].arg[k] - 1) * (cd->p - k - 1);
+ h->cmd[j].arg = (uint32_t*)M3D_REALLOC(h->cmd[j].arg, l * sizeof(uint32_t));
+ if(!h->cmd[j].arg) goto memerr;
+ memset(&h->cmd[j].arg[k + 1], 0, (l - k - 1) * sizeof(uint32_t));
+ break;
+ case m3dcp_qi_t:
+ ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]);
+ model->vertex[h->cmd[i].arg[k]].skinid = (M3D_INDEX)-2U;
+ break;
+ default:
+ ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]);
+ break;
+ }
+ }
+ } else {
+ M3D_LOG("Unknown shape command in");
+ M3D_LOG(h->name);
+ model->errcode = M3D_ERR_UNKCMD;
+ }
+ ptr = _m3d_findnl(ptr);
+ }
+ if(!h->numcmd) model->numshape--;
+ } else
+ /* annotation labels */
+ if(!memcmp(pe, "Labels", 6)) {
+ pe = _m3d_findarg(pe);
+ if(!*pe) goto asciiend;
+ if(*pe == '\r' || *pe == '\n') pe = NULL;
+ else pe = _m3d_safestr(pe, 0);
+ k = 0; fn = NULL;
+ while(*ptr && *ptr != '\r' && *ptr != '\n') {
+ if(*ptr == 'c') {
+ ptr = _m3d_findarg(ptr);
+ if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend;
+ ptr = _m3d_gethex(ptr, &k);
+ } else
+ if(*ptr == 'l') {
+ ptr = _m3d_findarg(ptr);
+ if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend;
+ fn = _m3d_safestr(ptr, 2);
+ } else {
+ i = model->numlabel++;
+ model->label = (m3dl_t*)M3D_REALLOC(model->label, model->numlabel * sizeof(m3dl_t));
+ if(!model->label) goto memerr;
+ model->label[i].name = pe;
+ model->label[i].lang = fn;
+ model->label[i].color = k;
+ ptr = _m3d_getint(ptr, &j);
+ model->label[i].vertexid = (M3D_INDEX)j;
+ ptr = _m3d_findarg(ptr);
+ if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend;
+ model->label[i].text = _m3d_safestr(ptr, 2);
+ }
+ ptr = _m3d_findnl(ptr);
+ }
+ } else
/* action */
if(!memcmp(pe, "Action", 6)) {
pe = _m3d_findarg(pe);
@@ -2548,6 +2844,33 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
ptr = _m3d_getint(ptr, &k);
if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend;
a->frame[i].transform[j].ori = (M3D_INDEX)k;
+ model->vertex[k].skinid = (M3D_INDEX)-2U;
+ }
+ ptr = _m3d_findnl(ptr);
+ }
+ } else
+ /* inlined assets chunk */
+ if(!memcmp(pe, "Assets", 6)) {
+ while(*ptr && *ptr != '\r' && *ptr != '\n') {
+ if(readfilecb) {
+ pe = _m3d_safestr(ptr, 2);
+ if(!pe || !*pe) goto asciiend;
+ i = model->numinlined++;
+ model->inlined = (m3di_t*)M3D_REALLOC(model->inlined, model->numinlined * sizeof(m3di_t));
+ if(!model->inlined) goto memerr;
+ t = &model->inlined[i];
+ model->inlined[i].data = (*readfilecb)(pe, &model->inlined[i].length);
+ if(model->inlined[i].data) {
+ fn = strrchr(pe, '.');
+ if(fn && (fn[1] == 'p' || fn[1] == 'P') && (fn[2] == 'n' || fn[2] == 'N') &&
+ (fn[3] == 'g' || fn[3] == 'G')) *fn = 0;
+ fn = strrchr(pe, '/');
+ if(!fn) fn = strrchr(pe, '\\');
+ if(!fn) fn = pe; else fn++;
+ model->inlined[i].name = _m3d_safestr(fn, 0);
+ } else
+ model->numinlined--;
+ M3D_FREE(pe);
}
ptr = _m3d_findnl(ptr);
}
@@ -2557,19 +2880,19 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d
pe = _m3d_findarg(pe);
if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend;
buff = (unsigned char*)_m3d_findnl(ptr);
- k = ((uint32_t)((uint64_t)buff - (uint64_t)ptr) / 3) + 1;
- i = model->numunknown++;
- model->unknown = (m3dchunk_t**)M3D_REALLOC(model->unknown, model->numunknown * sizeof(m3dchunk_t*));
- if(!model->unknown) goto memerr;
- model->unknown[i] = (m3dchunk_t*)M3D_MALLOC(k + sizeof(m3dchunk_t));
- if(!model->unknown[i]) goto memerr;
- memcpy(&model->unknown[i]->magic, pe, 4);
- model->unknown[i]->length = sizeof(m3dchunk_t);
- pe = (char*)model->unknown[i] + sizeof(m3dchunk_t);
+ k = ((uint32_t)((uintptr_t)buff - (uintptr_t)ptr) / 3) + 1;
+ i = model->numextra++;
+ model->extra = (m3dchunk_t**)M3D_REALLOC(model->extra, model->numextra * sizeof(m3dchunk_t*));
+ if(!model->extra) goto memerr;
+ model->extra[i] = (m3dchunk_t*)M3D_MALLOC(k + sizeof(m3dchunk_t));
+ if(!model->extra[i]) goto memerr;
+ memcpy(&model->extra[i]->magic, pe, 4);
+ model->extra[i]->length = sizeof(m3dchunk_t);
+ pe = (char*)model->extra[i] + sizeof(m3dchunk_t);
while(*ptr && *ptr != '\r' && *ptr != '\n') {
ptr = _m3d_gethex(ptr, &k);
*pe++ = (uint8_t)k;
- model->unknown[i]->length++;
+ model->extra[i]->length++;
}
} else
goto asciiend;
@@ -2579,14 +2902,12 @@ asciiend:
setlocale(LC_NUMERIC, ol);
goto postprocess;
}
- /* Binary variant */
#endif
+ /* Binary variant */
if(!M3D_CHUNKMAGIC(data + 8, 'H','E','A','D')) {
- stbi__g_failure_reason = "Corrupt file";
buff = (unsigned char *)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)data+8, ((m3dchunk_t*)data)->length-8,
4096, (int*)&len, 1);
if(!buff || !len || !M3D_CHUNKMAGIC(buff, 'H','E','A','D')) {
- M3D_LOG(stbi__g_failure_reason);
if(buff) M3D_FREE(buff);
M3D_FREE(model);
return NULL;
@@ -2594,6 +2915,14 @@ asciiend:
buff = (unsigned char*)M3D_REALLOC(buff, len);
model->flags |= M3D_FLG_FREERAW; /* mark that we have to free the raw buffer */
data = buff;
+#ifdef M3D_PROFILING
+ gettimeofday(&tv1, NULL);
+ tvd.tv_sec = tv1.tv_sec - tv0.tv_sec;
+ tvd.tv_usec = tv1.tv_usec - tv0.tv_usec;
+ if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
+ printf(" Deflate model %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec);
+ memcpy(&tv0, &tv1, sizeof(struct timeval));
+#endif
} else {
len = ((m3dhdr_t*)data)->length;
data += 8;
@@ -2622,11 +2951,15 @@ asciiend:
model->bi_s = 1 << ((model->raw->types >>10) & 3); /* bone index size */
model->nb_s = 1 << ((model->raw->types >>12) & 3); /* number of bones per vertex */
model->sk_s = 1 << ((model->raw->types >>14) & 3); /* skin index size */
- model->fi_s = 1 << ((model->raw->types >>16) & 3); /* frame counter size */
+ model->fc_s = 1 << ((model->raw->types >>16) & 3); /* frame counter size */
+ model->hi_s = 1 << ((model->raw->types >>18) & 3); /* shape index size */
+ model->fi_s = 1 << ((model->raw->types >>20) & 3); /* face index size */
if(model->ci_s == 8) model->ci_s = 0; /* optional indices */
if(model->ti_s == 8) model->ti_s = 0;
if(model->bi_s == 8) model->bi_s = 0;
if(model->sk_s == 8) model->sk_s = 0;
+ if(model->fc_s == 8) model->fc_s = 0;
+ if(model->hi_s == 8) model->hi_s = 0;
if(model->fi_s == 8) model->fi_s = 0;
/* variable limit checks */
@@ -2635,7 +2968,7 @@ asciiend:
model->errcode = M3D_ERR_TRUNC;
}
if(sizeof(M3D_INDEX) == 2 && (model->vi_s > 2 || model->si_s > 2 || model->ci_s > 2 || model->ti_s > 2 ||
- model->bi_s > 2 || model->sk_s > 2 || model->fi_s > 2)) {
+ model->bi_s > 2 || model->sk_s > 2 || model->fc_s > 2 || model->hi_s > 2 || model->fi_s > 2)) {
M3D_LOG("32 bit indices not supported, unable to load model");
M3D_FREE(model);
return NULL;
@@ -2646,7 +2979,7 @@ asciiend:
return NULL;
}
if(model->nb_s > M3D_NUMBONE) {
- M3D_LOG("Model has more bones per vertex than importer supports");
+ M3D_LOG("Model has more bones per vertex than what importer was configured to support");
model->errcode = M3D_ERR_TRUNC;
}
@@ -2692,6 +3025,11 @@ memerr: M3D_LOG("Out of memory");
chunk += len;
len -= sizeof(m3dchunk_t);
+ /* preview chunk */
+ if(M3D_CHUNKMAGIC(data, 'P','R','V','W') && len > 0) {
+ model->preview.length = len;
+ model->preview.data = data + sizeof(m3dchunk_t);
+ } else
/* color map */
if(M3D_CHUNKMAGIC(data, 'C','M','A','P')) {
M3D_LOG("Color map");
@@ -2751,10 +3089,10 @@ memerr: M3D_LOG("Out of memory");
data += 4;
break;
case 2:
- model->vertex[i].x = (M3D_FLOAT)((int16_t)((data[1]<<8)|data[0])) / 32767;
- model->vertex[i].y = (M3D_FLOAT)((int16_t)((data[3]<<8)|data[2])) / 32767;
- model->vertex[i].z = (M3D_FLOAT)((int16_t)((data[5]<<8)|data[4])) / 32767;
- model->vertex[i].w = (M3D_FLOAT)((int16_t)((data[7]<<8)|data[6])) / 32767;
+ model->vertex[i].x = (M3D_FLOAT)(*((int16_t*)(data+0))) / 32767;
+ model->vertex[i].y = (M3D_FLOAT)(*((int16_t*)(data+2))) / 32767;
+ model->vertex[i].z = (M3D_FLOAT)(*((int16_t*)(data+4))) / 32767;
+ model->vertex[i].w = (M3D_FLOAT)(*((int16_t*)(data+6))) / 32767;
data += 8;
break;
case 4:
@@ -2797,15 +3135,6 @@ memerr: M3D_LOG("Out of memory");
}
model->numskin = 0;
data = _m3d_getidx(data, model->sk_s, &model->numskin);
- if(model->numskin) {
- model->skin = (m3ds_t*)M3D_MALLOC(model->numskin * sizeof(m3ds_t));
- if(!model->skin) goto memerr;
- for(i = 0; i < model->numskin; i++)
- for(j = 0; j < M3D_NUMBONE; j++) {
- model->skin[i].boneid[j] = (M3D_INDEX)-1U;
- model->skin[i].weight[j] = (M3D_FLOAT)0.0;
- }
- }
/* read bone hierarchy */
for(i = 0; i < model->numbone; i++) {
data = _m3d_getidx(data, model->bi_s, &model->bone[i].parent);
@@ -2816,41 +3145,55 @@ memerr: M3D_LOG("Out of memory");
model->bone[i].weight = NULL;
}
/* read skin definitions */
- for(i = 0; data < chunk && i < model->numskin; i++) {
- memset(&weights, 0, sizeof(weights));
- if(model->nb_s == 1) weights[0] = 255;
- else {
- memcpy(&weights, data, model->nb_s);
- data += model->nb_s;
- }
- for(j = 0; j < (unsigned int)model->nb_s; j++) {
- if(weights[j]) {
- if(j >= M3D_NUMBONE)
- data += model->bi_s;
- else {
- model->skin[i].weight[j] = (M3D_FLOAT)(weights[j]) / 255;
- data = _m3d_getidx(data, model->bi_s, &model->skin[i].boneid[j]);
+ if(model->numskin) {
+ model->skin = (m3ds_t*)M3D_MALLOC(model->numskin * sizeof(m3ds_t));
+ if(!model->skin) goto memerr;
+ for(i = 0; data < chunk && i < model->numskin; i++) {
+ for(j = 0; j < M3D_NUMBONE; j++) {
+ model->skin[i].boneid[j] = (M3D_INDEX)-1U;
+ model->skin[i].weight[j] = (M3D_FLOAT)0.0;
+ }
+ memset(&weights, 0, sizeof(weights));
+ if(model->nb_s == 1) weights[0] = 255;
+ else {
+ memcpy(&weights, data, model->nb_s);
+ data += model->nb_s;
+ }
+ for(j = 0, w = (M3D_FLOAT)0.0; j < (unsigned int)model->nb_s; j++) {
+ if(weights[j]) {
+ if(j >= M3D_NUMBONE)
+ data += model->bi_s;
+ else {
+ model->skin[i].weight[j] = (M3D_FLOAT)(weights[j]) / 255;
+ w += model->skin[i].weight[j];
+ data = _m3d_getidx(data, model->bi_s, &model->skin[i].boneid[j]);
+ }
}
}
+ /* this can occur if model has more bones than what the importer is configured to handle */
+ if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) {
+ for(j = 0; j < M3D_NUMBONE; j++)
+ model->skin[i].weight[j] /= w;
+ }
}
}
} else
/* material */
if(M3D_CHUNKMAGIC(data, 'M','T','R','L')) {
data += sizeof(m3dchunk_t);
- M3D_GETSTR(material);
+ M3D_GETSTR(name);
M3D_LOG("Material");
- M3D_LOG(material);
+ M3D_LOG(name);
if(model->ci_s < 4 && !model->numcmap) model->errcode = M3D_ERR_CMAP;
for(i = 0; i < model->nummaterial; i++)
- if(!strcmp(material, model->material[i].name)) {
+ if(!strcmp(name, model->material[i].name)) {
model->errcode = M3D_ERR_MTRL;
M3D_LOG("Multiple definitions for material");
- M3D_LOG(material);
- material = NULL;
+ M3D_LOG(name);
+ name = NULL;
break;
}
- if(material) {
+ if(name) {
i = model->nummaterial++;
if(model->flags & M3D_FLG_MTLLIB) {
m = model->material;
@@ -2870,9 +3213,8 @@ memerr: M3D_LOG("Out of memory");
}
m = &model->material[i];
m->numprop = 0;
- m->prop = NULL;
- m->name = material;
- m->prop = (m3dp_t*)M3D_REALLOC(m->prop, (len / 2) * sizeof(m3dp_t));
+ m->name = name;
+ m->prop = (m3dp_t*)M3D_MALLOC((len / 2) * sizeof(m3dp_t));
if(!m->prop) goto memerr;
while(data < chunk) {
i = m->numprop++;
@@ -2899,12 +3241,12 @@ memerr: M3D_LOG("Out of memory");
case m3dpf_float: m->prop[i].value.fnum = *((float*)data); data += 4; break;
case m3dpf_map:
- M3D_GETSTR(material);
- m->prop[i].value.textureid = _m3d_gettx(model, readfilecb, freecb, material);
+ M3D_GETSTR(name);
+ m->prop[i].value.textureid = _m3d_gettx(model, readfilecb, freecb, name);
if(model->errcode == M3D_ERR_ALLOC) goto memerr;
if(m->prop[i].value.textureid == (M3D_INDEX)-1U) {
M3D_LOG("Texture not found");
- M3D_LOG(material);
+ M3D_LOG(m->name);
m->numprop--;
}
break;
@@ -2924,10 +3266,10 @@ memerr: M3D_LOG("Out of memory");
/* face */
if(M3D_CHUNKMAGIC(data, 'P','R','O','C')) {
/* procedural surface */
- M3D_GETSTR(material);
+ M3D_GETSTR(name);
M3D_LOG("Procedural surface");
- M3D_LOG(material);
- _m3d_getpr(model, readfilecb, freecb, material);
+ M3D_LOG(name);
+ _m3d_getpr(model, readfilecb, freecb, name);
} else
if(M3D_CHUNKMAGIC(data, 'M','E','S','H')) {
M3D_LOG("Mesh data");
@@ -2942,10 +3284,10 @@ memerr: M3D_LOG("Out of memory");
if(!n) {
/* use material */
mi = (M3D_INDEX)-1U;
- M3D_GETSTR(material);
- if(material) {
+ M3D_GETSTR(name);
+ if(name) {
for(j = 0; j < model->nummaterial; j++)
- if(!strcmp(material, model->material[j].name)) {
+ if(!strcmp(name, model->material[j].name)) {
mi = (M3D_INDEX)j;
break;
}
@@ -2971,10 +3313,124 @@ memerr: M3D_LOG("Out of memory");
/* normal */
if(k & 2)
data = _m3d_getidx(data, model->vi_s, &model->face[i].normal[j]);
+#ifndef M3D_NONORMALS
+ if(model->face[i].normal[j] == (M3D_INDEX)-1U) neednorm = 1;
+#endif
}
}
model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t));
} else
+ if(M3D_CHUNKMAGIC(data, 'S','H','P','E')) {
+ /* mathematical shape */
+ data += sizeof(m3dchunk_t);
+ M3D_GETSTR(name);
+ M3D_LOG("Mathematical Shape");
+ M3D_LOG(name);
+ i = model->numshape++;
+ model->shape = (m3dh_t*)M3D_REALLOC(model->shape, model->numshape * sizeof(m3dh_t));
+ if(!model->shape) goto memerr;
+ h = &model->shape[i];
+ h->numcmd = 0;
+ h->cmd = NULL;
+ h->name = name;
+ h->group = (M3D_INDEX)-1U;
+ data = _m3d_getidx(data, model->bi_s, &h->group);
+ if(h->group != (M3D_INDEX)-1U && h->group >= model->numbone) {
+ M3D_LOG("Unknown bone id as shape group in shape");
+ M3D_LOG(name);
+ h->group = (M3D_INDEX)-1U;
+ model->errcode = M3D_ERR_SHPE;
+ }
+ while(data < chunk) {
+ i = h->numcmd++;
+ h->cmd = (m3dc_t*)M3D_REALLOC(h->cmd, h->numcmd * sizeof(m3dc_t));
+ if(!h->cmd) goto memerr;
+ h->cmd[i].type = *data++;
+ if(h->cmd[i].type & 0x80) {
+ h->cmd[i].type &= 0x7F;
+ h->cmd[i].type |= (*data++ << 7);
+ }
+ if(h->cmd[i].type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0]))) {
+ M3D_LOG("Unknown shape command in");
+ M3D_LOG(h->name);
+ model->errcode = M3D_ERR_UNKCMD;
+ break;
+ }
+ cd = &m3d_commandtypes[h->cmd[i].type];
+ h->cmd[i].arg = (uint32_t*)M3D_MALLOC(cd->p * sizeof(uint32_t));
+ if(!h->cmd[i].arg) goto memerr;
+ memset(h->cmd[i].arg, 0, cd->p * sizeof(uint32_t));
+ for(k = n = 0, l = cd->p; k < l; k++)
+ switch(cd->a[((k - n) % (cd->p - n)) + n]) {
+ case m3dcp_mi_t:
+ h->cmd[i].arg[k] = -1U;
+ M3D_GETSTR(name);
+ if(name) {
+ for(n = 0; n < model->nummaterial; n++)
+ if(!strcmp(name, model->material[n].name)) {
+ h->cmd[i].arg[k] = n;
+ break;
+ }
+ if(h->cmd[i].arg[k] == -1U) model->errcode = M3D_ERR_MTRL;
+ }
+ break;
+ case m3dcp_vc_t:
+ f = 0.0f;
+ switch(model->vc_s) {
+ case 1: f = (float)((int8_t)data[0]) / 127; break;
+ case 2: f = (float)(*((int16_t*)(data+0))) / 32767; break;
+ case 4: f = (float)(*((float*)(data+0))); break;
+ case 8: f = (float)(*((double*)(data+0))); break;
+ }
+ h->cmd[i].arg[k] = *((uint32_t*)&f);
+ data += model->vc_s;
+ break;
+ case m3dcp_hi_t: data = _m3d_getidx(data, model->hi_s, &h->cmd[i].arg[k]); break;
+ case m3dcp_fi_t: data = _m3d_getidx(data, model->fi_s, &h->cmd[i].arg[k]); break;
+ case m3dcp_ti_t: data = _m3d_getidx(data, model->ti_s, &h->cmd[i].arg[k]); break;
+ case m3dcp_qi_t:
+ case m3dcp_vi_t: data = _m3d_getidx(data, model->vi_s, &h->cmd[i].arg[k]); break;
+ case m3dcp_i1_t: data = _m3d_getidx(data, 1, &h->cmd[i].arg[k]); break;
+ case m3dcp_i2_t: data = _m3d_getidx(data, 2, &h->cmd[i].arg[k]); break;
+ case m3dcp_i4_t: data = _m3d_getidx(data, 4, &h->cmd[i].arg[k]); break;
+ case m3dcp_va_t: data = _m3d_getidx(data, 4, &h->cmd[i].arg[k]);
+ n = k + 1; l += (h->cmd[i].arg[k] - 1) * (cd->p - k - 1);
+ h->cmd[i].arg = (uint32_t*)M3D_REALLOC(h->cmd[i].arg, l * sizeof(uint32_t));
+ if(!h->cmd[i].arg) goto memerr;
+ memset(&h->cmd[i].arg[k + 1], 0, (l - k - 1) * sizeof(uint32_t));
+ break;
+ }
+ }
+ } else
+ /* annotation label list */
+ if(M3D_CHUNKMAGIC(data, 'L','B','L','S')) {
+ data += sizeof(m3dchunk_t);
+ M3D_GETSTR(name);
+ M3D_GETSTR(lang);
+ M3D_LOG("Label list");
+ if(name) { M3D_LOG(name); }
+ if(lang) { M3D_LOG(lang); }
+ if(model->ci_s && model->ci_s < 4 && !model->cmap) model->errcode = M3D_ERR_CMAP;
+ k = 0;
+ switch(model->ci_s) {
+ case 1: k = model->cmap ? model->cmap[data[0]] : 0; data++; break;
+ case 2: k = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break;
+ case 4: k = *((uint32_t*)data); data += 4; break;
+ /* case 8: break; */
+ }
+ reclen = model->vi_s + model->si_s;
+ i = model->numlabel; model->numlabel += len / reclen;
+ model->label = (m3dl_t*)M3D_REALLOC(model->label, model->numlabel * sizeof(m3dl_t));
+ if(!model->label) goto memerr;
+ memset(&model->label[i], 0, (model->numlabel - i) * sizeof(m3dl_t));
+ for(; data < chunk && i < model->numlabel; i++) {
+ model->label[i].name = name;
+ model->label[i].lang = lang;
+ model->label[i].color = k;
+ data = _m3d_getidx(data, model->vi_s, &model->label[i].vertexid);
+ M3D_GETSTR(model->label[i].text);
+ }
+ } else
/* action */
if(M3D_CHUNKMAGIC(data, 'A','C','T','N')) {
M3D_LOG("Action");
@@ -2995,7 +3451,7 @@ memerr: M3D_LOG("Out of memory");
for(i = 0; data < chunk && i < a->numframe; i++) {
a->frame[i].msec = *((uint32_t*)data); data += 4;
a->frame[i].numtransform = 0; a->frame[i].transform = NULL;
- data = _m3d_getidx(data, model->fi_s, &a->frame[i].numtransform);
+ data = _m3d_getidx(data, model->fc_s, &a->frame[i].numtransform);
if(a->frame[i].numtransform > 0) {
a->frame[i].transform = (m3dtr_t*)M3D_MALLOC(a->frame[i].numtransform * sizeof(m3dtr_t));
for(j = 0; j < a->frame[i].numtransform; j++) {
@@ -3007,10 +3463,10 @@ memerr: M3D_LOG("Out of memory");
}
}
} else {
- i = model->numunknown++;
- model->unknown = (m3dchunk_t**)M3D_REALLOC(model->unknown, model->numunknown * sizeof(m3dchunk_t*));
- if(!model->unknown) goto memerr;
- model->unknown[i] = (m3dchunk_t*)data;
+ i = model->numextra++;
+ model->extra = (m3dchunk_t**)M3D_REALLOC(model->extra, model->numextra * sizeof(m3dchunk_t*));
+ if(!model->extra) goto memerr;
+ model->extra[i] = (m3dchunk_t*)data;
}
}
/* calculate normals, normalize skin weights, create bone/vertex cross-references and calculate transform matrices */
@@ -3018,59 +3474,64 @@ memerr: M3D_LOG("Out of memory");
postprocess:
#endif
if(model) {
+ M3D_LOG("Post-process");
+#ifdef M3D_PROFILING
+ gettimeofday(&tv1, NULL);
+ tvd.tv_sec = tv1.tv_sec - tv0.tv_sec;
+ tvd.tv_usec = tv1.tv_usec - tv0.tv_usec;
+ if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
+ printf(" Parsing chunks %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec);
+#endif
#ifndef M3D_NONORMALS
- if(model->numface && model->face) {
- memset(&vn, 0, sizeof(m3dv_t));
+ if(model->numface && model->face && neednorm) {
/* if they are missing, calculate triangle normals into a temporary buffer */
- for(i = numnorm = 0; i < model->numface; i++)
+ norm = (m3dv_t*)M3D_MALLOC(model->numface * sizeof(m3dv_t));
+ if(!norm) goto memerr;
+ for(i = 0, n = model->numvertex; i < model->numface; i++)
if(model->face[i].normal[0] == -1U) {
- v0 = &model->vertex[model->face[i].vertex[0]]; v1 = &model->vertex[model->face[i].vertex[1]];
+ v0 = &model->vertex[model->face[i].vertex[0]];
+ v1 = &model->vertex[model->face[i].vertex[1]];
v2 = &model->vertex[model->face[i].vertex[2]];
va.x = v1->x - v0->x; va.y = v1->y - v0->y; va.z = v1->z - v0->z;
vb.x = v2->x - v0->x; vb.y = v2->y - v0->y; vb.z = v2->z - v0->z;
- vn.x = (va.y * vb.z) - (va.z * vb.y);
- vn.y = (va.z * vb.x) - (va.x * vb.z);
- vn.z = (va.x * vb.y) - (va.y * vb.x);
- w = _m3d_rsq((vn.x * vn.x) + (vn.y * vn.y) + (vn.z * vn.z));
- vn.x *= w; vn.y *= w; vn.z *= w;
- norm = _m3d_addnorm(norm, &numnorm, &vn, &j);
- if(!ni) {
- ni = (M3D_INDEX*)M3D_MALLOC(model->numface * sizeof(M3D_INDEX));
- if(!ni) goto memerr;
- }
- ni[i] = j;
+ v0 = &norm[i];
+ v0->x = (va.y * vb.z) - (va.z * vb.y);
+ v0->y = (va.z * vb.x) - (va.x * vb.z);
+ v0->z = (va.x * vb.y) - (va.y * vb.x);
+ w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z));
+ v0->x *= w; v0->y *= w; v0->z *= w;
+ model->face[i].normal[0] = model->face[i].vertex[0] + n;
+ model->face[i].normal[1] = model->face[i].vertex[1] + n;
+ model->face[i].normal[2] = model->face[i].vertex[2] + n;
}
- if(ni && norm) {
- vi = (M3D_INDEX*)M3D_MALLOC(model->numvertex * sizeof(M3D_INDEX));
- if(!vi) goto memerr;
- /* for each vertex, take the average of the temporary normals and use that */
- for(i = 0, n = model->numvertex; i < n; i++) {
- memset(&vn, 0, sizeof(m3dv_t));
- for(j = 0; j < model->numface; j++)
- for(k = 0; k < 3; k++)
- if(model->face[j].vertex[k] == i) {
- vn.x += norm[ni[j]].x;
- vn.y += norm[ni[j]].y;
- vn.z += norm[ni[j]].z;
- }
- w = _m3d_rsq((vn.x * vn.x) + (vn.y * vn.y) + (vn.z * vn.z));
- vn.x *= w; vn.y *= w; vn.z *= w;
- vn.skinid = -1U;
- model->vertex = _m3d_addnorm(model->vertex, &model->numvertex, &vn, &vi[i]);
+ /* this is the fast way, we don't care if a normal is repeated in model->vertex */
+ M3D_LOG("Generating normals");
+ model->flags |= M3D_FLG_GENNORM;
+ model->numvertex <<= 1;
+ model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t));
+ if(!model->vertex) goto memerr;
+ memset(&model->vertex[n], 0, n * sizeof(m3dv_t));
+ for(i = 0; i < model->numface; i++)
+ for(j = 0; j < 3; j++) {
+ v0 = &model->vertex[model->face[i].vertex[j] + n];
+ v0->x += norm[i].x;
+ v0->y += norm[i].y;
+ v0->z += norm[i].z;
}
- for(j = 0; j < model->numface; j++)
- for(k = 0; k < 3; k++)
- model->face[j].normal[k] = vi[model->face[j].vertex[k]];
- M3D_FREE(norm);
- M3D_FREE(ni);
- M3D_FREE(vi);
+ /* for each vertex, take the average of the temporary normals and use that */
+ for(i = 0, v0 = &model->vertex[n]; i < n; i++, v0++) {
+ w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z));
+ v0->x *= w; v0->y *= w; v0->z *= w;
+ v0->skinid = -1U;
}
+ M3D_FREE(norm);
}
#endif
if(model->numbone && model->bone && model->numskin && model->skin && model->numvertex && model->vertex) {
#ifndef M3D_NOWEIGHTS
+ M3D_LOG("Generating weight cross-reference");
for(i = 0; i < model->numvertex; i++) {
- if(model->vertex[i].skinid < M3D_INDEXMAX) {
+ if(model->vertex[i].skinid < model->numskin) {
sk = &model->skin[model->vertex[i].skinid];
w = (M3D_FLOAT)0.0;
for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != (M3D_INDEX)-1U && sk->weight[j] > (M3D_FLOAT)0.0; j++)
@@ -3088,6 +3549,7 @@ postprocess:
}
#endif
#ifndef M3D_NOANIMATION
+ M3D_LOG("Calculating bone transformation matrices");
for(i = 0; i < model->numbone; i++) {
b = &model->bone[i];
if(model->bone[i].parent == (M3D_INDEX)-1U) {
@@ -3101,6 +3563,13 @@ postprocess:
_m3d_inv((M3D_FLOAT*)&model->bone[i].mat4);
#endif
}
+#ifdef M3D_PROFILING
+ gettimeofday(&tv0, NULL);
+ tvd.tv_sec = tv0.tv_sec - tv1.tv_sec;
+ tvd.tv_usec = tv0.tv_usec - tv1.tv_usec;
+ if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
+ printf(" Post-process %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec);
+#endif
}
return model;
}
@@ -3155,7 +3624,7 @@ gen: s = 0;
m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec)
{
unsigned int i, j, l;
- M3D_FLOAT r[16], t, d;
+ M3D_FLOAT r[16], t, c, d, s;
m3db_t *ret;
m3dv_t *v, *p, *f;
m3dtr_t *tmp;
@@ -3208,7 +3677,7 @@ m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec)
tmp[fr->transform[i].boneid].ori = fr->transform[i].ori;
}
for(i = 0, j = model->numvertex; i < model->numbone; i++) {
- /* LERP interpolation of position */
+ /* interpolation of position */
if(ret[i].pos != tmp[i].pos) {
p = &model->vertex[ret[i].pos];
f = &model->vertex[tmp[i].pos];
@@ -3218,18 +3687,33 @@ m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec)
v->z = p->z + t * (f->z - p->z);
ret[i].pos = j++;
}
- /* NLERP interpolation of orientation (could have used SLERP, that's nicer, but slower) */
+ /* interpolation of orientation */
if(ret[i].ori != tmp[i].ori) {
p = &model->vertex[ret[i].ori];
f = &model->vertex[tmp[i].ori];
v = &model->vertex[j];
- d = (p->w * f->w + p->x * f->x + p->y * f->y + p->z * f->z < 0) ? (M3D_FLOAT)-1.0 : (M3D_FLOAT)1.0;
- v->x = p->x + t * (d*f->x - p->x);
- v->y = p->y + t * (d*f->y - p->y);
- v->z = p->z + t * (d*f->z - p->z);
- v->w = p->w + t * (d*f->w - p->w);
+ d = p->w * f->w + p->x * f->x + p->y * f->y + p->z * f->z;
+ if(d < 0) { d = -d; s = (M3D_FLOAT)-1.0; } else s = (M3D_FLOAT)1.0;
+#if 0
+ /* don't use SLERP, requires two more variables, libm linkage and it is slow (but nice) */
+ a = (M3D_FLOAT)1.0 - t; b = t;
+ if(d < (M3D_FLOAT)0.999999) { c = acosf(d); b = 1 / sinf(c); a = sinf(a * c) * b; b *= sinf(t * c) * s; }
+ v->x = p->x * a + f->x * b;
+ v->y = p->y * a + f->y * b;
+ v->z = p->z * a + f->z * b;
+ v->w = p->w * a + f->w * b;
+#else
+ /* approximated NLERP, original approximation by Arseny Kapoulkine, heavily optimized by me */
+ c = t - (M3D_FLOAT)0.5; t += t * c * (t - (M3D_FLOAT)1.0) * (((M3D_FLOAT)1.0904 + d * ((M3D_FLOAT)-3.2452 +
+ d * ((M3D_FLOAT)3.55645 - d * (M3D_FLOAT)1.43519))) * c * c + ((M3D_FLOAT)0.848013 + d *
+ ((M3D_FLOAT)-1.06021 + d * (M3D_FLOAT)0.215638)));
+ v->x = p->x + t * (s * f->x - p->x);
+ v->y = p->y + t * (s * f->y - p->y);
+ v->z = p->z + t * (s * f->z - p->z);
+ v->w = p->w + t * (s * f->w - p->w);
d = _m3d_rsq(v->w * v->w + v->x * v->x + v->y * v->y + v->z * v->z);
v->x *= d; v->y *= d; v->z *= d; v->w *= d;
+#endif
ret[i].ori = j++;
}
}
@@ -3271,6 +3755,10 @@ void m3d_free(m3d_t *model)
for(i = 0; i < model->numbone; i++)
if(model->bone[i].name)
M3D_FREE(model->bone[i].name);
+ if(model->shape)
+ for(i = 0; i < model->numshape; i++)
+ if(model->shape[i].name)
+ M3D_FREE(model->shape[i].name);
if(model->material)
for(i = 0; i < model->nummaterial; i++)
if(model->material[i].name)
@@ -3283,10 +3771,36 @@ void m3d_free(m3d_t *model)
for(i = 0; i < model->numtexture; i++)
if(model->texture[i].name)
M3D_FREE(model->texture[i].name);
- if(model->unknown)
- for(i = 0; i < model->numunknown; i++)
- if(model->unknown[i])
- M3D_FREE(model->unknown[i]);
+ if(model->inlined)
+ for(i = 0; i < model->numinlined; i++) {
+ if(model->inlined[i].name)
+ M3D_FREE(model->inlined[i].name);
+ if(model->inlined[i].data)
+ M3D_FREE(model->inlined[i].data);
+ }
+ if(model->extra)
+ for(i = 0; i < model->numextra; i++)
+ if(model->extra[i])
+ M3D_FREE(model->extra[i]);
+ if(model->label)
+ for(i = 0; i < model->numlabel; i++) {
+ if(model->label[i].name) {
+ for(j = i + 1; j < model->numlabel; j++)
+ if(model->label[j].name == model->label[i].name)
+ model->label[j].name = NULL;
+ M3D_FREE(model->label[i].name);
+ }
+ if(model->label[i].lang) {
+ for(j = i + 1; j < model->numlabel; j++)
+ if(model->label[j].lang == model->label[i].lang)
+ model->label[j].lang = NULL;
+ M3D_FREE(model->label[i].lang);
+ }
+ if(model->label[i].text)
+ M3D_FREE(model->label[i].text);
+ }
+ if(model->preview.data)
+ M3D_FREE(model->preview.data);
}
#endif
if(model->flags & M3D_FLG_FREERAW) M3D_FREE(model->raw);
@@ -3301,6 +3815,16 @@ void m3d_free(m3d_t *model)
if(model->skin) M3D_FREE(model->skin);
if(model->vertex) M3D_FREE(model->vertex);
if(model->face) M3D_FREE(model->face);
+ if(model->shape) {
+ for(i = 0; i < model->numshape; i++) {
+ if(model->shape[i].cmd) {
+ for(j = 0; j < model->shape[i].numcmd; j++)
+ if(model->shape[i].cmd[j].arg) M3D_FREE(model->shape[i].cmd[j].arg);
+ M3D_FREE(model->shape[i].cmd);
+ }
+ }
+ M3D_FREE(model->shape);
+ }
if(model->material && !(model->flags & M3D_FLG_MTLLIB)) {
for(i = 0; i < model->nummaterial; i++)
if(model->material[i].prop) M3D_FREE(model->material[i].prop);
@@ -3321,8 +3845,9 @@ void m3d_free(m3d_t *model)
}
M3D_FREE(model->action);
}
+ if(model->label) M3D_FREE(model->label);
if(model->inlined) M3D_FREE(model->inlined);
- if(model->unknown) M3D_FREE(model->unknown);
+ if(model->extra) M3D_FREE(model->extra);
free(model);
}
#endif
@@ -3333,6 +3858,31 @@ typedef struct {
uint32_t offs;
} m3dstr_t;
+typedef struct {
+ m3dti_t data;
+ M3D_INDEX oldidx;
+ M3D_INDEX newidx;
+} m3dtisave_t;
+
+typedef struct {
+ m3dv_t data;
+ M3D_INDEX oldidx;
+ M3D_INDEX newidx;
+ unsigned char norm;
+} m3dvsave_t;
+
+typedef struct {
+ m3ds_t data;
+ M3D_INDEX oldidx;
+ M3D_INDEX newidx;
+} m3dssave_t;
+
+typedef struct {
+ m3df_t data;
+ int group;
+ uint8_t opacity;
+} m3dfsave_t;
+
/* create unique list of strings */
static m3dstr_t *_m3d_addstr(m3dstr_t *str, uint32_t *numstr, char *s)
{
@@ -3387,6 +3937,41 @@ static uint32_t _m3d_stridx(m3dstr_t *str, uint32_t numstr, char *s)
return 0;
}
+/* compare to faces by their material */
+static int _m3d_facecmp(const void *a, const void *b) {
+ const m3dfsave_t *A = (const m3dfsave_t*)a, *B = (const m3dfsave_t*)b;
+ return A->group != B->group ? A->group - B->group : (A->opacity != B->opacity ? (int)B->opacity - (int)A->opacity :
+ (int)A->data.materialid - (int)B->data.materialid);
+}
+/* compare face groups */
+static int _m3d_grpcmp(const void *a, const void *b) { return *((uint32_t*)a) - *((uint32_t*)b); }
+/* compare UVs */
+static int _m3d_ticmp(const void *a, const void *b) { return memcmp(a, b, sizeof(m3dti_t)); }
+/* compare skin groups */
+static int _m3d_skincmp(const void *a, const void *b) { return memcmp(a, b, sizeof(m3ds_t)); }
+/* compare vertices */
+static int _m3d_vrtxcmp(const void *a, const void *b) {
+ int c = memcmp(a, b, 3 * sizeof(M3D_FLOAT));
+ if(c) return c;
+ c = ((m3dvsave_t*)a)->norm - ((m3dvsave_t*)b)->norm;
+ if(c) return c;
+ return memcmp(a, b, sizeof(m3dv_t));
+}
+/* compare labels */
+static _inline int _m3d_strcmp(char *a, char *b)
+{
+ if(a == NULL && b != NULL) return -1;
+ if(a != NULL && b == NULL) return 1;
+ if(a == NULL && b == NULL) return 0;
+ return strcmp(a, b);
+}
+static int _m3d_lblcmp(const void *a, const void *b) {
+ const m3dl_t *A = (const m3dl_t*)a, *B = (const m3dl_t*)b;
+ int c = _m3d_strcmp(A->lang, B->lang);
+ if(!c) c = _m3d_strcmp(A->name, B->name);
+ if(!c) c = _m3d_strcmp(A->text, B->text);
+ return c;
+}
/* compare two colors by HSV value */
_inline static int _m3d_cmapcmp(const void *a, const void *b)
{
@@ -3421,60 +4006,13 @@ static uint32_t *_m3d_addcmap(uint32_t *cmap, uint32_t *numcmap, uint32_t color)
static uint32_t _m3d_cmapidx(uint32_t *cmap, uint32_t numcmap, uint32_t color)
{
uint32_t i;
+ if(numcmap >= 65536)
+ return color;
for(i = 0; i < numcmap; i++)
if(cmap[i] == color) return i;
return 0;
}
-/* add vertex to list */
-static m3dv_t *_m3d_addvrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx)
-{
- uint32_t i;
- 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;
- if(vrtx) {
- for(i = 0; i < *numvrtx; i++)
- if(!memcmp(&vrtx[i], v, sizeof(m3dv_t))) { *idx = i; return vrtx; }
- }
- vrtx = (m3dv_t*)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t));
- memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t));
- *idx = *numvrtx;
- (*numvrtx)++;
- return vrtx;
-}
-
-/* add texture map to list */
-static m3dti_t *_m3d_addtmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *t, uint32_t *idx)
-{
- uint32_t i;
- if(tmap) {
- for(i = 0; i < *numtmap; i++)
- if(!memcmp(&tmap[i], t, sizeof(m3dti_t))) { *idx = i; return tmap; }
- }
- tmap = (m3dti_t*)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t));
- memcpy(&tmap[*numtmap], t, sizeof(m3dti_t));
- *idx = *numtmap;
- (*numtmap)++;
- return tmap;
-}
-
-/* add material to list */
-static m3dm_t **_m3d_addmtrl(m3dm_t **mtrl, uint32_t *nummtrl, m3dm_t *m, uint32_t *idx)
-{
- uint32_t i;
- if(mtrl) {
- for(i = 0; i < *nummtrl; i++)
- if(mtrl[i]->name == m->name || !strcmp(mtrl[i]->name, m->name)) { *idx = i; return mtrl; }
- }
- mtrl = (m3dm_t**)M3D_REALLOC(mtrl, ((*nummtrl) + 1) * sizeof(m3dm_t*));
- mtrl[*nummtrl] = m;
- *idx = *nummtrl;
- (*nummtrl)++;
- return mtrl;
-}
-
/* add index to output */
static unsigned char *_m3d_addidx(unsigned char *out, char type, uint32_t idx) {
switch(type) {
@@ -3495,23 +4033,27 @@ static void _m3d_round(int quality, m3dv_t *src, m3dv_t *dst)
/* round according to quality */
switch(quality) {
case M3D_EXP_INT8:
- t = src->x * 127; dst->x = (M3D_FLOAT)t / 127;
- t = src->y * 127; dst->y = (M3D_FLOAT)t / 127;
- t = src->z * 127; dst->z = (M3D_FLOAT)t / 127;
- t = src->w * 127; dst->w = (M3D_FLOAT)t / 127;
+ t = src->x * 127 + (src->x >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5); dst->x = (M3D_FLOAT)t / 127;
+ t = src->y * 127 + (src->y >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5); dst->y = (M3D_FLOAT)t / 127;
+ t = src->z * 127 + (src->z >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5); dst->z = (M3D_FLOAT)t / 127;
+ t = src->w * 127 + (src->w >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5); dst->w = (M3D_FLOAT)t / 127;
break;
case M3D_EXP_INT16:
- t = src->x * 32767; dst->x = (M3D_FLOAT)t / 32767;
- t = src->y * 32767; dst->y = (M3D_FLOAT)t / 32767;
- t = src->z * 32767; dst->z = (M3D_FLOAT)t / 32767;
- t = src->w * 32767; dst->w = (M3D_FLOAT)t / 32767;
+ t = src->x * 32767 + (src->x >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5); dst->x = (M3D_FLOAT)t / 32767;
+ t = src->y * 32767 + (src->y >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5); dst->y = (M3D_FLOAT)t / 32767;
+ t = src->z * 32767 + (src->z >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5); dst->z = (M3D_FLOAT)t / 32767;
+ t = src->w * 32767 + (src->w >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5); dst->w = (M3D_FLOAT)t / 32767;
break;
}
+ if(dst->x == (M3D_FLOAT)-0.0) dst->x = (M3D_FLOAT)0.0;
+ if(dst->y == (M3D_FLOAT)-0.0) dst->y = (M3D_FLOAT)0.0;
+ if(dst->z == (M3D_FLOAT)-0.0) dst->z = (M3D_FLOAT)0.0;
+ if(dst->w == (M3D_FLOAT)-0.0) dst->w = (M3D_FLOAT)0.0;
}
#ifdef M3D_ASCII
/* add a bone to ascii output */
-static char *_m3d_prtbone(char *ptr, m3db_t *bone, M3D_INDEX numbone, M3D_INDEX parent, uint32_t level)
+static char *_m3d_prtbone(char *ptr, m3db_t *bone, M3D_INDEX numbone, M3D_INDEX parent, uint32_t level, M3D_INDEX *vrtxidx)
{
uint32_t i, j;
char *sn;
@@ -3521,9 +4063,9 @@ static char *_m3d_prtbone(char *ptr, m3db_t *bone, M3D_INDEX numbone, M3D_INDEX
if(bone[i].parent == parent) {
for(j = 0; j < level; j++) *ptr++ = '/';
sn = _m3d_safestr(bone[i].name, 0);
- ptr += sprintf(ptr, "%d %d %s\r\n", bone[i].pos, bone[i].ori, sn);
+ ptr += sprintf(ptr, "%d %d %s\r\n", vrtxidx[bone[i].pos], vrtxidx[bone[i].ori], sn);
M3D_FREE(sn);
- ptr = _m3d_prtbone(ptr, bone, numbone, i, level + 1);
+ ptr = _m3d_prtbone(ptr, bone, numbone, i, level + 1, vrtxidx);
}
}
return ptr;
@@ -3539,23 +4081,25 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size
const char *ol;
char *ptr;
#endif
- char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fi_s;
+ char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s, fi_s;
char *sn = NULL, *sl = NULL, *sa = NULL, *sd = NULL;
- unsigned char *out = NULL, *z = NULL, weights[M3D_NUMBONE];
- unsigned int i, j, k, l, len, chunklen, *length;
- float scale = 0.0f, min_x, max_x, min_y, max_y, min_z, max_z;
- uint32_t idx, numcmap = 0, *cmap = NULL, numvrtx = 0, numtmap = 0, numbone = 0;
- uint32_t numskin = 0, numactn = 0, *actn = NULL, numstr = 0, nummtrl = 0, maxt = 0;
+ unsigned char *out = NULL, *z = NULL, weights[M3D_NUMBONE], *norm = NULL;
+ unsigned int i, j, k, l, n, len, chunklen, *length;
+ M3D_FLOAT scale = (M3D_FLOAT)0.0, min_x, max_x, min_y, max_y, min_z, max_z;
+ M3D_INDEX last, *vrtxidx = NULL, *mtrlidx = NULL, *tmapidx = NULL, *skinidx = NULL;
+ uint32_t idx, numcmap = 0, *cmap = NULL, numvrtx = 0, maxvrtx = 0, numtmap = 0, maxtmap = 0, numproc = 0;
+ uint32_t numskin = 0, maxskin = 0, numstr = 0, maxt = 0, maxbone = 0, numgrp = 0, maxgrp = 0, *grpidx = NULL;
+ uint8_t *opa;
+ m3dcd_t *cd;
+ m3dc_t *cmd;
m3dstr_t *str = NULL;
- m3dv_t *vrtx = NULL, vertex;
- m3dti_t *tmap = NULL, tcoord;
- m3db_t *bone = NULL;
- m3ds_t *skin = NULL;
- m3df_t *face = NULL;
+ m3dvsave_t *vrtx = NULL, vertex;
+ m3dtisave_t *tmap = NULL, tcoord;
+ m3dssave_t *skin = NULL, sk;
+ m3dfsave_t *face = NULL;
m3dhdr_t *h = NULL;
- m3dm_t *m, **mtrl = NULL;
+ m3dm_t *m;
m3da_t *a;
- M3D_INDEX last;
if(!model) {
if(size) *size = 0;
@@ -3565,235 +4109,417 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size
#ifdef M3D_ASCII
if(flags & M3D_EXP_ASCII) quality = M3D_EXP_DOUBLE;
#endif
- /* collect array elements that are actually referenced */
- if(model->numface && model->face && !(flags & M3D_EXP_NOFACE)) {
- face = (m3df_t*)M3D_MALLOC(model->numface * sizeof(m3df_t));
- if(!face) goto memerr;
- memset(face, 255, model->numface * sizeof(m3df_t));
- last = (M3D_INDEX)-1U;
- for(i = 0; i < model->numface; i++) {
- face[i].materialid = (M3D_INDEX)-1U;
- if(!(flags & M3D_EXP_NOMATERIAL) && model->face[i].materialid != last) {
- last = model->face[i].materialid;
- if(last < model->nummaterial) {
- mtrl = _m3d_addmtrl(mtrl, &nummtrl, &model->material[last], &face[i].materialid);
- if(!mtrl) goto memerr;
+ vrtxidx = (M3D_INDEX*)M3D_MALLOC(model->numvertex * sizeof(M3D_INDEX));
+ if(!vrtxidx) goto memerr;
+ memset(vrtxidx, 255, model->numvertex * sizeof(M3D_INDEX));
+ if(model->numvertex && !(flags & M3D_EXP_NONORMAL)){
+ norm = (unsigned char*)M3D_MALLOC(model->numvertex * sizeof(unsigned char));
+ if(!norm) goto memerr;
+ memset(norm, 0, model->numvertex * sizeof(unsigned char));
+ }
+ if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) {
+ mtrlidx = (M3D_INDEX*)M3D_MALLOC(model->nummaterial * sizeof(M3D_INDEX));
+ if(!mtrlidx) goto memerr;
+ memset(mtrlidx, 255, model->nummaterial * sizeof(M3D_INDEX));
+ opa = (uint8_t*)M3D_MALLOC(model->nummaterial * 2 * sizeof(M3D_INDEX));
+ if(!opa) goto memerr;
+ memset(opa, 255, model->nummaterial * 2 * sizeof(M3D_INDEX));
+ }
+ if(model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) {
+ tmapidx = (M3D_INDEX*)M3D_MALLOC(model->numtmap * sizeof(M3D_INDEX));
+ if(!tmapidx) goto memerr;
+ memset(tmapidx, 255, model->numtmap * sizeof(M3D_INDEX));
+ }
+ /** collect array elements that are actually referenced **/
+ if(!(flags & M3D_EXP_NOFACE)) {
+ /* face */
+ if(model->numface && model->face) {
+ M3D_LOG("Processing mesh face");
+ face = (m3dfsave_t*)M3D_MALLOC(model->numface * sizeof(m3dfsave_t));
+ if(!face) goto memerr;
+ for(i = 0; i < model->numface; i++) {
+ memcpy(&face[i].data, &model->face[i], sizeof(m3df_t));
+ face[i].group = 0;
+ face[i].opacity = 255;
+ if(!(flags & M3D_EXP_NOMATERIAL) && model->face[i].materialid < model->nummaterial) {
+ if(model->material[model->face[i].materialid].numprop) {
+ mtrlidx[model->face[i].materialid] = 0;
+ if(opa[model->face[i].materialid * 2]) {
+ m = &model->material[model->face[i].materialid];
+ for(j = 0; j < m->numprop; j++)
+ if(m->prop[j].type == m3dp_Kd) {
+ opa[model->face[i].materialid * 2 + 1] = ((uint8_t*)&m->prop[j].value.color)[3];
+ break;
+ }
+ for(j = 0; j < m->numprop; j++)
+ if(m->prop[j].type == m3dp_d) {
+ opa[model->face[i].materialid * 2 + 1] = (uint8_t)(m->prop[j].value.fnum * 255);
+ break;
+ }
+ opa[model->face[i].materialid * 2] = 0;
+ }
+ face[i].opacity = opa[model->face[i].materialid * 2 + 1];
+ } else
+ face[i].data.materialid = (M3D_INDEX)-1U;
+ }
+ for(j = 0; j < 3; j++) {
+ k = model->face[i].vertex[j];
+ if(k < model->numvertex)
+ vrtxidx[k] = 0;
+ if(!(flags & M3D_EXP_NOCMAP)) {
+ cmap = _m3d_addcmap(cmap, &numcmap, model->vertex[k].color);
+ if(!cmap) goto memerr;
+ }
+ k = model->face[i].normal[j];
+ if(k < model->numvertex && !(flags & M3D_EXP_NONORMAL)) {
+ vrtxidx[k] = 0;
+ norm[k] = 1;
+ }
+ k = model->face[i].texcoord[j];
+ if(k < model->numtmap && !(flags & M3D_EXP_NOTXTCRD))
+ tmapidx[k] = 0;
+ }
+ /* convert from CW to CCW */
+ if(flags & M3D_EXP_IDOSUCK) {
+ j = face[i].data.vertex[1];
+ face[i].data.vertex[1] = face[i].data.vertex[2];
+ face[i].data.vertex[2] = face[i].data.vertex[1];
+ j = face[i].data.normal[1];
+ face[i].data.normal[1] = face[i].data.normal[2];
+ face[i].data.normal[2] = face[i].data.normal[1];
+ j = face[i].data.texcoord[1];
+ face[i].data.texcoord[1] = face[i].data.texcoord[2];
+ face[i].data.texcoord[2] = face[i].data.texcoord[1];
}
}
- for(j = 0; j < 3; j++) {
- k = model->face[i].vertex[j];
- if(quality < M3D_EXP_FLOAT) {
- _m3d_round(quality, &model->vertex[k], &vertex);
- vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &idx);
- } else
- vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[k], &idx);
- if(!vrtx) goto memerr;
- face[i].vertex[j] = (M3D_INDEX)idx;
+ }
+ if(model->numshape && model->shape) {
+ M3D_LOG("Processing shape face");
+ for(i = 0; i < model->numshape; i++) {
+ if(!model->shape[i].numcmd) continue;
+ str = _m3d_addstr(str, &numstr, model->shape[i].name);
+ if(!str) goto memerr;
+ for(j = 0; j < model->shape[i].numcmd; j++) {
+ cmd = &model->shape[i].cmd[j];
+ if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg)
+ continue;
+ if(cmd->type == m3dc_mesh) {
+ if(numgrp + 2 < maxgrp) {
+ maxgrp += 1024;
+ grpidx = (uint32_t*)realloc(grpidx, maxgrp * sizeof(uint32_t));
+ if(!grpidx) goto memerr;
+ if(!numgrp) {
+ grpidx[0] = 0;
+ grpidx[1] = model->numface;
+ numgrp += 2;
+ }
+ }
+ grpidx[numgrp + 0] = cmd->arg[0];
+ grpidx[numgrp + 1] = cmd->arg[0] + cmd->arg[1];
+ numgrp += 2;
+ }
+ cd = &m3d_commandtypes[cmd->type];
+ for(k = n = 0, l = cd->p; k < l; k++)
+ switch(cd->a[((k - n) % (cd->p - n)) + n]) {
+ case m3dcp_mi_t:
+ if(!(flags & M3D_EXP_NOMATERIAL) && cmd->arg[k] < model->nummaterial)
+ mtrlidx[cmd->arg[k]] = 0;
+ break;
+ case m3dcp_ti_t:
+ if(!(flags & M3D_EXP_NOTXTCRD) && cmd->arg[k] < model->numtmap)
+ tmapidx[cmd->arg[k]] = 0;
+ break;
+ case m3dcp_qi_t:
+ case m3dcp_vi_t:
+ if(cmd->arg[k] < model->numvertex)
+ vrtxidx[cmd->arg[k]] = 0;
+ break;
+ case m3dcp_va_t:
+ n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1);
+ break;
+ }
+ }
+ }
+ }
+ if(model->numface && face) {
+ if(numgrp && grpidx) {
+ qsort(grpidx, numgrp, sizeof(uint32_t), _m3d_grpcmp);
+ for(i = j = 0; i < model->numface && j < numgrp; i++) {
+ while(j < numgrp && grpidx[j] < i) j++;
+ face[i].group = j;
+ }
+ }
+ qsort(face, model->numface, sizeof(m3dfsave_t), _m3d_facecmp);
+ }
+ if(grpidx) { M3D_FREE(grpidx); grpidx = NULL; }
+ if(model->numlabel && model->label) {
+ M3D_LOG("Processing annotation labels");
+ for(i = 0; i < model->numlabel; i++) {
+ str = _m3d_addstr(str, &numstr, model->label[i].name);
+ str = _m3d_addstr(str, &numstr, model->label[i].lang);
+ str = _m3d_addstr(str, &numstr, model->label[i].text);
if(!(flags & M3D_EXP_NOCMAP)) {
- cmap = _m3d_addcmap(cmap, &numcmap, model->vertex[k].color);
+ cmap = _m3d_addcmap(cmap, &numcmap, model->label[i].color);
if(!cmap) goto memerr;
}
- k = model->face[i].normal[j];
- if(k < model->numvertex && !(flags & M3D_EXP_NONORMAL)) {
- if(quality < M3D_EXP_FLOAT) {
- _m3d_round(quality, &model->vertex[k], &vertex);
- vrtx = _m3d_addnorm(vrtx, &numvrtx, &vertex, &idx);
- } else
- vrtx = _m3d_addnorm(vrtx, &numvrtx, &model->vertex[k], &idx);
- if(!vrtx) goto memerr;
- face[i].normal[j] = (M3D_INDEX)idx;
- }
- k = model->face[i].texcoord[j];
- if(k < model->numtmap) {
- switch(quality) {
- case M3D_EXP_INT8:
- l = model->tmap[k].u * 255; tcoord.u = (M3D_FLOAT)l / 255;
- l = model->tmap[k].v * 255; tcoord.v = (M3D_FLOAT)l / 255;
- break;
- case M3D_EXP_INT16:
- l = model->tmap[k].u * 65535; tcoord.u = (M3D_FLOAT)l / 65535;
- l = model->tmap[k].v * 65535; tcoord.v = (M3D_FLOAT)l / 65535;
- break;
- default:
- tcoord.u = model->tmap[k].u;
- tcoord.v = model->tmap[k].v;
- break;
- }
- if(flags & M3D_EXP_FLIPTXTCRD)
- tcoord.v = (M3D_FLOAT)1.0 - tcoord.v;
- tmap = _m3d_addtmap(tmap, &numtmap, &tcoord, &idx);
- if(!tmap) goto memerr;
- face[i].texcoord[j] = (M3D_INDEX)idx;
- }
- }
- /* convert from CW to CCW */
- if(flags & M3D_EXP_IDOSUCK) {
- j = face[i].vertex[1];
- face[i].vertex[1] = face[i].vertex[2];
- face[i].vertex[2] = face[i].vertex[1];
- j = face[i].normal[1];
- face[i].normal[1] = face[i].normal[2];
- face[i].normal[2] = face[i].normal[1];
- j = face[i].texcoord[1];
- face[i].texcoord[1] = face[i].texcoord[2];
- face[i].texcoord[2] = face[i].texcoord[1];
+ if(model->label[i].vertexid < model->numvertex)
+ vrtxidx[model->label[i].vertexid] = 0;
}
+ qsort(model->label, model->numlabel, sizeof(m3dl_t), _m3d_lblcmp);
}
} else if(!(flags & M3D_EXP_NOMATERIAL)) {
/* without a face, simply add all materials, because it can be an mtllib */
- nummtrl = model->nummaterial;
+ for(i = 0; i < model->nummaterial; i++)
+ mtrlidx[i] = i;
}
- /* add colors to color map and texture names to string table */
- for(i = 0; i < nummtrl; i++) {
- m = !mtrl ? &model->material[i] : mtrl[i];
- str = _m3d_addstr(str, &numstr, m->name);
- if(!str) goto memerr;
- for(j = 0; j < mtrl[i]->numprop; j++) {
- if(!(flags & M3D_EXP_NOCMAP) && m->prop[j].type < 128) {
- for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) {
- if(m->prop[j].type == m3d_propertytypes[l].id && m3d_propertytypes[l].format == m3dpf_color) {
- cmap = _m3d_addcmap(cmap, &numcmap, m->prop[j].value.color);
- if(!cmap) goto memerr;
- break;
- }
- }
- }
- if(m->prop[j].type >= 128 && m->prop[j].value.textureid < model->numtexture &&
- model->texture[m->prop[j].value.textureid].name) {
- str = _m3d_addstr(str, &numstr, model->texture[m->prop[j].value.textureid].name);
- if(!str) goto memerr;
- }
- }
- }
- /* get bind-pose skeleton and skin */
+ /* bind-pose skeleton */
if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) {
- numbone = model->numbone;
- bone = (m3db_t*)M3D_MALLOC(model->numbone * sizeof(m3db_t));
- if(!bone) goto memerr;
- memset(bone, 0, model->numbone * sizeof(m3db_t));
+ M3D_LOG("Processing bones");
for(i = 0; i < model->numbone; i++) {
- bone[i].parent = model->bone[i].parent;
- bone[i].name = model->bone[i].name;
- str = _m3d_addstr(str, &numstr, bone[i].name);
+ str = _m3d_addstr(str, &numstr, model->bone[i].name);
if(!str) goto memerr;
- if(quality < M3D_EXP_FLOAT) {
- _m3d_round(quality, &model->vertex[model->bone[i].pos], &vertex);
- vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &k);
- } else
- vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[model->bone[i].pos], &k);
- if(!vrtx) goto memerr;
- bone[i].pos = (M3D_INDEX)k;
- if(quality < M3D_EXP_FLOAT) {
- _m3d_round(quality, &model->vertex[model->bone[i].ori], &vertex);
- vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &k);
- } else
- vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[model->bone[i].ori], &k);
- if(!vrtx) goto memerr;
- bone[i].ori = (M3D_INDEX)k;
+ k = model->bone[i].pos;
+ if(k < model->numvertex)
+ vrtxidx[k] = 0;
+ k = model->bone[i].ori;
+ if(k < model->numvertex)
+ vrtxidx[k] = 0;
}
}
/* actions, animated skeleton poses */
if(model->numaction && model->action && !(flags & M3D_EXP_NOACTION)) {
+ M3D_LOG("Processing action list");
for(j = 0; j < model->numaction; j++) {
a = &model->action[j];
str = _m3d_addstr(str, &numstr, a->name);
if(!str) goto memerr;
if(a->numframe > 65535) a->numframe = 65535;
for(i = 0; i < a->numframe; i++) {
- l = numactn;
- numactn += (a->frame[i].numtransform * 2);
- if(a->frame[i].numtransform > maxt)
- maxt = a->frame[i].numtransform;
- actn = (uint32_t*)M3D_REALLOC(actn, numactn * sizeof(uint32_t));
- if(!actn) goto memerr;
- for(k = 0; k < a->frame[i].numtransform; k++) {
- if(quality < M3D_EXP_FLOAT) {
- _m3d_round(quality, &model->vertex[a->frame[i].transform[k].pos], &vertex);
- vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &actn[l++]);
- if(!vrtx) goto memerr;
- _m3d_round(quality, &model->vertex[a->frame[i].transform[k].ori], &vertex);
- vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &actn[l++]);
- } else {
- vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[a->frame[i].transform[k].pos], &actn[l++]);
- if(!vrtx) goto memerr;
- vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[a->frame[i].transform[k].ori], &actn[l++]);
- }
- if(!vrtx) goto memerr;
+ for(l = 0; l < a->frame[i].numtransform; l++) {
+ k = a->frame[i].transform[l].pos;
+ if(k < model->numvertex)
+ vrtxidx[k] = 0;
+ k = a->frame[i].transform[l].ori;
+ if(k < model->numvertex)
+ vrtxidx[k] = 0;
}
+ if(l > maxt) maxt = l;
}
}
}
- /* normalize bounding cube and collect referenced skin records */
- if(numvrtx) {
- min_x = min_y = min_z = 1e10;
- max_x = max_y = max_z = -1e10;
- j = model->numskin && model->skin && !(flags & M3D_EXP_NOBONE);
- for(i = 0; i < numvrtx; i++) {
- if(j && model->numskin && model->skin && vrtx[i].skinid < M3D_INDEXMAX) {
- skin = _m3d_addskin(skin, &numskin, &model->skin[vrtx[i].skinid], &idx);
- if(!skin) goto memerr;
- vrtx[i].skinid = idx;
- }
- if(vrtx[i].skinid == (M3D_INDEX)-2U) continue;
- if(vrtx[i].x > max_x) max_x = vrtx[i].x;
- if(vrtx[i].x < min_x) min_x = vrtx[i].x;
- if(vrtx[i].y > max_y) max_y = vrtx[i].y;
- if(vrtx[i].y < min_y) min_y = vrtx[i].y;
- if(vrtx[i].z > max_z) max_z = vrtx[i].z;
- if(vrtx[i].z < min_z) min_z = vrtx[i].z;
+ /* add colors to color map and texture names to string table */
+ if(!(flags & M3D_EXP_NOMATERIAL)) {
+ M3D_LOG("Processing materials");
+ for(i = k = 0; i < model->nummaterial; i++) {
+ if(mtrlidx[i] == (M3D_INDEX)-1U || !model->material[i].numprop) continue;
+ mtrlidx[i] = k++;
+ m = &model->material[i];
+ str = _m3d_addstr(str, &numstr, m->name);
+ if(!str) goto memerr;
+ if(m->prop)
+ for(j = 0; j < m->numprop; j++) {
+ if(!(flags & M3D_EXP_NOCMAP) && m->prop[j].type < 128) {
+ for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) {
+ if(m->prop[j].type == m3d_propertytypes[l].id && m3d_propertytypes[l].format == m3dpf_color) {
+ ((uint8_t*)&m->prop[j].value.color)[3] = opa[i * 2 + 1];
+ cmap = _m3d_addcmap(cmap, &numcmap, m->prop[j].value.color);
+ if(!cmap) goto memerr;
+ break;
+ }
+ }
+ }
+ if(m->prop[j].type >= 128 && m->prop[j].value.textureid < model->numtexture &&
+ model->texture[m->prop[j].value.textureid].name) {
+ str = _m3d_addstr(str, &numstr, model->texture[m->prop[j].value.textureid].name);
+ if(!str) goto memerr;
+ }
+ }
}
- if(min_x < 0.0f) min_x = -min_x;
- if(max_x < 0.0f) max_x = -max_x;
- if(min_y < 0.0f) min_y = -min_y;
- if(max_y < 0.0f) max_y = -max_y;
- if(min_z < 0.0f) min_z = -min_z;
- if(max_z < 0.0f) max_z = -max_z;
+ }
+ /* if there's only one black color, don't store it */
+ if(numcmap == 1 && cmap && !cmap[0]) numcmap = 0;
+
+ /** compress lists **/
+ if(model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) {
+ M3D_LOG("Compressing tmap");
+ tmap = (m3dtisave_t*)M3D_MALLOC(model->numtmap * sizeof(m3dtisave_t));
+ if(!tmap) goto memerr;
+ for(i = 0; i < model->numtmap; i++) {
+ if(tmapidx[i] == (M3D_INDEX)-1U) continue;
+ switch(quality) {
+ case M3D_EXP_INT8:
+ l = model->tmap[i].u * 255; tcoord.data.u = (M3D_FLOAT)l / 255;
+ l = model->tmap[i].v * 255; tcoord.data.v = (M3D_FLOAT)l / 255;
+ break;
+ case M3D_EXP_INT16:
+ l = model->tmap[i].u * 65535; tcoord.data.u = (M3D_FLOAT)l / 65535;
+ l = model->tmap[i].v * 65535; tcoord.data.v = (M3D_FLOAT)l / 65535;
+ break;
+ default:
+ tcoord.data.u = model->tmap[i].u;
+ tcoord.data.v = model->tmap[i].v;
+ break;
+ }
+ if(flags & M3D_EXP_FLIPTXTCRD)
+ tcoord.data.v = (M3D_FLOAT)1.0 - tcoord.data.v;
+ tcoord.oldidx = i;
+ memcpy(&tmap[numtmap++], &tcoord, sizeof(m3dtisave_t));
+ }
+ if(numtmap) {
+ qsort(tmap, numtmap, sizeof(m3dtisave_t), _m3d_ticmp);
+ memcpy(&tcoord.data, &tmap[0], sizeof(m3dti_t));
+ for(i = 0; i < numtmap; i++) {
+ if(memcmp(&tcoord.data, &tmap[i].data, sizeof(m3dti_t))) {
+ memcpy(&tcoord.data, &tmap[i].data, sizeof(m3dti_t));
+ maxtmap++;
+ }
+ tmap[i].newidx = maxtmap;
+ tmapidx[tmap[i].oldidx] = maxtmap;
+ }
+ maxtmap++;
+ }
+ }
+ if(model->numskin && model->skin && !(flags & M3D_EXP_NOBONE)) {
+ M3D_LOG("Compressing skin");
+ skinidx = (M3D_INDEX*)M3D_MALLOC(model->numskin * sizeof(M3D_INDEX));
+ if(!skinidx) goto memerr;
+ skin = (m3dssave_t*)M3D_MALLOC(model->numskin * sizeof(m3dssave_t));
+ if(!skin) goto memerr;
+ memset(skinidx, 255, model->numskin * sizeof(M3D_INDEX));
+ for(i = 0; i < model->numvertex; i++) {
+ if(vrtxidx[i] != (M3D_INDEX)-1U && model->vertex[i].skinid < model->numskin)
+ skinidx[model->vertex[i].skinid] = 0;
+ }
+ for(i = 0; i < model->numskin; i++) {
+ if(skinidx[i] == (M3D_INDEX)-1U) continue;
+ memset(&sk, 0, sizeof(m3dssave_t));
+ for(j = 0, min_x = (M3D_FLOAT)0.0; j < M3D_NUMBONE && model->skin[i].boneid[j] != (M3D_INDEX)-1U &&
+ model->skin[i].weight[j] > (M3D_FLOAT)0.0; j++) {
+ sk.data.boneid[j] = model->skin[i].boneid[j];
+ sk.data.weight[j] = model->skin[i].weight[j];
+ min_x += sk.data.weight[j];
+ }
+ if(j > maxbone) maxbone = j;
+ if(min_x != (M3D_FLOAT)1.0 && min_x != (M3D_FLOAT)0.0)
+ for(j = 0; j < M3D_NUMBONE && sk.data.weight[j] > (M3D_FLOAT)0.0; j++)
+ sk.data.weight[j] /= min_x;
+ sk.oldidx = i;
+ memcpy(&skin[numskin++], &sk, sizeof(m3dssave_t));
+ }
+ if(numskin) {
+ qsort(skin, numskin, sizeof(m3dssave_t), _m3d_skincmp);
+ memcpy(&sk.data, &skin[0].data, sizeof(m3ds_t));
+ for(i = 0; i < numskin; i++) {
+ if(memcmp(&sk.data, &skin[i].data, sizeof(m3ds_t))) {
+ memcpy(&sk.data, &skin[i].data, sizeof(m3ds_t));
+ maxskin++;
+ }
+ skin[i].newidx = maxskin;
+ skinidx[skin[i].oldidx] = maxskin;
+ }
+ maxskin++;
+ }
+ }
+
+ M3D_LOG("Compressing vertex list");
+ min_x = min_y = min_z = (M3D_FLOAT)1e10;
+ max_x = max_y = max_z = (M3D_FLOAT)-1e10;
+ if(vrtxidx) {
+ vrtx = (m3dvsave_t*)M3D_MALLOC(model->numvertex * sizeof(m3dvsave_t));
+ if(!vrtx) goto memerr;
+ for(i = numvrtx = 0; i < model->numvertex; i++) {
+ if(vrtxidx[i] == (M3D_INDEX)-1U) continue;
+ _m3d_round(quality, &model->vertex[i], &vertex.data);
+ vertex.norm = norm ? norm[i] : 0;
+ if(vertex.data.skinid != (M3D_INDEX)-2U && !vertex.norm) {
+ vertex.data.skinid = vertex.data.skinid != (M3D_INDEX)-1U && skinidx ? skinidx[vertex.data.skinid] : (M3D_INDEX)-1U;
+ if(vertex.data.x > max_x) max_x = vertex.data.x;
+ if(vertex.data.x < min_x) min_x = vertex.data.x;
+ if(vertex.data.y > max_y) max_y = vertex.data.y;
+ if(vertex.data.y < min_y) min_y = vertex.data.y;
+ if(vertex.data.z > max_z) max_z = vertex.data.z;
+ if(vertex.data.z < min_z) min_z = vertex.data.z;
+ }
+#ifdef M3D_VERTEXTYPE
+ vertex.data.type = 0;
+#endif
+ vertex.oldidx = i;
+ memcpy(&vrtx[numvrtx++], &vertex, sizeof(m3dvsave_t));
+ }
+ if(numvrtx) {
+ qsort(vrtx, numvrtx, sizeof(m3dvsave_t), _m3d_vrtxcmp);
+ memcpy(&vertex.data, &vrtx[0].data, sizeof(m3dv_t));
+ for(i = 0; i < numvrtx; i++) {
+ if(memcmp(&vertex.data, &vrtx[i].data, vrtx[i].norm ? 3 * sizeof(M3D_FLOAT) : sizeof(m3dv_t))) {
+ memcpy(&vertex.data, &vrtx[i].data, sizeof(m3dv_t));
+ maxvrtx++;
+ }
+ vrtx[i].newidx = maxvrtx;
+ vrtxidx[vrtx[i].oldidx] = maxvrtx;
+ }
+ maxvrtx++;
+ }
+ }
+ if(skinidx) { M3D_FREE(skinidx); skinidx = NULL; }
+ if(norm) { M3D_FREE(norm); norm = NULL; }
+
+ /* normalize to bounding cube */
+ if(numvrtx && !(flags & M3D_EXP_NORECALC)) {
+ M3D_LOG("Normalizing coordinates");
+ if(min_x < (M3D_FLOAT)0.0) min_x = -min_x;
+ if(max_x < (M3D_FLOAT)0.0) max_x = -max_x;
+ if(min_y < (M3D_FLOAT)0.0) min_y = -min_y;
+ if(max_y < (M3D_FLOAT)0.0) max_y = -max_y;
+ if(min_z < (M3D_FLOAT)0.0) min_z = -min_z;
+ if(max_z < (M3D_FLOAT)0.0) max_z = -max_z;
scale = min_x;
if(max_x > scale) scale = max_x;
if(min_y > scale) scale = min_y;
if(max_y > scale) scale = max_y;
if(min_z > scale) scale = min_z;
if(max_z > scale) scale = max_z;
- if(scale == 0.0f) scale = 1.0f;
- if(scale != 1.0f && !(flags & M3D_EXP_NORECALC)) {
+ if(scale == (M3D_FLOAT)0.0) scale = (M3D_FLOAT)1.0;
+ if(scale != (M3D_FLOAT)1.0) {
for(i = 0; i < numvrtx; i++) {
- if(vrtx[i].skinid == (M3D_INDEX)-2U) continue;
- vrtx[i].x /= scale;
- vrtx[i].y /= scale;
- vrtx[i].z /= scale;
+ if(vrtx[i].data.skinid == (M3D_INDEX)-2U) continue;
+ vrtx[i].data.x /= scale;
+ vrtx[i].data.y /= scale;
+ vrtx[i].data.z /= scale;
}
}
}
- /* if there's only one black color, don't store it */
- if(numcmap == 1 && cmap && !cmap[0]) numcmap = 0;
- /* at least 3 UV coordinate required for texture mapping */
- if(numtmap < 3 && tmap) numtmap = 0;
+ if(model->scale > (M3D_FLOAT)0.0) scale = model->scale;
+ if(scale <= (M3D_FLOAT)0.0) scale = (M3D_FLOAT)1.0;
+
/* meta info */
sn = _m3d_safestr(model->name && *model->name ? model->name : (char*)"(noname)", 2);
sl = _m3d_safestr(model->license ? model->license : (char*)"MIT", 2);
sa = _m3d_safestr(model->author ? model->author : getenv("LOGNAME"), 2);
if(!sn || !sl || !sa) {
-memerr: if(face) M3D_FREE(face);
+memerr: if(vrtxidx) M3D_FREE(vrtxidx);
+ if(mtrlidx) M3D_FREE(mtrlidx);
+ if(tmapidx) M3D_FREE(tmapidx);
+ if(skinidx) M3D_FREE(skinidx);
+ if(grpidx) M3D_FREE(grpidx);
+ if(norm) M3D_FREE(norm);
+ if(face) M3D_FREE(face);
if(cmap) M3D_FREE(cmap);
if(tmap) M3D_FREE(tmap);
- if(mtrl) M3D_FREE(mtrl);
- if(vrtx) M3D_FREE(vrtx);
- if(bone) M3D_FREE(bone);
if(skin) M3D_FREE(skin);
- if(actn) M3D_FREE(actn);
+ if(str) M3D_FREE(str);
+ if(vrtx) M3D_FREE(vrtx);
if(sn) M3D_FREE(sn);
if(sl) M3D_FREE(sl);
if(sa) M3D_FREE(sa);
if(sd) M3D_FREE(sd);
if(out) M3D_FREE(out);
- if(str) M3D_FREE(str);
if(h) M3D_FREE(h);
M3D_LOG("Out of memory");
model->errcode = M3D_ERR_ALLOC;
return NULL;
}
- if(model->scale > (M3D_FLOAT)0.0) scale = (float)model->scale;
- if(scale <= 0.0f) scale = 1.0f;
+
+ M3D_LOG("Serializing model");
#ifdef M3D_ASCII
if(flags & M3D_EXP_ASCII) {
/* use CRLF to make model creators on Win happy... */
@@ -3808,68 +4534,87 @@ memerr: if(face) M3D_FREE(face);
ptr = (char*)out;
ptr += sprintf(ptr, "3dmodel %g\r\n%s\r\n%s\r\n%s\r\n%s\r\n\r\n", scale,
sn, sl, sa, sd);
- M3D_FREE(sn); M3D_FREE(sl); M3D_FREE(sa); M3D_FREE(sd);
- sn = sl = sa = sd = NULL;
+ M3D_FREE(sl); M3D_FREE(sa); M3D_FREE(sd);
+ sl = sa = sd = NULL;
+ /* preview chunk */
+ if(model->preview.data && model->preview.length) {
+ sl = _m3d_safestr(sn, 0);
+ if(sl) {
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + 20;
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
+ if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
+ ptr += sprintf(ptr, "Preview\r\n%s.png\r\n\r\n", sl);
+ M3D_FREE(sl); sl = NULL;
+ }
+ }
+ M3D_FREE(sn); sn = NULL;
/* texture map */
if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) {
- ptr -= (uint64_t)out; len = (uint64_t)ptr + numtmap * 32 + 12;
- out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out;
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + maxtmap * 32 + 12;
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
ptr += sprintf(ptr, "Textmap\r\n");
- for(i = 0; i < numtmap; i++)
- ptr += sprintf(ptr, "%g %g\r\n", tmap[i].u, tmap[i].v);
+ last = (M3D_INDEX)-1U;
+ for(i = 0; i < numtmap; i++) {
+ if(tmap[i].newidx == last) continue;
+ last = tmap[i].newidx;
+ ptr += sprintf(ptr, "%g %g\r\n", tmap[i].data.u, tmap[i].data.v);
+ }
ptr += sprintf(ptr, "\r\n");
}
/* vertex chunk */
if(numvrtx && vrtx && !(flags & M3D_EXP_NOFACE)) {
- ptr -= (uint64_t)out; len = (uint64_t)ptr + numvrtx * 128 + 10;
- out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out;
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + maxvrtx * 128 + 10;
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
ptr += sprintf(ptr, "Vertex\r\n");
+ last = (M3D_INDEX)-1U;
for(i = 0; i < numvrtx; i++) {
- ptr += sprintf(ptr, "%g %g %g %g", vrtx[i].x, vrtx[i].y, vrtx[i].z, vrtx[i].w);
- if(!(flags & M3D_EXP_NOCMAP) && vrtx[i].color)
- ptr += sprintf(ptr, " #%08x", vrtx[i].color);
- if(!(flags & M3D_EXP_NOBONE) && numbone && numskin && vrtx[i].skinid != (M3D_INDEX)-1U &&
- vrtx[i].skinid != (M3D_INDEX)-2U) {
- if(skin[vrtx[i].skinid].weight[0] == (M3D_FLOAT)1.0)
- ptr += sprintf(ptr, " %d", skin[vrtx[i].skinid].boneid[0]);
+ if(vrtx[i].newidx == last) continue;
+ last = vrtx[i].newidx;
+ ptr += sprintf(ptr, "%g %g %g %g", vrtx[i].data.x, vrtx[i].data.y, vrtx[i].data.z, vrtx[i].data.w);
+ if(!(flags & M3D_EXP_NOCMAP) && vrtx[i].data.color)
+ ptr += sprintf(ptr, " #%08x", vrtx[i].data.color);
+ if(!(flags & M3D_EXP_NOBONE) && model->numbone && maxskin && vrtx[i].data.skinid < M3D_INDEXMAX) {
+ if(skin[vrtx[i].data.skinid].data.weight[0] == (M3D_FLOAT)1.0)
+ ptr += sprintf(ptr, " %d", skin[vrtx[i].data.skinid].data.boneid[0]);
else
- for(j = 0; j < M3D_NUMBONE && skin[vrtx[i].skinid].boneid[j] != (M3D_INDEX)-1U &&
- skin[vrtx[i].skinid].weight[j] > (M3D_FLOAT)0.0; j++)
- ptr += sprintf(ptr, " %d:%g", skin[vrtx[i].skinid].boneid[j],
- skin[vrtx[i].skinid].weight[j]);
+ for(j = 0; j < M3D_NUMBONE && skin[vrtx[i].data.skinid].data.boneid[j] != (M3D_INDEX)-1U &&
+ skin[vrtx[i].data.skinid].data.weight[j] > (M3D_FLOAT)0.0; j++)
+ ptr += sprintf(ptr, " %d:%g", skin[vrtx[i].data.skinid].data.boneid[j],
+ skin[vrtx[i].data.skinid].data.weight[j]);
}
ptr += sprintf(ptr, "\r\n");
}
ptr += sprintf(ptr, "\r\n");
}
/* bones chunk */
- if(numbone && bone && !(flags & M3D_EXP_NOBONE)) {
- ptr -= (uint64_t)out; len = (uint64_t)ptr + 9;
- for(i = 0; i < numbone; i++) {
- len += strlen(bone[i].name) + 128;
+ if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) {
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + 9;
+ for(i = 0; i < model->numbone; i++) {
+ len += strlen(model->bone[i].name) + 128;
}
- out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out;
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
ptr += sprintf(ptr, "Bones\r\n");
- ptr = _m3d_prtbone(ptr, bone, numbone, (M3D_INDEX)-1U, 0);
+ ptr = _m3d_prtbone(ptr, model->bone, model->numbone, (M3D_INDEX)-1U, 0, vrtxidx);
ptr += sprintf(ptr, "\r\n");
}
/* materials */
- if(nummtrl && !(flags & M3D_EXP_NOMATERIAL)) {
- for(j = 0; j < nummtrl; j++) {
- m = !mtrl ? &model->material[j] : mtrl[j];
+ if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) {
+ for(j = 0; j < model->nummaterial; j++) {
+ if(mtrlidx[j] == (M3D_INDEX)-1U || !model->material[j].numprop || !model->material[j].prop) continue;
+ m = &model->material[j];
sn = _m3d_safestr(m->name, 0);
if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; }
- ptr -= (uint64_t)out; len = (uint64_t)ptr + strlen(sn) + 12;
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + strlen(sn) + 12;
for(i = 0; i < m->numprop; i++) {
if(m->prop[i].type < 128)
len += 32;
else if(m->prop[i].value.textureid < model->numtexture && model->texture[m->prop[i].value.textureid].name)
len += strlen(model->texture[m->prop[i].value.textureid].name) + 16;
}
- out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out;
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
ptr += sprintf(ptr, "Material %s\r\n", sn);
M3D_FREE(sn); sn = NULL;
@@ -3918,28 +4663,50 @@ memerr: if(face) M3D_FREE(face);
ptr += sprintf(ptr, "\r\n");
}
}
+ /* procedural face */
+ if(model->numinlined && model->inlined && !(flags & M3D_EXP_NOFACE)) {
+ /* all inlined assets which are not textures should be procedural surfaces */
+ for(j = 0; j < model->numinlined; j++) {
+ if(!model->inlined[j].name || !*model->inlined[j].name || !model->inlined[j].length || !model->inlined[j].data ||
+ (model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && model->inlined[j].data[3] == 'G'))
+ continue;
+ for(i = k = 0; i < model->numtexture; i++) {
+ if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; }
+ }
+ if(k) continue;
+ sn = _m3d_safestr(model->inlined[j].name, 0);
+ if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; }
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + strlen(sn) + 18;
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
+ if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
+ ptr += sprintf(ptr, "Procedural\r\n%s\r\n\r\n", sn);
+ M3D_FREE(sn); sn = NULL;
+ }
+ }
/* mesh face */
if(model->numface && face && !(flags & M3D_EXP_NOFACE)) {
- ptr -= (uint64_t)out; len = (uint64_t)ptr + model->numface * 128 + 6;
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + model->numface * 128 + 6;
last = (M3D_INDEX)-1U;
if(!(flags & M3D_EXP_NOMATERIAL))
for(i = 0; i < model->numface; i++) {
- if(face[i].materialid != last) {
- last = face[i].materialid;
- if(last < nummtrl)
- len += strlen(mtrl[last]->name);
+ j = face[i].data.materialid < model->nummaterial ? face[i].data.materialid : (M3D_INDEX)-1U;
+ if(j != last) {
+ last = j;
+ if(last < model->nummaterial)
+ len += strlen(model->material[last].name);
len += 6;
}
}
- out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out;
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
ptr += sprintf(ptr, "Mesh\r\n");
last = (M3D_INDEX)-1U;
for(i = 0; i < model->numface; i++) {
- if(!(flags & M3D_EXP_NOMATERIAL) && face[i].materialid != last) {
- last = face[i].materialid;
- if(last < nummtrl) {
- sn = _m3d_safestr(mtrl[last]->name, 0);
+ j = face[i].data.materialid < model->nummaterial ? face[i].data.materialid : (M3D_INDEX)-1U;
+ if(!(flags & M3D_EXP_NOMATERIAL) && j != last) {
+ last = j;
+ if(last < model->nummaterial) {
+ sn = _m3d_safestr(model->material[last].name, 0);
if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; }
ptr += sprintf(ptr, "use %s\r\n", sn);
M3D_FREE(sn); sn = NULL;
@@ -3948,63 +4715,165 @@ memerr: if(face) M3D_FREE(face);
}
/* hardcoded triangles. Should be repeated as many times as the number of edges in polygon */
for(j = 0; j < 3; j++) {
- ptr += sprintf(ptr, "%s%d", j?" ":"", face[i].vertex[j]);
- if(!(flags & M3D_EXP_NOTXTCRD) && (face[i].texcoord[j] != (M3D_INDEX)-1U))
- ptr += sprintf(ptr, "/%d", face[i].texcoord[j]);
- if(!(flags & M3D_EXP_NONORMAL) && (face[i].normal[j] != (M3D_INDEX)-1U))
- ptr += sprintf(ptr, "%s/%d",
- (flags & M3D_EXP_NOTXTCRD) || (face[i].texcoord[j] == (M3D_INDEX)-1U)? "/" : "",
- face[i].normal[j]);
+ ptr += sprintf(ptr, "%s%d", j?" ":"", vrtxidx[face[i].data.vertex[j]]);
+ k = -1U;
+ if(!(flags & M3D_EXP_NOTXTCRD) && (face[i].data.texcoord[j] != (M3D_INDEX)-1U) &&
+ (tmapidx[face[i].data.texcoord[j]] != (M3D_INDEX)-1U)) {
+ k = tmapidx[face[i].data.texcoord[j]];
+ ptr += sprintf(ptr, "/%d", k);
+ }
+ if(!(flags & M3D_EXP_NONORMAL) && (face[i].data.normal[j] != (M3D_INDEX)-1U))
+ ptr += sprintf(ptr, "%s/%d", k == -1U? "/" : "", vrtxidx[face[i].data.normal[j]]);
}
ptr += sprintf(ptr, "\r\n");
}
ptr += sprintf(ptr, "\r\n");
}
+ /* mathematical shapes face */
+ if(model->numshape && model->numshape && !(flags & M3D_EXP_NOFACE)) {
+ for(j = 0; j < model->numshape; j++) {
+ sn = _m3d_safestr(model->shape[j].name, 0);
+ if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; }
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + strlen(sn) + 33;
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
+ if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
+ ptr += sprintf(ptr, "Shape %s\r\n", sn);
+ M3D_FREE(sn); sn = NULL;
+ if(model->shape[j].group != (M3D_INDEX)-1U && !(flags & M3D_EXP_NOBONE))
+ ptr += sprintf(ptr, "group %d\r\n", model->shape[j].group);
+ for(i = 0; i < model->shape[j].numcmd; i++) {
+ cmd = &model->shape[j].cmd[i];
+ if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg)
+ continue;
+ cd = &m3d_commandtypes[cmd->type];
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + strlen(cd->key) + 3;
+ for(k = 0; k < cd->p; k++)
+ switch(cd->a[k]) {
+ case m3dcp_mi_t: if(cmd->arg[k] != -1U) { len += strlen(model->material[cmd->arg[k]].name) + 1; } break;
+ case m3dcp_va_t: len += cmd->arg[k] * (cd->p - k - 1) * 16; k = cd->p; break;
+ default: len += 16; break;
+ }
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
+ if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
+ ptr += sprintf(ptr, "%s", cd->key);
+ for(k = n = 0, l = cd->p; k < l; k++) {
+ switch(cd->a[((k - n) % (cd->p - n)) + n]) {
+ case m3dcp_mi_t:
+ if(cmd->arg[k] != -1U) {
+ sn = _m3d_safestr(model->material[cmd->arg[k]].name, 0);
+ if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; }
+ ptr += sprintf(ptr, " %s", sn);
+ M3D_FREE(sn); sn = NULL;
+ }
+ break;
+ case m3dcp_vc_t: ptr += sprintf(ptr, " %g", *((float*)&cmd->arg[k])); break;
+ case m3dcp_va_t: ptr += sprintf(ptr, " %d[", cmd->arg[k]);
+ n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1);
+ break;
+ default: ptr += sprintf(ptr, " %d", cmd->arg[k]); break;
+ }
+ }
+ ptr += sprintf(ptr, "%s\r\n", l > cd->p ? " ]" : "");
+ }
+ ptr += sprintf(ptr, "\r\n");
+ }
+ }
+ /* annotation labels */
+ if(model->numlabel && model->label && !(flags & M3D_EXP_NOFACE)) {
+ for(i = 0, j = 3, length = NULL; i < model->numlabel; i++) {
+ if(model->label[i].name) j += strlen(model->label[i].name);
+ if(model->label[i].lang) j += strlen(model->label[i].lang);
+ if(model->label[i].text) j += strlen(model->label[i].text);
+ j += 40;
+ }
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + j;
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
+ if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
+ for(i = 0; i < model->numlabel; i++) {
+ if(!i || _m3d_strcmp(sl, model->label[i].lang) || _m3d_strcmp(sn, model->label[i].name)) {
+ sl = model->label[i].lang;
+ sn = model->label[i].name;
+ sd = _m3d_safestr(sn, 0);
+ if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; }
+ if(i) ptr += sprintf(ptr, "\r\n");
+ ptr += sprintf(ptr, "Labels %s\r\n", sd);
+ M3D_FREE(sd); sd = NULL;
+ if(model->label[i].color)
+ ptr += sprintf(ptr, "color #0x%08x\r\n", model->label[i].color);
+ if(sl && *sl) {
+ sd = _m3d_safestr(sl, 0);
+ if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; }
+ ptr += sprintf(ptr, "lang %s\r\n", sd);
+ M3D_FREE(sd); sd = NULL;
+ }
+ }
+ sd = _m3d_safestr(model->label[i].text, 2);
+ if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; }
+ ptr += sprintf(ptr, "%d %s\r\n", model->label[i].vertexid, sd);
+ M3D_FREE(sd); sd = NULL;
+ }
+ ptr += sprintf(ptr, "\r\n");
+ sn = sl = NULL;
+ }
/* actions */
- if(model->numaction && model->action && numactn && actn && !(flags & M3D_EXP_NOACTION)) {
- l = 0;
+ if(model->numaction && model->action && !(flags & M3D_EXP_NOACTION)) {
for(j = 0; j < model->numaction; j++) {
a = &model->action[j];
sn = _m3d_safestr(a->name, 0);
if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; }
- ptr -= (uint64_t)out; len = (uint64_t)ptr + strlen(sn) + 48;
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + strlen(sn) + 48;
for(i = 0; i < a->numframe; i++)
len += a->frame[i].numtransform * 128 + 8;
- out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out;
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
ptr += sprintf(ptr, "Action %d %s\r\n", a->durationmsec, sn);
M3D_FREE(sn); sn = NULL;
- if(a->numframe > 65535) a->numframe = 65535;
for(i = 0; i < a->numframe; i++) {
ptr += sprintf(ptr, "frame %d\r\n", a->frame[i].msec);
for(k = 0; k < a->frame[i].numtransform; k++) {
- ptr += sprintf(ptr, "%d %d %d\r\n", a->frame[i].transform[k].boneid, actn[l], actn[l + 1]);
- l += 2;
+ ptr += sprintf(ptr, "%d %d %d\r\n", a->frame[i].transform[k].boneid,
+ vrtxidx[a->frame[i].transform[k].pos], vrtxidx[a->frame[i].transform[k].ori]);
}
}
ptr += sprintf(ptr, "\r\n");
}
}
+ /* inlined assets */
+ if(model->numinlined && model->inlined) {
+ for(i = j = 0; i < model->numinlined; i++)
+ if(model->inlined[i].name)
+ j += strlen(model->inlined[i].name) + 6;
+ if(j > 0) {
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + j + 16;
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
+ if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
+ ptr += sprintf(ptr, "Assets\r\n");
+ for(i = 0; i < model->numinlined; i++)
+ if(model->inlined[i].name)
+ ptr += sprintf(ptr, "%s%s\r\n", model->inlined[i].name, strrchr(model->inlined[i].name, '.') ? "" : ".png");
+ ptr += sprintf(ptr, "\r\n");
+ }
+ }
/* extra info */
- if(model->numunknown && (flags & M3D_EXP_EXTRA)) {
- for(i = 0; i < model->numunknown; i++) {
- if(model->unknown[i]->length < 9) continue;
- ptr -= (uint64_t)out; len = (uint64_t)ptr + 17 + model->unknown[i]->length * 3;
- out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out;
+ if(model->numextra && (flags & M3D_EXP_EXTRA)) {
+ for(i = 0; i < model->numextra; i++) {
+ if(model->extra[i]->length < 9) continue;
+ ptr -= (uintptr_t)out; len = (uintptr_t)ptr + 17 + model->extra[i]->length * 3;
+ out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out;
if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; }
ptr += sprintf(ptr, "Extra %c%c%c%c\r\n",
- model->unknown[i]->magic[0] > ' ' ? model->unknown[i]->magic[0] : '_',
- model->unknown[i]->magic[1] > ' ' ? model->unknown[i]->magic[1] : '_',
- model->unknown[i]->magic[2] > ' ' ? model->unknown[i]->magic[2] : '_',
- model->unknown[i]->magic[3] > ' ' ? model->unknown[i]->magic[3] : '_');
- for(j = 0; j < model->unknown[i]->length; j++)
- ptr += sprintf(ptr, "%02x ", *((unsigned char *)model->unknown + sizeof(m3dchunk_t) + j));
+ model->extra[i]->magic[0] > ' ' ? model->extra[i]->magic[0] : '_',
+ model->extra[i]->magic[1] > ' ' ? model->extra[i]->magic[1] : '_',
+ model->extra[i]->magic[2] > ' ' ? model->extra[i]->magic[2] : '_',
+ model->extra[i]->magic[3] > ' ' ? model->extra[i]->magic[3] : '_');
+ for(j = 0; j < model->extra[i]->length; j++)
+ ptr += sprintf(ptr, "%02x ", *((unsigned char *)model->extra + sizeof(m3dchunk_t) + j));
ptr--;
ptr += sprintf(ptr, "\r\n\r\n");
}
}
setlocale(LC_NUMERIC, ol);
- len = (uint64_t)ptr - (uint64_t)out;
+ len = (uintptr_t)ptr - (uintptr_t)out;
out = (unsigned char*)M3D_REALLOC(out, len + 1);
if(!out) goto memerr;
out[len] = 0;
@@ -4025,16 +4894,6 @@ memerr: if(face) M3D_FREE(face);
i = strlen(sa); memcpy((uint8_t*)h + h->length, sa, i+1); h->length += i+1; M3D_FREE(sa);
i = strlen(sd); memcpy((uint8_t*)h + h->length, sd, i+1); h->length += i+1; M3D_FREE(sd);
sn = sl = sa = sd = NULL;
- len = 0;
- if(!bone) numbone = 0;
- if(skin)
- for(i = 0; i < numskin; i++) {
- for(j = k = 0; j < M3D_NUMBONE; j++)
- if(skin[i].boneid[j] != (M3D_INDEX)-1U && skin[i].weight[j] > (M3D_FLOAT)0.0) k++;
- if(k > len) len = k;
- }
- else
- numskin = 0;
if(model->inlined)
for(i = 0; i < model->numinlined; i++) {
if(model->inlined[i].name && *model->inlined[i].name && model->inlined[i].length > 0) {
@@ -4048,14 +4907,19 @@ memerr: if(face) M3D_FREE(face);
if(!h) goto memerr;
}
vc_s = quality == M3D_EXP_INT8? 1 : (quality == M3D_EXP_INT16? 2 : (quality == M3D_EXP_DOUBLE? 8 : 4));
- vi_s = numvrtx < 254 ? 1 : (numvrtx < 65534 ? 2 : 4);
+ vi_s = maxvrtx < 254 ? 1 : (maxvrtx < 65534 ? 2 : 4);
si_s = h->length - 16 < 254 ? 1 : (h->length - 16 < 65534 ? 2 : 4);
ci_s = !numcmap || !cmap ? 0 : (numcmap < 254 ? 1 : (numcmap < 65534 ? 2 : 4));
- ti_s = !numtmap || !tmap ? 0 : (numtmap < 254 ? 1 : (numtmap < 65534 ? 2 : 4));
- bi_s = !numbone || !bone ? 0 : (numbone < 254 ? 1 : (numbone < 65534 ? 2 : 4));
- nb_s = len < 2 ? 1 : (len == 2 ? 2 : (len <= 4 ? 4 : 8));
- sk_s = !numbone || !numskin ? 0 : (numskin < 254 ? 1 : (numskin < 65534 ? 2 : 4));
- fi_s = maxt < 254 ? 1 : (maxt < 65534 ? 2 : 4);
+ ti_s = !maxtmap || !tmap ? 0 : (maxtmap < 254 ? 1 : (maxtmap < 65534 ? 2 : 4));
+ bi_s = !model->numbone || !model->bone || (flags & M3D_EXP_NOBONE)? 0 : (model->numbone < 254 ? 1 :
+ (model->numbone < 65534 ? 2 : 4));
+ nb_s = maxbone < 2 ? 1 : (maxbone == 2 ? 2 : (maxbone <= 4 ? 4 : 8));
+ sk_s = !bi_s || !maxskin || !skin ? 0 : (maxskin < 254 ? 1 : (maxskin < 65534 ? 2 : 4));
+ fc_s = maxt < 254 ? 1 : (maxt < 65534 ? 2 : 4);
+ hi_s = !model->numshape || !model->shape || (flags & M3D_EXP_NOFACE)? 0 : (model->numshape < 254 ? 1 :
+ (model->numshape < 65534 ? 2 : 4));
+ fi_s = !model->numface || !model->face || (flags & M3D_EXP_NOFACE)? 0 : (model->numface < 254 ? 1 :
+ (model->numface < 65534 ? 2 : 4));
h->types = (vc_s == 8 ? (3<<0) : (vc_s == 2 ? (1<<0) : (vc_s == 1 ? (0<<0) : (2<<0)))) |
(vi_s == 2 ? (1<<2) : (vi_s == 1 ? (0<<2) : (2<<2))) |
(si_s == 2 ? (1<<4) : (si_s == 1 ? (0<<4) : (2<<4))) |
@@ -4064,8 +4928,20 @@ memerr: if(face) M3D_FREE(face);
(bi_s == 2 ? (1<<10): (bi_s == 1 ? (0<<10): (bi_s == 4 ? (2<<10) : (3<<10)))) |
(nb_s == 2 ? (1<<12): (nb_s == 1 ? (0<<12): (2<<12))) |
(sk_s == 2 ? (1<<14): (sk_s == 1 ? (0<<14): (sk_s == 4 ? (2<<14) : (3<<14)))) |
- (fi_s == 2 ? (1<<16): (fi_s == 1 ? (0<<16): (2<<16))) ;
+ (fc_s == 2 ? (1<<16): (fc_s == 1 ? (0<<16): (2<<16))) |
+ (hi_s == 2 ? (1<<18): (hi_s == 1 ? (0<<18): (hi_s == 4 ? (2<<18) : (3<<18)))) |
+ (fi_s == 2 ? (1<<20): (fi_s == 1 ? (0<<20): (fi_s == 4 ? (2<<20) : (3<<20))));
len = h->length;
+ /* preview image chunk, must be the first if exists */
+ if(model->preview.data && model->preview.length) {
+ chunklen = 8 + model->preview.length;
+ h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen);
+ if(!h) goto memerr;
+ memcpy((uint8_t*)h + len, "PRVW", 4);
+ *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen;
+ memcpy((uint8_t*)h + len + 8, model->preview.data, model->preview.length);
+ len += chunklen;
+ }
/* color map */
if(numcmap && cmap && ci_s < 4 && !(flags & M3D_EXP_NOCMAP)) {
chunklen = 8 + numcmap * sizeof(uint32_t);
@@ -4078,116 +4954,127 @@ memerr: if(face) M3D_FREE(face);
} else numcmap = 0;
/* texture map */
if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) {
- chunklen = 8 + numtmap * vc_s * 2;
+ chunklen = 8 + maxtmap * vc_s * 2;
h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen);
if(!h) goto memerr;
memcpy((uint8_t*)h + len, "TMAP", 4);
- *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen;
+ length = (uint32_t*)((uint8_t*)h + len + 4);
out = (uint8_t*)h + len + 8;
+ last = (M3D_INDEX)-1U;
for(i = 0; i < numtmap; i++) {
+ if(tmap[i].newidx == last) continue;
+ last = tmap[i].newidx;
switch(vc_s) {
- case 1: *out++ = (uint8_t)(tmap[i].u * 255); *out++ = (uint8_t)(tmap[i].v * 255); break;
+ case 1: *out++ = (uint8_t)(tmap[i].data.u * 255); *out++ = (uint8_t)(tmap[i].data.v * 255); break;
case 2:
- *((uint16_t*)out) = (uint16_t)(tmap[i].u * 65535); out += 2;
- *((uint16_t*)out) = (uint16_t)(tmap[i].v * 65535); out += 2;
+ *((uint16_t*)out) = (uint16_t)(tmap[i].data.u * 65535); out += 2;
+ *((uint16_t*)out) = (uint16_t)(tmap[i].data.v * 65535); out += 2;
break;
- case 4: *((float*)out) = tmap[i].u; out += 4; *((float*)out) = tmap[i].v; out += 4; break;
- case 8: *((double*)out) = tmap[i].u; out += 8; *((double*)out) = tmap[i].v; out += 8; break;
+ case 4: *((float*)out) = tmap[i].data.u; out += 4; *((float*)out) = tmap[i].data.v; out += 4; break;
+ case 8: *((double*)out) = tmap[i].data.u; out += 8; *((double*)out) = tmap[i].data.v; out += 8; break;
}
}
+ *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len);
out = NULL;
- len += chunklen;
+ len += *length;
}
/* vertex */
if(numvrtx && vrtx) {
- chunklen = 8 + numvrtx * (ci_s + sk_s + 4 * vc_s);
+ chunklen = 8 + maxvrtx * (ci_s + sk_s + 4 * vc_s);
h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen);
if(!h) goto memerr;
memcpy((uint8_t*)h + len, "VRTS", 4);
- *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen;
+ length = (uint32_t*)((uint8_t*)h + len + 4);
out = (uint8_t*)h + len + 8;
+ last = (M3D_INDEX)-1U;
for(i = 0; i < numvrtx; i++) {
+ if(vrtx[i].newidx == last) continue;
+ last = vrtx[i].newidx;
switch(vc_s) {
case 1:
- *out++ = (int8_t)(vrtx[i].x * 127);
- *out++ = (int8_t)(vrtx[i].y * 127);
- *out++ = (int8_t)(vrtx[i].z * 127);
- *out++ = (int8_t)(vrtx[i].w * 127);
+ *out++ = (int8_t)(vrtx[i].data.x * 127);
+ *out++ = (int8_t)(vrtx[i].data.y * 127);
+ *out++ = (int8_t)(vrtx[i].data.z * 127);
+ *out++ = (int8_t)(vrtx[i].data.w * 127);
break;
case 2:
- *((int16_t*)out) = (int16_t)(vrtx[i].x * 32767); out += 2;
- *((int16_t*)out) = (int16_t)(vrtx[i].y * 32767); out += 2;
- *((int16_t*)out) = (int16_t)(vrtx[i].z * 32767); out += 2;
- *((int16_t*)out) = (int16_t)(vrtx[i].w * 32767); out += 2;
+ *((int16_t*)out) = (int16_t)(vrtx[i].data.x * 32767); out += 2;
+ *((int16_t*)out) = (int16_t)(vrtx[i].data.y * 32767); out += 2;
+ *((int16_t*)out) = (int16_t)(vrtx[i].data.z * 32767); out += 2;
+ *((int16_t*)out) = (int16_t)(vrtx[i].data.w * 32767); out += 2;
break;
case 4:
- *((float*)out) = vrtx[i].x; out += 4;
- *((float*)out) = vrtx[i].y; out += 4;
- *((float*)out) = vrtx[i].z; out += 4;
- *((float*)out) = vrtx[i].w; out += 4;
+ *((float*)out) = vrtx[i].data.x; out += 4;
+ *((float*)out) = vrtx[i].data.y; out += 4;
+ *((float*)out) = vrtx[i].data.z; out += 4;
+ *((float*)out) = vrtx[i].data.w; out += 4;
break;
case 8:
- *((double*)out) = vrtx[i].x; out += 8;
- *((double*)out) = vrtx[i].y; out += 8;
- *((double*)out) = vrtx[i].z; out += 8;
- *((double*)out) = vrtx[i].w; out += 8;
+ *((double*)out) = vrtx[i].data.x; out += 8;
+ *((double*)out) = vrtx[i].data.y; out += 8;
+ *((double*)out) = vrtx[i].data.z; out += 8;
+ *((double*)out) = vrtx[i].data.w; out += 8;
break;
}
- idx = _m3d_cmapidx(cmap, numcmap, vrtx[i].color);
+ idx = _m3d_cmapidx(cmap, numcmap, vrtx[i].data.color);
switch(ci_s) {
case 1: *out++ = (uint8_t)(idx); break;
case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break;
- case 4: *((uint32_t*)out) = vrtx[i].color; out += 4; break;
+ case 4: *((uint32_t*)out) = vrtx[i].data.color; out += 4; break;
}
- out = _m3d_addidx(out, sk_s, numbone && numskin ? vrtx[i].skinid : -1U);
+ out = _m3d_addidx(out, sk_s, vrtx[i].data.skinid);
}
+ *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len);
out = NULL;
- len += chunklen;
+ len += *length;
}
/* bones chunk */
- if(numbone && bone && !(flags & M3D_EXP_NOBONE)) {
- i = 8 + bi_s + sk_s + numbone * (bi_s + si_s + 2*vi_s);
+ if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) {
+ i = 8 + bi_s + sk_s + model->numbone * (bi_s + si_s + 2*vi_s);
chunklen = i + numskin * nb_s * (bi_s + 1);
h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen);
if(!h) goto memerr;
memcpy((uint8_t*)h + len, "BONE", 4);
length = (uint32_t*)((uint8_t*)h + len + 4);
out = (uint8_t*)h + len + 8;
- out = _m3d_addidx(out, bi_s, numbone);
- out = _m3d_addidx(out, sk_s, numskin);
- for(i = 0; i < numbone; i++) {
- out = _m3d_addidx(out, bi_s, bone[i].parent);
- out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, bone[i].name));
- out = _m3d_addidx(out, vi_s, bone[i].pos);
- out = _m3d_addidx(out, vi_s, bone[i].ori);
+ out = _m3d_addidx(out, bi_s, model->numbone);
+ out = _m3d_addidx(out, sk_s, maxskin);
+ for(i = 0; i < model->numbone; i++) {
+ out = _m3d_addidx(out, bi_s, model->bone[i].parent);
+ out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->bone[i].name));
+ out = _m3d_addidx(out, vi_s, vrtxidx[model->bone[i].pos]);
+ out = _m3d_addidx(out, vi_s, vrtxidx[model->bone[i].ori]);
}
if(numskin && skin && sk_s) {
+ last = (M3D_INDEX)-1U;
for(i = 0; i < numskin; i++) {
+ if(skin[i].newidx == last) continue;
+ last = skin[i].newidx;
memset(&weights, 0, nb_s);
- for(j = 0; j < (uint32_t)nb_s && skin[i].boneid[j] != (M3D_INDEX)-1U &&
- skin[i].weight[j] > (M3D_FLOAT)0.0; j++)
- weights[j] = (uint8_t)(skin[i].weight[j] * 255);
+ for(j = 0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != (M3D_INDEX)-1U &&
+ skin[i].data.weight[j] > (M3D_FLOAT)0.0; j++)
+ weights[j] = (uint8_t)(skin[i].data.weight[j] * 255);
switch(nb_s) {
case 1: weights[0] = 255; break;
case 2: *((uint16_t*)out) = *((uint16_t*)&weights[0]); out += 2; break;
case 4: *((uint32_t*)out) = *((uint32_t*)&weights[0]); out += 4; break;
case 8: *((uint64_t*)out) = *((uint64_t*)&weights[0]); out += 8; break;
}
- for(j = 0; j < (uint32_t)nb_s && skin[i].boneid[j] != (M3D_INDEX)-1U &&
- skin[i].weight[j] > (M3D_FLOAT)0.0; j++) {
- out = _m3d_addidx(out, bi_s, skin[i].boneid[j]);
+ for(j = 0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != (M3D_INDEX)-1U && weights[j]; j++) {
+ out = _m3d_addidx(out, bi_s, skin[i].data.boneid[j]);
*length += bi_s;
}
}
}
- *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len);
+ *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len);
out = NULL;
len += *length;
}
/* materials */
- if(nummtrl && !(flags & M3D_EXP_NOMATERIAL)) {
- for(j = 0; j < nummtrl; j++) {
- m = !mtrl ? &model->material[j] : mtrl[j];
+ if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) {
+ for(j = 0; j < model->nummaterial; j++) {
+ if(mtrlidx[j] == (M3D_INDEX)-1U || !model->material[j].numprop || !model->material[j].prop) continue;
+ m = &model->material[j];
chunklen = 12 + si_s + m->numprop * 5;
h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen);
if(!h) goto memerr;
@@ -4228,11 +5115,35 @@ memerr: if(face) M3D_FREE(face);
break;
}
}
- *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len);
+ *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len);
len += *length;
out = NULL;
}
}
+ /* procedural face */
+ if(model->numinlined && model->inlined && !(flags & M3D_EXP_NOFACE)) {
+ /* all inlined assets which are not textures should be procedural surfaces */
+ for(j = 0; j < model->numinlined; j++) {
+ if(!model->inlined[j].name || !model->inlined[j].name[0] || model->inlined[j].length < 4 ||
+ !model->inlined[j].data || (model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' &&
+ model->inlined[j].data[3] == 'G'))
+ continue;
+ for(i = k = 0; i < model->numtexture; i++) {
+ if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; }
+ }
+ if(k) continue;
+ numproc++;
+ chunklen = 8 + si_s;
+ h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen);
+ if(!h) goto memerr;
+ memcpy((uint8_t*)h + len, "PROC", 4);
+ *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen;
+ out = (uint8_t*)h + len + 8;
+ out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->inlined[j].name));
+ out = NULL;
+ len += chunklen;
+ }
+ }
/* mesh face */
if(model->numface && face && !(flags & M3D_EXP_NOFACE)) {
chunklen = 8 + si_s + model->numface * (6 * vi_s + 3 * ti_s + si_s + 1);
@@ -4243,41 +5154,123 @@ memerr: if(face) M3D_FREE(face);
out = (uint8_t*)h + len + 8;
last = (M3D_INDEX)-1U;
for(i = 0; i < model->numface; i++) {
- if(!(flags & M3D_EXP_NOMATERIAL) && face[i].materialid != last) {
- last = face[i].materialid;
- if(last < nummtrl) {
- idx = _m3d_stridx(str, numstr, !mtrl ? model->material[last].name : mtrl[last]->name);
- if(idx) {
- *out++ = 0;
- out = _m3d_addidx(out, si_s, idx);
- }
- }
+ if(!(flags & M3D_EXP_NOMATERIAL) && face[i].data.materialid != last) {
+ last = face[i].data.materialid;
+ idx = last < model->nummaterial ? _m3d_stridx(str, numstr, model->material[last].name) : 0;
+ *out++ = 0;
+ out = _m3d_addidx(out, si_s, idx);
}
/* hardcoded triangles. */
k = (3 << 4) |
- (((flags & M3D_EXP_NOTXTCRD) || ti_s == 8 || (face[i].texcoord[0] == (M3D_INDEX)-1U &&
- face[i].texcoord[1] == (M3D_INDEX)-1U && face[i].texcoord[2] == (M3D_INDEX)-1U)) ? 0 : 1) |
- (((flags & M3D_EXP_NONORMAL) || (face[i].normal[0] == (M3D_INDEX)-1U &&
- face[i].normal[1] == (M3D_INDEX)-1U && face[i].normal[2] == (M3D_INDEX)-1U)) ? 0 : 2);
+ (((flags & M3D_EXP_NOTXTCRD) || !ti_s || face[i].data.texcoord[0] == (M3D_INDEX)-1U ||
+ face[i].data.texcoord[1] == (M3D_INDEX)-1U || face[i].data.texcoord[2] == (M3D_INDEX)-1U) ? 0 : 1) |
+ (((flags & M3D_EXP_NONORMAL) || face[i].data.normal[0] == (M3D_INDEX)-1U ||
+ face[i].data.normal[1] == (M3D_INDEX)-1U || face[i].data.normal[2] == (M3D_INDEX)-1U) ? 0 : 2);
*out++ = k;
for(j = 0; j < 3; j++) {
- out = _m3d_addidx(out, vi_s, face[i].vertex[j]);
+ out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.vertex[j]]);
if(k & 1)
- out = _m3d_addidx(out, ti_s, face[i].texcoord[j]);
+ out = _m3d_addidx(out, ti_s, tmapidx[face[i].data.texcoord[j]]);
if(k & 2)
- out = _m3d_addidx(out, vi_s, face[i].normal[j]);
+ out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.normal[j]]);
}
}
- *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len);
+ *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len);
len += *length;
out = NULL;
}
+ /* mathematical shapes face */
+ if(model->numshape && model->shape && !(flags & M3D_EXP_NOFACE)) {
+ for(j = 0; j < model->numshape; j++) {
+ chunklen = 12 + si_s + model->shape[j].numcmd * (M3D_CMDMAXARG + 1) * 4;
+ h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen);
+ if(!h) goto memerr;
+ memcpy((uint8_t*)h + len, "SHPE", 4);
+ length = (uint32_t*)((uint8_t*)h + len + 4);
+ out = (uint8_t*)h + len + 8;
+ out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->shape[j].name));
+ out = _m3d_addidx(out, bi_s, model->shape[j].group);
+ for(i = 0; i < model->shape[j].numcmd; i++) {
+ cmd = &model->shape[j].cmd[i];
+ if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg)
+ continue;
+ cd = &m3d_commandtypes[cmd->type];
+ *out++ = (cmd->type & 0x7F) | (cmd->type > 127 ? 0x80 : 0);
+ if(cmd->type > 127) *out++ = (cmd->type >> 7) & 0xff;
+ for(k = n = 0, l = cd->p; k < l; k++) {
+ switch(cd->a[((k - n) % (cd->p - n)) + n]) {
+ case m3dcp_mi_t:
+ out = _m3d_addidx(out, si_s, cmd->arg[k] < model->nummaterial ?
+ _m3d_stridx(str, numstr, model->material[cmd->arg[k]].name) : 0);
+ break;
+ case m3dcp_vc_t:
+ min_x = *((float*)&cmd->arg[k]);
+ switch(vc_s) {
+ case 1: *out++ = (int8_t)(min_x * 127); break;
+ case 2: *((int16_t*)out) = (int16_t)(min_x * 32767); out += 2; break;
+ case 4: *((float*)out) = min_x; out += 4; break;
+ case 8: *((double*)out) = min_x; out += 8; break;
+ }
+ break;
+ case m3dcp_hi_t: out = _m3d_addidx(out, hi_s, cmd->arg[k]); break;
+ case m3dcp_fi_t: out = _m3d_addidx(out, fi_s, cmd->arg[k]); break;
+ case m3dcp_ti_t: out = _m3d_addidx(out, ti_s, cmd->arg[k]); break;
+ case m3dcp_qi_t:
+ case m3dcp_vi_t: out = _m3d_addidx(out, vi_s, cmd->arg[k]); break;
+ case m3dcp_i1_t: out = _m3d_addidx(out, 1, cmd->arg[k]); break;
+ case m3dcp_i2_t: out = _m3d_addidx(out, 2, cmd->arg[k]); break;
+ case m3dcp_i4_t: out = _m3d_addidx(out, 4, cmd->arg[k]); break;
+ case m3dcp_va_t: out = _m3d_addidx(out, 4, cmd->arg[k]);
+ n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1);
+ break;
+ }
+ }
+ }
+ *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len);
+ len += *length;
+ out = NULL;
+ }
+ }
+ /* annotation labels */
+ if(model->numlabel && model->label) {
+ for(i = 0, length = NULL; i < model->numlabel; i++) {
+ if(!i || _m3d_strcmp(sl, model->label[i].lang) || _m3d_strcmp(sn, model->label[i].name)) {
+ sl = model->label[i].lang;
+ sn = model->label[i].name;
+ if(length) {
+ *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len);
+ len += *length;
+ }
+ chunklen = 8 + 2 * si_s + ci_s + model->numlabel * (vi_s + si_s);
+ h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen);
+ if(!h) { sn = NULL; sl = NULL; goto memerr; }
+ memcpy((uint8_t*)h + len, "LBLS", 4);
+ length = (uint32_t*)((uint8_t*)h + len + 4);
+ out = (uint8_t*)h + len + 8;
+ out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].name));
+ out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].lang));
+ idx = _m3d_cmapidx(cmap, numcmap, model->label[i].color);
+ switch(ci_s) {
+ case 1: *out++ = (uint8_t)(idx); break;
+ case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break;
+ case 4: *((uint32_t*)out) = model->label[i].color; out += 4; break;
+ }
+ }
+ out = _m3d_addidx(out, vi_s, vrtxidx[model->label[i].vertexid]);
+ out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].text));
+ }
+ if(length) {
+ *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len);
+ len += *length;
+ }
+ out = NULL;
+ sn = sl = NULL;
+ }
/* actions */
- if(model->numaction && model->action && numactn && actn && numbone && bone && !(flags & M3D_EXP_NOACTION)) {
- l = 0;
+ if(model->numaction && model->action && model->numbone && model->bone && !(flags & M3D_EXP_NOACTION)) {
for(j = 0; j < model->numaction; j++) {
a = &model->action[j];
- chunklen = 14 + si_s + a->numframe * (4 + fi_s + maxt * (bi_s + 2 * vi_s));
+ chunklen = 14 + si_s + a->numframe * (4 + fc_s + maxt * (bi_s + 2 * vi_s));
h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen);
if(!h) goto memerr;
memcpy((uint8_t*)h + len, "ACTN", 4);
@@ -4288,23 +5281,31 @@ memerr: if(face) M3D_FREE(face);
*((uint32_t*)out) = (uint32_t)(a->durationmsec); out += 4;
for(i = 0; i < a->numframe; i++) {
*((uint32_t*)out) = (uint32_t)(a->frame[i].msec); out += 4;
- out = _m3d_addidx(out, fi_s, a->frame[i].numtransform);
+ out = _m3d_addidx(out, fc_s, a->frame[i].numtransform);
for(k = 0; k < a->frame[i].numtransform; k++) {
out = _m3d_addidx(out, bi_s, a->frame[i].transform[k].boneid);
- out = _m3d_addidx(out, vi_s, actn[l++]);
- out = _m3d_addidx(out, vi_s, actn[l++]);
+ out = _m3d_addidx(out, vi_s, vrtxidx[a->frame[i].transform[k].pos]);
+ out = _m3d_addidx(out, vi_s, vrtxidx[a->frame[i].transform[k].ori]);
}
}
- *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len);
+ *length = (uintptr_t)out - (uintptr_t)((uint8_t*)h + len);
len += *length;
out = NULL;
}
}
/* inlined assets */
- if(model->numinlined && model->inlined && (flags & M3D_EXP_INLINE)) {
+ if(model->numinlined && model->inlined && (numproc || (flags & M3D_EXP_INLINE))) {
for(j = 0; j < model->numinlined; j++) {
- if(!model->inlined[j].name || !*model->inlined[j].name || !model->inlined[j].length)
+ if(!model->inlined[j].name || !model->inlined[j].name[0] || model->inlined[j].length<4 || !model->inlined[j].data)
continue;
+ if(!(flags & M3D_EXP_INLINE)) {
+ if(model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && model->inlined[j].data[3] == 'G')
+ continue;
+ for(i = k = 0; i < model->numtexture; i++) {
+ if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; }
+ }
+ if(k) continue;
+ }
chunklen = 8 + si_s + model->inlined[j].length;
h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen);
if(!h) goto memerr;
@@ -4318,14 +5319,14 @@ memerr: if(face) M3D_FREE(face);
}
}
/* extra chunks */
- if(model->numunknown && model->unknown && (flags & M3D_EXP_EXTRA)) {
- for(j = 0; j < model->numunknown; j++) {
- if(!model->unknown[j] || model->unknown[j]->length < 8)
+ if(model->numextra && model->extra && (flags & M3D_EXP_EXTRA)) {
+ for(j = 0; j < model->numextra; j++) {
+ if(!model->extra[j] || model->extra[j]->length < 8)
continue;
- chunklen = model->unknown[j]->length;
+ chunklen = model->extra[j]->length;
h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen);
if(!h) goto memerr;
- memcpy((uint8_t*)h + len, model->unknown[j], chunklen);
+ memcpy((uint8_t*)h + len, model->extra[j], chunklen);
len += chunklen;
}
}
@@ -4336,6 +5337,7 @@ memerr: if(face) M3D_FREE(face);
len += 4;
/* zlib compress */
if(!(flags & M3D_EXP_NOZLIB)) {
+ M3D_LOG("Deflating chunks");
z = stbi_zlib_compress((unsigned char *)h, len, (int*)&l, 9);
if(z && l > 0 && l < len) { len = l; M3D_FREE(h); h = (m3dhdr_t*)z; }
}
@@ -4348,15 +5350,17 @@ memerr: if(face) M3D_FREE(face);
memcpy(out + 8, h, len - 8);
}
if(size) *size = out ? len : 0;
+ if(vrtxidx) M3D_FREE(vrtxidx);
+ if(mtrlidx) M3D_FREE(mtrlidx);
+ if(tmapidx) M3D_FREE(tmapidx);
+ if(skinidx) M3D_FREE(skinidx);
+ if(norm) M3D_FREE(norm);
if(face) M3D_FREE(face);
if(cmap) M3D_FREE(cmap);
if(tmap) M3D_FREE(tmap);
- if(mtrl) M3D_FREE(mtrl);
- if(vrtx) M3D_FREE(vrtx);
- if(bone) M3D_FREE(bone);
if(skin) M3D_FREE(skin);
- if(actn) M3D_FREE(actn);
if(str) M3D_FREE(str);
+ if(vrtx) M3D_FREE(vrtx);
if(h) M3D_FREE(h);
return out;
}
@@ -4397,6 +5401,14 @@ namespace M3D {
this->model = m3d_load((unsigned char *)&data[0], ReadFileCB, FreeCB, mtllib.model);
#else
Model();
+#endif
+ }
+ Model(_unused const unsigned char *data, _unused m3dread_t ReadFileCB,
+ _unused m3dfree_t FreeCB, _unused M3D::Model mtllib) {
+#ifndef M3D_NOIMPORTER
+ this->model = m3d_load((unsigned char*)data, ReadFileCB, FreeCB, mtllib.model);
+#else
+ Model();
#endif
}
~Model() { m3d_free(this->model); }
@@ -4413,6 +5425,9 @@ namespace M3D {
void setDescription(std::string desc) { this->model->desc = (char*)desc.c_str(); }
float getScale() { return this->model->scale; }
void setScale(float scale) { this->model->scale = scale; }
+ std::vector getPreview() { return this->model->preview.data ?
+ std::vector(this->model->preview.data, this->model->preview.data + this->model->preview.length) :
+ std::vector(); }
std::vector getColorMap() { return this->model->cmap ? std::vector(this->model->cmap,
this->model->cmap + this->model->numcmap) : std::vector(); }
std::vector getTextureMap() { return this->model->tmap ? std::vector(this->model->tmap,
@@ -4462,6 +5477,18 @@ namespace M3D {
this->model->vertex + this->model->numvertex) : std::vector(); }
std::vector getFace() { return this->model->face ? std::vector(this->model->face, this->model->face +
this->model->numface) : std::vector(); }
+ std::vector getShape() { return this->model->shape ? std::vector(this->model->shape,
+ this->model->shape + this->model->numshape) : std::vector(); }
+ std::string getShapeName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape &&
+ this->model->shape[idx].name && this->model->shape[idx].name[0] ?
+ std::string(this->model->shape[idx].name) : nullptr; }
+ unsigned int getShapeGroup(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape ?
+ this->model->shape[idx].group : 0xFFFFFFFF; }
+ std::vector getShapeCommands(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape &&
+ this->model->shape[idx].cmd ? std::vector(this->model->shape[idx].cmd, this->model->shape[idx].cmd +
+ this->model->shape[idx].numcmd) : std::vector(); }
+ std::vector getAnnotationLabels() { return this->model->label ? std::vector(this->model->label,
+ this->model->label + this->model->numlabel) : std::vector(); }
std::vector getSkin() { return this->model->skin ? std::vector(this->model->skin, this->model->skin +
this->model->numskin) : std::vector(); }
std::vector getActions() { return this->model->action ? std::vector(this->model->action,
@@ -4491,9 +5518,9 @@ namespace M3D {
return std::vector(pose, pose + this->model->numbone); }
std::vector getInlinedAssets() { return this->model->inlined ? std::vector(this->model->inlined,
this->model->inlined + this->model->numinlined) : std::vector(); }
- std::vector> getUnknowns() { return this->model->unknown ?
- std::vector>(this->model->unknown,
- this->model->unknown + this->model->numunknown) : std::vector>(); }
+ std::vector> getExtras() { return this->model->extra ?
+ std::vector>(this->model->extra,
+ this->model->extra + this->model->numextra) : std::vector>(); }
std::vector Save(_unused int quality, _unused int flags) {
#ifdef M3D_EXPORTER
unsigned int size;
@@ -4513,6 +5540,7 @@ namespace M3D {
public:
Model(const std::string &data, m3dread_t ReadFileCB, m3dfree_t FreeCB);
Model(const std::vector data, m3dread_t ReadFileCB, m3dfree_t FreeCB);
+ Model(const unsigned char *data, m3dread_t ReadFileCB, m3dfree_t FreeCB);
Model();
~Model();
@@ -4528,6 +5556,7 @@ namespace M3D {
void setDescription(std::string desc);
float getScale();
void setScale(float scale);
+ std::vector getPreview();
std::vector getColorMap();
std::vector getTextureMap();
std::vector getTextures();
@@ -4542,6 +5571,11 @@ namespace M3D {
m3dtx_t* getMaterialPropertyMap(int idx, int type);
std::vector getVertices();
std::vector getFace();
+ std::vector getShape();
+ std::string getShapeName(int idx);
+ unsigned int getShapeGroup(int idx);
+ std::vector getShapeCommands(int idx);
+ std::vector getAnnotationLabels();
std::vector getSkin();
std::vector getActions();
std::string getActionName(int aidx);
@@ -4552,7 +5586,7 @@ namespace M3D {
std::vector getActionFrame(int aidx, int fidx, std::vector skeleton);
std::vector getActionPose(int aidx, unsigned int msec);
std::vector getInlinedAssets();
- std::vector> getUnknowns();
+ std::vector> getExtras();
std::vector Save(int quality, int flags);
};
diff --git a/code/Material/MaterialSystem.cpp b/code/Material/MaterialSystem.cpp
index 0be6e9f7b..aa3df9ac2 100644
--- a/code/Material/MaterialSystem.cpp
+++ b/code/Material/MaterialSystem.cpp
@@ -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,
const char* pKey,
unsigned int type,
unsigned int index,
aiUVTransform* pOut)
{
- unsigned int iMax = 4;
+ unsigned int iMax = 5;
return aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax);
}
@@ -471,12 +471,12 @@ aiReturn aiMaterial::AddBinaryProperty (const void* pInput,
aiPropertyTypeInfo pType
)
{
- ai_assert( pInput != NULL );
- ai_assert( pKey != NULL );
+ ai_assert( pInput != nullptr );
+ ai_assert(pKey != nullptr );
ai_assert( 0 != pSizeInBytes );
if ( 0 == pSizeInBytes ) {
-
+ return AI_FAILURE;
}
// first search the list whether there is already an entry with this key
diff --git a/code/PostProcessing/ValidateDataStructure.cpp b/code/PostProcessing/ValidateDataStructure.cpp
index 75d1b6ef7..1dc217663 100644
--- a/code/PostProcessing/ValidateDataStructure.cpp
+++ b/code/PostProcessing/ValidateDataStructure.cpp
@@ -603,15 +603,18 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
ReportError("%s #%i is set, but there are only %i %s textures",
szType,iIndex,iNumIndices,szType);
}
- if (!iNumIndices)return;
+ if (!iNumIndices) {
+ return;
+ }
std::vector mappings(iNumIndices);
// Now check whether all UV indices are valid ...
bool bNoSpecified = true;
- for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
- {
+ for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) {
aiMaterialProperty* prop = pMaterial->mProperties[i];
- if (prop->mSemantic != type)continue;
+ if (prop->mSemantic != type) {
+ continue;
+ }
if ((int)prop->mIndex >= iNumIndices)
{
@@ -634,7 +637,7 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
ReportError("Material property %s%i is expected to be 5 floats large (size is %i)",
prop->mKey.data,prop->mIndex, prop->mDataLength);
}
- mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData);
+ //mappings[prop->mIndex] = ((aiUVTransform*)prop->mData);
}
else if (!::strcmp(prop->mKey.data,"$tex.uvwsrc")) {
if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength)
diff --git a/code/glTF/glTFAsset.inl b/code/glTF/glTFAsset.inl
index f31781a3f..25cf1873c 100644
--- a/code/glTF/glTFAsset.inl
+++ b/code/glTF/glTFAsset.inl
@@ -1427,9 +1427,6 @@ inline void Asset::ReadExtensionsUsed(Document& doc)
}
}
- #define CHECK_EXT(EXT) \
- if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
-
CHECK_EXT(KHR_binary_glTF);
CHECK_EXT(KHR_materials_common);
diff --git a/code/glTF/glTFCommon.h b/code/glTF/glTFCommon.h
index d9edee75e..b2e28d580 100644
--- a/code/glTF/glTFCommon.h
+++ b/code/glTF/glTFCommon.h
@@ -188,7 +188,7 @@ namespace glTFCommon {
size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out);
inline
- size_t DecodeBase64(const char* in, uint8_t*& out) {
+ size_t DecodeBase64(const char* in, uint8_t*& out) {
return DecodeBase64(in, strlen(in), out);
}
@@ -221,25 +221,22 @@ namespace glTFCommon {
};
inline
- char EncodeCharBase64(uint8_t b) {
+ char EncodeCharBase64(uint8_t b) {
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)];
}
inline
- uint8_t DecodeCharBase64(char c) {
+ uint8_t DecodeCharBase64(char c) {
return DATA::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs?
- /*if (c >= 'A' && c <= 'Z') return c - 'A';
- if (c >= 'a' && c <= 'z') return c - 'a' + 26;
- if (c >= '0' && c <= '9') return c - '0' + 52;
- if (c == '+') return 62;
- if (c == '/') return 63;
- return 64; // '-' */
}
size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out);
void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out);
- }
+ } // namespace Util
+
+#define CHECK_EXT(EXT) \
+ if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
}
diff --git a/code/glTF2/glTF2Asset.h b/code/glTF2/glTF2Asset.h
index 15c4c44fa..d13ebfd66 100644
--- a/code/glTF2/glTF2Asset.h
+++ b/code/glTF2/glTF2Asset.h
@@ -685,6 +685,13 @@ namespace glTF2
Ref texture;
unsigned int index;
unsigned int texCoord = 0;
+
+ bool textureTransformSupported = false;
+ struct TextureTransformExt {
+ float offset[2];
+ float rotation;
+ float scale[2];
+ } TextureTransformExt_t;
};
struct NormalTextureInfo : TextureInfo
@@ -1024,9 +1031,15 @@ namespace glTF2
bool KHR_materials_pbrSpecularGlossiness;
bool KHR_materials_unlit;
bool KHR_lights_punctual;
-
+ bool KHR_texture_transform;
} extensionsUsed;
+ //! Keeps info about the required extensions
+ struct RequiredExtensions
+ {
+ bool KHR_draco_mesh_compression;
+ } extensionsRequired;
+
AssetMetadata asset;
@@ -1069,6 +1082,7 @@ namespace glTF2
, textures (*this, "textures")
{
memset(&extensionsUsed, 0, sizeof(extensionsUsed));
+ memset(&extensionsRequired, 0, sizeof(extensionsRequired));
}
//! Main function
@@ -1087,6 +1101,7 @@ namespace glTF2
void ReadBinaryHeader(IOStream& stream, std::vector& sceneData);
void ReadExtensionsUsed(Document& doc);
+ void ReadExtensionsRequired(Document& doc);
IOStream* OpenFile(std::string path, const char* mode, bool absolute = false);
};
diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl
index 6b47b1607..99f8c876f 100644
--- a/code/glTF2/glTF2Asset.inl
+++ b/code/glTF2/glTF2Asset.inl
@@ -800,8 +800,34 @@ inline void Texture::Read(Value& obj, Asset& r)
}
namespace {
- inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out)
- {
+ inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out) {
+ if (r.extensionsUsed.KHR_texture_transform) {
+ if (Value *extensions = FindObject(*prop, "extensions")) {
+ out.textureTransformSupported = true;
+ if (Value *pKHR_texture_transform = FindObject(*extensions, "KHR_texture_transform")) {
+ if (Value *array = FindArray(*pKHR_texture_transform, "offset")) {
+ out.TextureTransformExt_t.offset[0] = (*array)[0].GetFloat();
+ out.TextureTransformExt_t.offset[1] = (*array)[1].GetFloat();
+ } else {
+ out.TextureTransformExt_t.offset[0] = 0;
+ out.TextureTransformExt_t.offset[1] = 0;
+ }
+
+ if (!ReadMember(*pKHR_texture_transform, "rotation", out.TextureTransformExt_t.rotation)) {
+ out.TextureTransformExt_t.rotation = 0;
+ }
+
+ if (Value *array = FindArray(*pKHR_texture_transform, "scale")) {
+ out.TextureTransformExt_t.scale[0] = (*array)[0].GetFloat();
+ out.TextureTransformExt_t.scale[1] = (*array)[1].GetFloat();
+ } else {
+ out.TextureTransformExt_t.scale[0] = 1;
+ out.TextureTransformExt_t.scale[1] = 1;
+ }
+ }
+ }
+ }
+
if (Value* index = FindUInt(*prop, "index")) {
out.texture = r.textures.Retrieve(index->GetUint());
}
@@ -877,6 +903,9 @@ inline void Material::Read(Value& material, Asset& r)
}
}
+ if (r.extensionsUsed.KHR_texture_transform) {
+ }
+
unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit");
}
}
@@ -1403,6 +1432,12 @@ inline void Asset::Load(const std::string& pFile, bool isBinary)
// Load the metadata
asset.Read(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
for (size_t i = 0; i < mDicts.size(); ++i) {
@@ -1449,6 +1484,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 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)
{
@@ -1463,12 +1521,10 @@ inline void Asset::ReadExtensionsUsed(Document& doc)
}
}
- #define CHECK_EXT(EXT) \
- if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
-
CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
CHECK_EXT(KHR_materials_unlit);
CHECK_EXT(KHR_lights_punctual);
+ CHECK_EXT(KHR_texture_transform);
#undef CHECK_EXT
}
diff --git a/code/glTF2/glTF2Exporter.h b/code/glTF2/glTF2Exporter.h
index 2dc083709..b527c4bc9 100644
--- a/code/glTF2/glTF2Exporter.h
+++ b/code/glTF2/glTF2Exporter.h
@@ -74,6 +74,7 @@ namespace glTF2
struct Texture;
// Vec/matrix types, as raw float arrays
+ typedef float (vec2)[2];
typedef float (vec3)[3];
typedef float (vec4)[4];
}
diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp
index b3141fd96..dd80aeba9 100644
--- a/code/glTF2/glTF2Importer.cpp
+++ b/code/glTF2/glTF2Importer.cpp
@@ -43,18 +43,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
#include "glTF2/glTF2Importer.h"
+#include "PostProcessing/MakeVerboseFormat.h"
#include "glTF2/glTF2Asset.h"
#include "glTF2/glTF2AssetWriter.h"
-#include "PostProcessing/MakeVerboseFormat.h"
+#include
#include
#include
-#include
-#include
#include
-#include
#include
-#include
+#include
+#include
+#include
#include
#include
@@ -67,11 +67,11 @@ using namespace glTF2;
using namespace glTFCommon;
namespace {
- // generate bi-tangents from normals and tangents according to spec
- struct Tangent {
- aiVector3D xyz;
- ai_real w;
- };
+// generate bi-tangents from normals and tangents according to spec
+struct Tangent {
+ aiVector3D xyz;
+ ai_real w;
+};
} // namespace
//
@@ -79,66 +79,63 @@ namespace {
//
static const aiImporterDesc desc = {
- "glTF2 Importer",
- "",
- "",
- "",
- aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
- 0,
- 0,
- 0,
- 0,
- "gltf glb"
+ "glTF2 Importer",
+ "",
+ "",
+ "",
+ aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
+ 0,
+ 0,
+ 0,
+ 0,
+ "gltf glb"
};
-glTF2Importer::glTF2Importer()
-: BaseImporter()
-, meshOffsets()
-, embeddedTexIdxs()
-, mScene( NULL ) {
- // empty
+glTF2Importer::glTF2Importer() :
+ BaseImporter(),
+ meshOffsets(),
+ embeddedTexIdxs(),
+ mScene(NULL) {
+ // empty
}
glTF2Importer::~glTF2Importer() {
- // empty
+ // empty
}
-const aiImporterDesc* glTF2Importer::GetInfo() const
-{
- return &desc;
+const aiImporterDesc *glTF2Importer::GetInfo() const {
+ return &desc;
}
-bool glTF2Importer::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool /* checkSig */) const
-{
- const std::string &extension = GetExtension(pFile);
+bool glTF2Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const {
+ const std::string &extension = GetExtension(pFile);
- if (extension != "gltf" && extension != "glb")
- return false;
+ if (extension != "gltf" && extension != "glb")
+ return false;
- if (pIOHandler) {
- glTF2::Asset asset(pIOHandler);
- asset.Load(pFile, extension == "glb");
- std::string version = asset.asset.version;
- return !version.empty() && version[0] == '2';
- }
+ if (pIOHandler) {
+ glTF2::Asset asset(pIOHandler);
+ asset.Load(pFile, extension == "glb");
+ std::string version = asset.asset.version;
+ return !version.empty() && version[0] == '2';
+ }
- return false;
+ return false;
}
-static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode)
-{
- switch (gltfWrapMode) {
- case SamplerWrap::Mirrored_Repeat:
- return aiTextureMapMode_Mirror;
+static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) {
+ switch (gltfWrapMode) {
+ case SamplerWrap::Mirrored_Repeat:
+ return aiTextureMapMode_Mirror;
- case SamplerWrap::Clamp_To_Edge:
- return aiTextureMapMode_Clamp;
+ case SamplerWrap::Clamp_To_Edge:
+ return aiTextureMapMode_Clamp;
- case SamplerWrap::UNSET:
- case SamplerWrap::Repeat:
- default:
- return aiTextureMapMode_Wrap;
- }
+ case SamplerWrap::UNSET:
+ case SamplerWrap::Repeat:
+ default:
+ return aiTextureMapMode_Wrap;
+ }
}
/*static void CopyValue(const glTF2::vec3& v, aiColor3D& out)
@@ -180,1182 +177,1160 @@ static void CopyValue(const glTF2::vec4& v, aiQuaternion& out)
o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15];
}*/
-inline void SetMaterialColorProperty(Asset& /*r*/, vec4& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx)
-{
- aiColor4D col;
- CopyValue(prop, col);
- mat->AddProperty(&col, 1, pKey, type, idx);
+inline void SetMaterialColorProperty(Asset & /*r*/, vec4 &prop, aiMaterial *mat, const char *pKey, unsigned int type, unsigned int idx) {
+ aiColor4D col;
+ CopyValue(prop, col);
+ mat->AddProperty(&col, 1, pKey, type, idx);
}
-inline void SetMaterialColorProperty(Asset& /*r*/, vec3& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx)
-{
- aiColor4D col;
- glTFCommon::CopyValue(prop, col);
- mat->AddProperty(&col, 1, pKey, type, idx);
+inline void SetMaterialColorProperty(Asset & /*r*/, vec3 &prop, aiMaterial *mat, const char *pKey, unsigned int type, unsigned int idx) {
+ aiColor4D col;
+ glTFCommon::CopyValue(prop, col);
+ mat->AddProperty(&col, 1, pKey, type, idx);
}
-inline void SetMaterialTextureProperty(std::vector& embeddedTexIdxs, Asset& /*r*/, glTF2::TextureInfo prop, aiMaterial* mat, aiTextureType texType, unsigned int texSlot = 0)
-{
- if (prop.texture && prop.texture->source) {
- aiString uri(prop.texture->source->uri);
+inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset & /*r*/, glTF2::TextureInfo prop, aiMaterial *mat, aiTextureType texType, unsigned int texSlot = 0) {
+ if (prop.texture && prop.texture->source) {
+ aiString uri(prop.texture->source->uri);
- int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()];
- if (texIdx != -1) { // embedded
- // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
- uri.data[0] = '*';
- uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx);
- }
+ int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()];
+ if (texIdx != -1) { // embedded
+ // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
+ uri.data[0] = '*';
+ uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx);
+ }
mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot));
- mat->AddProperty(&prop.texCoord, 1, _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, texType, texSlot);
- if (prop.texture->sampler) {
- Ref sampler = prop.texture->sampler;
+ if (prop.textureTransformSupported) {
+ aiUVTransform transform;
+ transform.mScaling.x = prop.TextureTransformExt_t.scale[0];
+ transform.mScaling.y = prop.TextureTransformExt_t.scale[1];
+ transform.mRotation = -prop.TextureTransformExt_t.rotation; // must be negated
- aiString name(sampler->name);
- aiString id(sampler->id);
+ // 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(&name, AI_MATKEY_GLTF_MAPPINGNAME(texType, texSlot));
- mat->AddProperty(&id, AI_MATKEY_GLTF_MAPPINGID(texType, texSlot));
+ mat->AddProperty(&transform, 1, _AI_MATKEY_UVTRANSFORM_BASE, texType, texSlot);
+ }
- aiTextureMapMode wrapS = ConvertWrappingMode(sampler->wrapS);
- aiTextureMapMode wrapT = ConvertWrappingMode(sampler->wrapT);
- mat->AddProperty(&wrapS, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot));
- mat->AddProperty(&wrapT, 1, AI_MATKEY_MAPPINGMODE_V(texType, texSlot));
+ if (prop.texture->sampler) {
+ Ref sampler = prop.texture->sampler;
- if (sampler->magFilter != SamplerMagFilter::UNSET) {
- mat->AddProperty(&sampler->magFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(texType, texSlot));
- }
+ aiString name(sampler->name);
+ aiString id(sampler->id);
- if (sampler->minFilter != SamplerMinFilter::UNSET) {
- mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(texType, texSlot));
- }
- }
- }
+ mat->AddProperty(&name, AI_MATKEY_GLTF_MAPPINGNAME(texType, texSlot));
+ mat->AddProperty(&id, AI_MATKEY_GLTF_MAPPINGID(texType, texSlot));
+
+ aiTextureMapMode wrapS = ConvertWrappingMode(sampler->wrapS);
+ aiTextureMapMode wrapT = ConvertWrappingMode(sampler->wrapT);
+ mat->AddProperty(&wrapS, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot));
+ mat->AddProperty(&wrapT, 1, AI_MATKEY_MAPPINGMODE_V(texType, texSlot));
+
+ if (sampler->magFilter != SamplerMagFilter::UNSET) {
+ mat->AddProperty(&sampler->magFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(texType, texSlot));
+ }
+
+ if (sampler->minFilter != SamplerMinFilter::UNSET) {
+ mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(texType, texSlot));
+ }
+ }
+ }
}
-inline void SetMaterialTextureProperty(std::vector& embeddedTexIdxs, Asset& r, glTF2::NormalTextureInfo& prop, aiMaterial* mat, aiTextureType texType, unsigned int texSlot = 0)
-{
- SetMaterialTextureProperty( embeddedTexIdxs, r, (glTF2::TextureInfo) prop, mat, texType, texSlot );
+inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset &r, glTF2::NormalTextureInfo &prop, aiMaterial *mat, aiTextureType texType, unsigned int texSlot = 0) {
+ SetMaterialTextureProperty(embeddedTexIdxs, r, (glTF2::TextureInfo)prop, mat, texType, texSlot);
- if (prop.texture && prop.texture->source) {
- mat->AddProperty(&prop.scale, 1, AI_MATKEY_GLTF_TEXTURE_SCALE(texType, texSlot));
- }
+ if (prop.texture && prop.texture->source) {
+ mat->AddProperty(&prop.scale, 1, AI_MATKEY_GLTF_TEXTURE_SCALE(texType, texSlot));
+ }
}
-inline void SetMaterialTextureProperty(std::vector& embeddedTexIdxs, Asset& r, glTF2::OcclusionTextureInfo& prop, aiMaterial* mat, aiTextureType texType, unsigned int texSlot = 0)
-{
- SetMaterialTextureProperty( embeddedTexIdxs, r, (glTF2::TextureInfo) prop, mat, texType, texSlot );
+inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset &r, glTF2::OcclusionTextureInfo &prop, aiMaterial *mat, aiTextureType texType, unsigned int texSlot = 0) {
+ SetMaterialTextureProperty(embeddedTexIdxs, r, (glTF2::TextureInfo)prop, mat, texType, texSlot);
- if (prop.texture && prop.texture->source) {
- mat->AddProperty(&prop.strength, 1, AI_MATKEY_GLTF_TEXTURE_STRENGTH(texType, texSlot));
- }
+ if (prop.texture && prop.texture->source) {
+ mat->AddProperty(&prop.strength, 1, AI_MATKEY_GLTF_TEXTURE_STRENGTH(texType, texSlot));
+ }
}
-static aiMaterial* ImportMaterial(std::vector& embeddedTexIdxs, Asset& r, Material& mat)
-{
- aiMaterial* aimat = new aiMaterial();
+static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, Material &mat) {
+ aiMaterial *aimat = new aiMaterial();
- if (!mat.name.empty()) {
- aiString str(mat.name);
+ if (!mat.name.empty()) {
+ aiString str(mat.name);
- aimat->AddProperty(&str, AI_MATKEY_NAME);
- }
+ aimat->AddProperty(&str, AI_MATKEY_NAME);
+ }
- SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE);
- SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR);
+ SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE);
+ SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR);
- SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE);
- SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE);
+ SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE);
+ SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE);
- SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
+ SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
- aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR);
- aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR);
+ aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR);
+ aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR);
- float roughnessAsShininess = 1 - mat.pbrMetallicRoughness.roughnessFactor;
- roughnessAsShininess *= roughnessAsShininess * 1000;
- aimat->AddProperty(&roughnessAsShininess, 1, AI_MATKEY_SHININESS);
+ float roughnessAsShininess = 1 - mat.pbrMetallicRoughness.roughnessFactor;
+ roughnessAsShininess *= roughnessAsShininess * 1000;
+ aimat->AddProperty(&roughnessAsShininess, 1, AI_MATKEY_SHININESS);
- SetMaterialTextureProperty(embeddedTexIdxs, r, mat.normalTexture, aimat, aiTextureType_NORMALS);
- SetMaterialTextureProperty(embeddedTexIdxs, r, mat.occlusionTexture, aimat, aiTextureType_LIGHTMAP);
- SetMaterialTextureProperty(embeddedTexIdxs, r, mat.emissiveTexture, aimat, aiTextureType_EMISSIVE);
- SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE);
+ SetMaterialTextureProperty(embeddedTexIdxs, r, mat.normalTexture, aimat, aiTextureType_NORMALS);
+ SetMaterialTextureProperty(embeddedTexIdxs, r, mat.occlusionTexture, aimat, aiTextureType_LIGHTMAP);
+ SetMaterialTextureProperty(embeddedTexIdxs, r, mat.emissiveTexture, aimat, aiTextureType_EMISSIVE);
+ SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE);
- aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED);
+ aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED);
- aiString alphaMode(mat.alphaMode);
- aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE);
- aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF);
+ aiString alphaMode(mat.alphaMode);
+ aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE);
+ aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF);
- //pbrSpecularGlossiness
- if (mat.pbrSpecularGlossiness.isPresent) {
- PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value;
+ //pbrSpecularGlossiness
+ if (mat.pbrSpecularGlossiness.isPresent) {
+ PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value;
- aimat->AddProperty(&mat.pbrSpecularGlossiness.isPresent, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS);
- SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE);
- SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_COLOR_SPECULAR);
+ aimat->AddProperty(&mat.pbrSpecularGlossiness.isPresent, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS);
+ SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE);
+ SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_COLOR_SPECULAR);
- float glossinessAsShininess = pbrSG.glossinessFactor * 1000.0f;
- aimat->AddProperty(&glossinessAsShininess, 1, AI_MATKEY_SHININESS);
- aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR);
+ float glossinessAsShininess = pbrSG.glossinessFactor * 1000.0f;
+ aimat->AddProperty(&glossinessAsShininess, 1, AI_MATKEY_SHININESS);
+ aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR);
- SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, aiTextureType_DIFFUSE);
+ SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, aiTextureType_DIFFUSE);
- SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, aiTextureType_SPECULAR);
- }
- if (mat.unlit) {
- aimat->AddProperty(&mat.unlit, 1, AI_MATKEY_GLTF_UNLIT);
- }
+ SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, aiTextureType_SPECULAR);
+ }
+ if (mat.unlit) {
+ aimat->AddProperty(&mat.unlit, 1, AI_MATKEY_GLTF_UNLIT);
+ }
- return aimat;
+ return aimat;
}
-void glTF2Importer::ImportMaterials(glTF2::Asset& r)
-{
- const unsigned int numImportedMaterials = unsigned(r.materials.Size());
- Material defaultMaterial;
+void glTF2Importer::ImportMaterials(glTF2::Asset &r) {
+ const unsigned int numImportedMaterials = unsigned(r.materials.Size());
+ Material defaultMaterial;
- mScene->mNumMaterials = numImportedMaterials + 1;
- mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials];
- mScene->mMaterials[numImportedMaterials] = ImportMaterial(embeddedTexIdxs, r, defaultMaterial);
+ mScene->mNumMaterials = numImportedMaterials + 1;
+ mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials];
+ mScene->mMaterials[numImportedMaterials] = ImportMaterial(embeddedTexIdxs, r, defaultMaterial);
- for (unsigned int i = 0; i < numImportedMaterials; ++i) {
- mScene->mMaterials[i] = ImportMaterial(embeddedTexIdxs, r, r.materials[i]);
- }
+ for (unsigned int i = 0; i < numImportedMaterials; ++i) {
+ mScene->mMaterials[i] = ImportMaterial(embeddedTexIdxs, r, r.materials[i]);
+ }
}
-
-static inline void SetFace(aiFace& face, int a)
-{
- face.mNumIndices = 1;
- face.mIndices = new unsigned int[1];
- face.mIndices[0] = a;
+static inline void SetFace(aiFace &face, int a) {
+ face.mNumIndices = 1;
+ face.mIndices = new unsigned int[1];
+ face.mIndices[0] = a;
}
-static inline void SetFace(aiFace& face, int a, int b)
-{
- face.mNumIndices = 2;
- face.mIndices = new unsigned int[2];
- face.mIndices[0] = a;
- face.mIndices[1] = b;
+static inline void SetFace(aiFace &face, int a, int b) {
+ face.mNumIndices = 2;
+ face.mIndices = new unsigned int[2];
+ face.mIndices[0] = a;
+ face.mIndices[1] = b;
}
-static inline void SetFace(aiFace& face, int a, int b, int c)
-{
- face.mNumIndices = 3;
- face.mIndices = new unsigned int[3];
- face.mIndices[0] = a;
- face.mIndices[1] = b;
- face.mIndices[2] = c;
+static inline void SetFace(aiFace &face, int a, int b, int c) {
+ face.mNumIndices = 3;
+ face.mIndices = new unsigned int[3];
+ face.mIndices[0] = a;
+ face.mIndices[1] = b;
+ face.mIndices[2] = c;
}
#ifdef ASSIMP_BUILD_DEBUG
-static inline bool CheckValidFacesIndices(aiFace* faces, unsigned nFaces, unsigned nVerts)
-{
- for (unsigned i = 0; i < nFaces; ++i) {
- for (unsigned j = 0; j < faces[i].mNumIndices; ++j) {
- unsigned idx = faces[i].mIndices[j];
- if (idx >= nVerts)
- return false;
- }
- }
- return true;
+static inline bool CheckValidFacesIndices(aiFace *faces, unsigned nFaces, unsigned nVerts) {
+ for (unsigned i = 0; i < nFaces; ++i) {
+ for (unsigned j = 0; j < faces[i].mNumIndices; ++j) {
+ unsigned idx = faces[i].mIndices[j];
+ if (idx >= nVerts)
+ return false;
+ }
+ }
+ return true;
}
#endif // ASSIMP_BUILD_DEBUG
-void glTF2Importer::ImportMeshes(glTF2::Asset& r)
-{
- std::vector meshes;
+void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
+ std::vector meshes;
- unsigned int k = 0;
+ unsigned int k = 0;
- for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
- Mesh& mesh = r.meshes[m];
+ for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
+ Mesh &mesh = r.meshes[m];
- meshOffsets.push_back(k);
- k += unsigned(mesh.primitives.size());
+ meshOffsets.push_back(k);
+ k += unsigned(mesh.primitives.size());
- for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
- Mesh::Primitive& prim = mesh.primitives[p];
+ for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
+ Mesh::Primitive &prim = mesh.primitives[p];
- aiMesh* aim = new aiMesh();
- meshes.push_back(aim);
+ aiMesh *aim = new aiMesh();
+ meshes.push_back(aim);
- aim->mName = mesh.name.empty() ? mesh.id : mesh.name;
+ aim->mName = mesh.name.empty() ? mesh.id : mesh.name;
- if (mesh.primitives.size() > 1) {
- ai_uint32& len = aim->mName.length;
- aim->mName.data[len] = '-';
- len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p);
- }
+ if (mesh.primitives.size() > 1) {
+ ai_uint32 &len = aim->mName.length;
+ aim->mName.data[len] = '-';
+ len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p);
+ }
- switch (prim.mode) {
- case PrimitiveMode_POINTS:
- aim->mPrimitiveTypes |= aiPrimitiveType_POINT;
- break;
+ switch (prim.mode) {
+ case PrimitiveMode_POINTS:
+ aim->mPrimitiveTypes |= aiPrimitiveType_POINT;
+ break;
- case PrimitiveMode_LINES:
- case PrimitiveMode_LINE_LOOP:
- case PrimitiveMode_LINE_STRIP:
- aim->mPrimitiveTypes |= aiPrimitiveType_LINE;
- break;
+ case PrimitiveMode_LINES:
+ case PrimitiveMode_LINE_LOOP:
+ case PrimitiveMode_LINE_STRIP:
+ aim->mPrimitiveTypes |= aiPrimitiveType_LINE;
+ break;
- case PrimitiveMode_TRIANGLES:
- case PrimitiveMode_TRIANGLE_STRIP:
- case PrimitiveMode_TRIANGLE_FAN:
- aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
- break;
+ case PrimitiveMode_TRIANGLES:
+ case PrimitiveMode_TRIANGLE_STRIP:
+ case PrimitiveMode_TRIANGLE_FAN:
+ aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
+ break;
+ }
- }
+ Mesh::Primitive::Attributes &attr = prim.attributes;
- Mesh::Primitive::Attributes& attr = prim.attributes;
+ if (attr.position.size() > 0 && attr.position[0]) {
+ aim->mNumVertices = static_cast(attr.position[0]->count);
+ attr.position[0]->ExtractData(aim->mVertices);
+ }
- if (attr.position.size() > 0 && attr.position[0]) {
- aim->mNumVertices = static_cast(attr.position[0]->count);
- attr.position[0]->ExtractData(aim->mVertices);
- }
+ if (attr.normal.size() > 0 && attr.normal[0]) {
+ attr.normal[0]->ExtractData(aim->mNormals);
- if (attr.normal.size() > 0 && attr.normal[0]) {
- attr.normal[0]->ExtractData(aim->mNormals);
+ // only extract tangents if normals are present
+ if (attr.tangent.size() > 0 && attr.tangent[0]) {
+ // generate bitangents from normals and tangents according to spec
+ Tangent *tangents = nullptr;
- // only extract tangents if normals are present
- if (attr.tangent.size() > 0 && attr.tangent[0]) {
- // generate bitangents from normals and tangents according to spec
- Tangent *tangents = nullptr;
+ attr.tangent[0]->ExtractData(tangents);
- attr.tangent[0]->ExtractData(tangents);
+ aim->mTangents = new aiVector3D[aim->mNumVertices];
+ aim->mBitangents = new aiVector3D[aim->mNumVertices];
- aim->mTangents = new aiVector3D[aim->mNumVertices];
- aim->mBitangents = new aiVector3D[aim->mNumVertices];
+ for (unsigned int i = 0; i < aim->mNumVertices; ++i) {
+ aim->mTangents[i] = tangents[i].xyz;
+ aim->mBitangents[i] = (aim->mNormals[i] ^ tangents[i].xyz) * tangents[i].w;
+ }
- for (unsigned int i = 0; i < aim->mNumVertices; ++i) {
- aim->mTangents[i] = tangents[i].xyz;
- aim->mBitangents[i] = (aim->mNormals[i] ^ tangents[i].xyz) * tangents[i].w;
- }
+ delete[] tangents;
+ }
+ }
- delete [] tangents;
- }
- }
+ for (size_t c = 0; c < attr.color.size() && c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c) {
+ if (attr.color[c]->count != aim->mNumVertices) {
+ DefaultLogger::get()->warn("Color stream size in mesh \"" + mesh.name +
+ "\" does not match the vertex count");
+ continue;
+ }
+ attr.color[c]->ExtractData(aim->mColors[c]);
+ }
+ for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
+ if (attr.texcoord[tc]->count != aim->mNumVertices) {
+ DefaultLogger::get()->warn("Texcoord stream size in mesh \"" + mesh.name +
+ "\" does not match the vertex count");
+ continue;
+ }
- for (size_t c = 0; c < attr.color.size() && c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c) {
- if (attr.color[c]->count != aim->mNumVertices) {
- DefaultLogger::get()->warn("Color stream size in mesh \"" + mesh.name +
- "\" does not match the vertex count");
- continue;
- }
- attr.color[c]->ExtractData(aim->mColors[c]);
- }
- for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
- if (attr.texcoord[tc]->count != aim->mNumVertices) {
- DefaultLogger::get()->warn("Texcoord stream size in mesh \"" + mesh.name +
- "\" does not match the vertex count");
- continue;
- }
+ attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
+ aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
- attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
- aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
+ aiVector3D *values = aim->mTextureCoords[tc];
+ for (unsigned int i = 0; i < aim->mNumVertices; ++i) {
+ values[i].y = 1 - values[i].y; // Flip Y coords
+ }
+ }
- aiVector3D* values = aim->mTextureCoords[tc];
- for (unsigned int i = 0; i < aim->mNumVertices; ++i) {
- values[i].y = 1 - values[i].y; // Flip Y coords
- }
- }
+ std::vector &targets = prim.targets;
+ if (targets.size() > 0) {
+ aim->mNumAnimMeshes = (unsigned int)targets.size();
+ aim->mAnimMeshes = new aiAnimMesh *[aim->mNumAnimMeshes];
+ for (size_t i = 0; i < targets.size(); i++) {
+ aim->mAnimMeshes[i] = aiCreateAnimMesh(aim);
+ aiAnimMesh &aiAnimMesh = *(aim->mAnimMeshes[i]);
+ Mesh::Primitive::Target &target = targets[i];
- std::vector& targets = prim.targets;
- if (targets.size() > 0) {
- aim->mNumAnimMeshes = (unsigned int)targets.size();
- aim->mAnimMeshes = new aiAnimMesh*[aim->mNumAnimMeshes];
- for (size_t i = 0; i < targets.size(); i++) {
- aim->mAnimMeshes[i] = aiCreateAnimMesh(aim);
- aiAnimMesh& aiAnimMesh = *(aim->mAnimMeshes[i]);
- Mesh::Primitive::Target& target = targets[i];
+ if (target.position.size() > 0) {
+ aiVector3D *positionDiff = nullptr;
+ target.position[0]->ExtractData(positionDiff);
+ for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
+ aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId];
+ }
+ delete[] positionDiff;
+ }
+ if (target.normal.size() > 0) {
+ aiVector3D *normalDiff = nullptr;
+ target.normal[0]->ExtractData(normalDiff);
+ for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
+ aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId];
+ }
+ delete[] normalDiff;
+ }
+ if (target.tangent.size() > 0) {
+ Tangent *tangent = nullptr;
+ attr.tangent[0]->ExtractData(tangent);
- if (target.position.size() > 0) {
- aiVector3D *positionDiff = nullptr;
- target.position[0]->ExtractData(positionDiff);
- for(unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
- aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId];
- }
- delete [] positionDiff;
- }
- if (target.normal.size() > 0) {
- aiVector3D *normalDiff = nullptr;
- target.normal[0]->ExtractData(normalDiff);
- for(unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
- aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId];
- }
- delete [] normalDiff;
- }
- if (target.tangent.size() > 0) {
- Tangent *tangent = nullptr;
- attr.tangent[0]->ExtractData(tangent);
+ aiVector3D *tangentDiff = nullptr;
+ target.tangent[0]->ExtractData(tangentDiff);
- aiVector3D *tangentDiff = nullptr;
- target.tangent[0]->ExtractData(tangentDiff);
+ for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; ++vertexId) {
+ tangent[vertexId].xyz += tangentDiff[vertexId];
+ aiAnimMesh.mTangents[vertexId] = tangent[vertexId].xyz;
+ aiAnimMesh.mBitangents[vertexId] = (aiAnimMesh.mNormals[vertexId] ^ tangent[vertexId].xyz) * tangent[vertexId].w;
+ }
+ delete[] tangent;
+ delete[] tangentDiff;
+ }
+ if (mesh.weights.size() > i) {
+ aiAnimMesh.mWeight = mesh.weights[i];
+ }
+ }
+ }
- for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; ++vertexId) {
- tangent[vertexId].xyz += tangentDiff[vertexId];
- aiAnimMesh.mTangents[vertexId] = tangent[vertexId].xyz;
- aiAnimMesh.mBitangents[vertexId] = (aiAnimMesh.mNormals[vertexId] ^ tangent[vertexId].xyz) * tangent[vertexId].w;
- }
- delete [] tangent;
- delete [] tangentDiff;
- }
- if (mesh.weights.size() > i) {
- aiAnimMesh.mWeight = mesh.weights[i];
- }
- }
- }
+ aiFace *faces = 0;
+ size_t nFaces = 0;
+ if (prim.indices) {
+ size_t count = prim.indices->count;
- aiFace* faces = 0;
- size_t nFaces = 0;
+ Accessor::Indexer data = prim.indices->GetIndexer();
+ ai_assert(data.IsValid());
- if (prim.indices) {
- size_t count = prim.indices->count;
+ switch (prim.mode) {
+ case PrimitiveMode_POINTS: {
+ nFaces = count;
+ faces = new aiFace[nFaces];
+ for (unsigned int i = 0; i < count; ++i) {
+ SetFace(faces[i], data.GetUInt(i));
+ }
+ break;
+ }
- Accessor::Indexer data = prim.indices->GetIndexer();
- ai_assert(data.IsValid());
+ case PrimitiveMode_LINES: {
+ nFaces = count / 2;
+ if (nFaces * 2 != count) {
+ ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
+ count = nFaces * 2;
+ }
+ faces = new aiFace[nFaces];
+ for (unsigned int i = 0; i < count; i += 2) {
+ SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
+ }
+ break;
+ }
- switch (prim.mode) {
- case PrimitiveMode_POINTS: {
- nFaces = count;
- faces = new aiFace[nFaces];
- for (unsigned int i = 0; i < count; ++i) {
- SetFace(faces[i], data.GetUInt(i));
- }
- break;
- }
+ case PrimitiveMode_LINE_LOOP:
+ case PrimitiveMode_LINE_STRIP: {
+ nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
+ faces = new aiFace[nFaces];
+ SetFace(faces[0], data.GetUInt(0), data.GetUInt(1));
+ for (unsigned int i = 2; i < count; ++i) {
+ SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i));
+ }
+ if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
+ SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
+ }
+ break;
+ }
- case PrimitiveMode_LINES: {
- nFaces = count / 2;
- if (nFaces * 2 != count) {
- ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
- count = nFaces * 2;
- }
- faces = new aiFace[nFaces];
- for (unsigned int i = 0; i < count; i += 2) {
- SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
- }
- break;
- }
+ case PrimitiveMode_TRIANGLES: {
+ nFaces = count / 3;
+ if (nFaces * 3 != count) {
+ ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
+ count = nFaces * 3;
+ }
+ faces = new aiFace[nFaces];
+ for (unsigned int i = 0; i < count; i += 3) {
+ SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
+ }
+ break;
+ }
+ case PrimitiveMode_TRIANGLE_STRIP: {
+ nFaces = count - 2;
+ faces = new aiFace[nFaces];
+ for (unsigned int i = 0; i < nFaces; ++i) {
+ //The ordering is to ensure that the triangles are all drawn with the same orientation
+ if ((i + 1) % 2 == 0) {
+ //For even n, vertices n + 1, n, and n + 2 define triangle n
+ SetFace(faces[i], data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2));
+ } else {
+ //For odd n, vertices n, n+1, and n+2 define triangle n
+ SetFace(faces[i], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
+ }
+ }
+ break;
+ }
+ case PrimitiveMode_TRIANGLE_FAN:
+ nFaces = count - 2;
+ faces = new aiFace[nFaces];
+ SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
+ for (unsigned int i = 1; i < nFaces; ++i) {
+ SetFace(faces[i], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i + 2));
+ }
+ break;
+ }
+ } else { // no indices provided so directly generate from counts
- case PrimitiveMode_LINE_LOOP:
- case PrimitiveMode_LINE_STRIP: {
- nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
- faces = new aiFace[nFaces];
- SetFace(faces[0], data.GetUInt(0), data.GetUInt(1));
- for (unsigned int i = 2; i < count; ++i) {
- SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i));
- }
- if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
- SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
- }
- break;
- }
+ // use the already determined count as it includes checks
+ unsigned int count = aim->mNumVertices;
- case PrimitiveMode_TRIANGLES: {
- nFaces = count / 3;
- if (nFaces * 3 != count) {
- ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
- count = nFaces * 3;
- }
- faces = new aiFace[nFaces];
- for (unsigned int i = 0; i < count; i += 3) {
- SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
- }
- break;
- }
- case PrimitiveMode_TRIANGLE_STRIP: {
- nFaces = count - 2;
- faces = new aiFace[nFaces];
- for (unsigned int i = 0; i < nFaces; ++i) {
- //The ordering is to ensure that the triangles are all drawn with the same orientation
- if ((i + 1) % 2 == 0)
- {
- //For even n, vertices n + 1, n, and n + 2 define triangle n
- SetFace(faces[i], data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2));
- }
- else
- {
- //For odd n, vertices n, n+1, and n+2 define triangle n
- SetFace(faces[i], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
- }
- }
- break;
- }
- case PrimitiveMode_TRIANGLE_FAN:
- nFaces = count - 2;
- faces = new aiFace[nFaces];
- SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
- for (unsigned int i = 1; i < nFaces; ++i) {
- SetFace(faces[i], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i + 2));
- }
- break;
- }
- }
- else { // no indices provided so directly generate from counts
+ switch (prim.mode) {
+ case PrimitiveMode_POINTS: {
+ nFaces = count;
+ faces = new aiFace[nFaces];
+ for (unsigned int i = 0; i < count; ++i) {
+ SetFace(faces[i], i);
+ }
+ break;
+ }
- // use the already determined count as it includes checks
- unsigned int count = aim->mNumVertices;
+ case PrimitiveMode_LINES: {
+ nFaces = count / 2;
+ if (nFaces * 2 != count) {
+ ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
+ count = (unsigned int)nFaces * 2;
+ }
+ faces = new aiFace[nFaces];
+ for (unsigned int i = 0; i < count; i += 2) {
+ SetFace(faces[i / 2], i, i + 1);
+ }
+ break;
+ }
- switch (prim.mode) {
- case PrimitiveMode_POINTS: {
- nFaces = count;
- faces = new aiFace[nFaces];
- for (unsigned int i = 0; i < count; ++i) {
- SetFace(faces[i], i);
- }
- break;
- }
+ case PrimitiveMode_LINE_LOOP:
+ case PrimitiveMode_LINE_STRIP: {
+ nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
+ faces = new aiFace[nFaces];
+ SetFace(faces[0], 0, 1);
+ for (unsigned int i = 2; i < count; ++i) {
+ SetFace(faces[i - 1], faces[i - 2].mIndices[1], i);
+ }
+ if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
+ SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
+ }
+ break;
+ }
- case PrimitiveMode_LINES: {
- nFaces = count / 2;
- if (nFaces * 2 != count) {
- ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
- count = nFaces * 2;
- }
- faces = new aiFace[nFaces];
- for (unsigned int i = 0; i < count; i += 2) {
- SetFace(faces[i / 2], i, i + 1);
- }
- break;
- }
+ case PrimitiveMode_TRIANGLES: {
+ nFaces = count / 3;
+ if (nFaces * 3 != count) {
+ ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
+ count = (unsigned int)nFaces * 3;
+ }
+ faces = new aiFace[nFaces];
+ for (unsigned int i = 0; i < count; i += 3) {
+ SetFace(faces[i / 3], i, i + 1, i + 2);
+ }
+ break;
+ }
+ case PrimitiveMode_TRIANGLE_STRIP: {
+ nFaces = count - 2;
+ faces = new aiFace[nFaces];
+ for (unsigned int i = 0; i < nFaces; ++i) {
+ //The ordering is to ensure that the triangles are all drawn with the same orientation
+ if ((i + 1) % 2 == 0) {
+ //For even n, vertices n + 1, n, and n + 2 define triangle n
+ SetFace(faces[i], i + 1, i, i + 2);
+ } else {
+ //For odd n, vertices n, n+1, and n+2 define triangle n
+ SetFace(faces[i], i, i + 1, i + 2);
+ }
+ }
+ break;
+ }
+ case PrimitiveMode_TRIANGLE_FAN:
+ nFaces = count - 2;
+ faces = new aiFace[nFaces];
+ SetFace(faces[0], 0, 1, 2);
+ for (unsigned int i = 1; i < nFaces; ++i) {
+ SetFace(faces[i], faces[0].mIndices[0], faces[i - 1].mIndices[2], i + 2);
+ }
+ break;
+ }
+ }
- case PrimitiveMode_LINE_LOOP:
- case PrimitiveMode_LINE_STRIP: {
- nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
- faces = new aiFace[nFaces];
- SetFace(faces[0], 0, 1);
- for (unsigned int i = 2; i < count; ++i) {
- SetFace(faces[i - 1], faces[i - 2].mIndices[1], i);
- }
- if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
- SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
- }
- break;
- }
+ if (faces) {
+ aim->mFaces = faces;
+ aim->mNumFaces = static_cast(nFaces);
+ ai_assert(CheckValidFacesIndices(faces, static_cast(nFaces), aim->mNumVertices));
+ }
- case PrimitiveMode_TRIANGLES: {
- nFaces = count / 3;
- if (nFaces * 3 != count) {
- ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
- count = nFaces * 3;
- }
- faces = new aiFace[nFaces];
- for (unsigned int i = 0; i < count; i += 3) {
- SetFace(faces[i / 3], i, i + 1, i + 2);
- }
- break;
- }
- case PrimitiveMode_TRIANGLE_STRIP: {
- nFaces = count - 2;
- faces = new aiFace[nFaces];
- for (unsigned int i = 0; i < nFaces; ++i) {
- //The ordering is to ensure that the triangles are all drawn with the same orientation
- if ((i+1) % 2 == 0)
- {
- //For even n, vertices n + 1, n, and n + 2 define triangle n
- SetFace(faces[i], i+1, i, i+2);
- }
- else
- {
- //For odd n, vertices n, n+1, and n+2 define triangle n
- SetFace(faces[i], i, i+1, i+2);
- }
- }
- break;
- }
- case PrimitiveMode_TRIANGLE_FAN:
- nFaces = count - 2;
- faces = new aiFace[nFaces];
- SetFace(faces[0], 0, 1, 2);
- for (unsigned int i = 1; i < nFaces; ++i) {
- SetFace(faces[i], faces[0].mIndices[0], faces[i - 1].mIndices[2], i + 2);
- }
- break;
- }
- }
+ if (prim.material) {
+ aim->mMaterialIndex = prim.material.GetIndex();
+ } else {
+ aim->mMaterialIndex = mScene->mNumMaterials - 1;
+ }
+ }
+ }
- if (faces) {
- aim->mFaces = faces;
- aim->mNumFaces = static_cast(nFaces);
- ai_assert(CheckValidFacesIndices(faces, static_cast(nFaces), aim->mNumVertices));
- }
+ meshOffsets.push_back(k);
- if (prim.material) {
- aim->mMaterialIndex = prim.material.GetIndex();
- }
- else {
- aim->mMaterialIndex = mScene->mNumMaterials - 1;
- }
-
- }
- }
-
- meshOffsets.push_back(k);
-
- CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
+ CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
}
-void glTF2Importer::ImportCameras(glTF2::Asset& r)
-{
- if (!r.cameras.Size()) return;
+void glTF2Importer::ImportCameras(glTF2::Asset &r) {
+ if (!r.cameras.Size()) return;
- mScene->mNumCameras = r.cameras.Size();
- mScene->mCameras = new aiCamera*[r.cameras.Size()];
+ mScene->mNumCameras = r.cameras.Size();
+ mScene->mCameras = new aiCamera *[r.cameras.Size()];
- for (size_t i = 0; i < r.cameras.Size(); ++i) {
- Camera& cam = r.cameras[i];
+ for (size_t i = 0; i < r.cameras.Size(); ++i) {
+ Camera &cam = r.cameras[i];
- aiCamera* aicam = mScene->mCameras[i] = new aiCamera();
+ aiCamera *aicam = mScene->mCameras[i] = new aiCamera();
- // cameras point in -Z by default, rest is specified in node transform
- aicam->mLookAt = aiVector3D(0.f,0.f,-1.f);
+ // cameras point in -Z by default, rest is specified in node transform
+ aicam->mLookAt = aiVector3D(0.f, 0.f, -1.f);
- if (cam.type == Camera::Perspective) {
+ if (cam.type == Camera::Perspective) {
- aicam->mAspect = cam.cameraProperties.perspective.aspectRatio;
- aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect);
- aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar;
- aicam->mClipPlaneNear = cam.cameraProperties.perspective.znear;
- } else {
- aicam->mClipPlaneFar = cam.cameraProperties.ortographic.zfar;
- aicam->mClipPlaneNear = cam.cameraProperties.ortographic.znear;
- aicam->mHorizontalFOV = 0.0;
- aicam->mAspect = 1.0f;
- if (0.f != cam.cameraProperties.ortographic.ymag ) {
- aicam->mAspect = cam.cameraProperties.ortographic.xmag / cam.cameraProperties.ortographic.ymag;
- }
- }
- }
+ aicam->mAspect = cam.cameraProperties.perspective.aspectRatio;
+ aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect);
+ aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar;
+ aicam->mClipPlaneNear = cam.cameraProperties.perspective.znear;
+ } else {
+ aicam->mClipPlaneFar = cam.cameraProperties.ortographic.zfar;
+ aicam->mClipPlaneNear = cam.cameraProperties.ortographic.znear;
+ aicam->mHorizontalFOV = 0.0;
+ aicam->mAspect = 1.0f;
+ if (0.f != cam.cameraProperties.ortographic.ymag) {
+ aicam->mAspect = cam.cameraProperties.ortographic.xmag / cam.cameraProperties.ortographic.ymag;
+ }
+ }
+ }
}
-void glTF2Importer::ImportLights(glTF2::Asset& r)
-{
- if (!r.lights.Size())
- return;
+void glTF2Importer::ImportLights(glTF2::Asset &r) {
+ if (!r.lights.Size())
+ return;
- mScene->mNumLights = r.lights.Size();
- mScene->mLights = new aiLight*[r.lights.Size()];
+ mScene->mNumLights = r.lights.Size();
+ mScene->mLights = new aiLight *[r.lights.Size()];
- for (size_t i = 0; i < r.lights.Size(); ++i) {
- Light& light = r.lights[i];
+ for (size_t i = 0; i < r.lights.Size(); ++i) {
+ Light &light = r.lights[i];
- aiLight* ail = mScene->mLights[i] = new aiLight();
+ aiLight *ail = mScene->mLights[i] = new aiLight();
- switch (light.type)
- {
- case Light::Directional:
- ail->mType = aiLightSource_DIRECTIONAL; break;
- case Light::Point:
- ail->mType = aiLightSource_POINT; break;
- case Light::Spot:
- ail->mType = aiLightSource_SPOT; break;
- }
+ switch (light.type) {
+ case Light::Directional:
+ ail->mType = aiLightSource_DIRECTIONAL;
+ break;
+ case Light::Point:
+ ail->mType = aiLightSource_POINT;
+ break;
+ case Light::Spot:
+ ail->mType = aiLightSource_SPOT;
+ break;
+ }
- if (ail->mType != aiLightSource_POINT)
- {
- ail->mDirection = aiVector3D(0.0f, 0.0f, -1.0f);
- ail->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
- }
+ if (ail->mType != aiLightSource_POINT) {
+ ail->mDirection = aiVector3D(0.0f, 0.0f, -1.0f);
+ ail->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
+ }
- vec3 colorWithIntensity = { light.color[0] * light.intensity, light.color[1] * light.intensity, light.color[2] * light.intensity };
- CopyValue(colorWithIntensity, ail->mColorAmbient);
- CopyValue(colorWithIntensity, ail->mColorDiffuse);
- CopyValue(colorWithIntensity, ail->mColorSpecular);
+ vec3 colorWithIntensity = { light.color[0] * light.intensity, light.color[1] * light.intensity, light.color[2] * light.intensity };
+ CopyValue(colorWithIntensity, ail->mColorAmbient);
+ CopyValue(colorWithIntensity, ail->mColorDiffuse);
+ CopyValue(colorWithIntensity, ail->mColorSpecular);
- if (ail->mType == aiLightSource_DIRECTIONAL)
- {
- ail->mAttenuationConstant = 1.0;
- ail->mAttenuationLinear = 0.0;
- ail->mAttenuationQuadratic = 0.0;
- }
- else
- {
- //in PBR attenuation is calculated using inverse square law which can be expressed
- //using assimps equation: 1/(att0 + att1 * d + att2 * d*d) with the following parameters
- //this is correct equation for the case when range (see
- //https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual)
- //is not present. When range is not present it is assumed that it is infinite and so numerator is 1.
- //When range is present then numerator might be any value in range [0,1] and then assimps equation
- //will not suffice. In this case range is added into metadata in ImportNode function
- //and its up to implementation to read it when it wants to
- ail->mAttenuationConstant = 0.0;
- ail->mAttenuationLinear = 0.0;
- ail->mAttenuationQuadratic = 1.0;
- }
+ if (ail->mType == aiLightSource_DIRECTIONAL) {
+ ail->mAttenuationConstant = 1.0;
+ ail->mAttenuationLinear = 0.0;
+ ail->mAttenuationQuadratic = 0.0;
+ } else {
+ //in PBR attenuation is calculated using inverse square law which can be expressed
+ //using assimps equation: 1/(att0 + att1 * d + att2 * d*d) with the following parameters
+ //this is correct equation for the case when range (see
+ //https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual)
+ //is not present. When range is not present it is assumed that it is infinite and so numerator is 1.
+ //When range is present then numerator might be any value in range [0,1] and then assimps equation
+ //will not suffice. In this case range is added into metadata in ImportNode function
+ //and its up to implementation to read it when it wants to
+ ail->mAttenuationConstant = 0.0;
+ ail->mAttenuationLinear = 0.0;
+ ail->mAttenuationQuadratic = 1.0;
+ }
- if (ail->mType == aiLightSource_SPOT)
- {
- ail->mAngleInnerCone = light.innerConeAngle;
- ail->mAngleOuterCone = light.outerConeAngle;
- }
- }
+ if (ail->mType == aiLightSource_SPOT) {
+ ail->mAngleInnerCone = light.innerConeAngle;
+ ail->mAngleOuterCone = light.outerConeAngle;
+ }
+ }
}
-static void GetNodeTransform(aiMatrix4x4& matrix, const glTF2::Node& node) {
- if (node.matrix.isPresent) {
- CopyValue(node.matrix.value, matrix);
- }
- else {
- if (node.translation.isPresent) {
- aiVector3D trans;
- CopyValue(node.translation.value, trans);
- aiMatrix4x4 t;
- aiMatrix4x4::Translation(trans, t);
- matrix = matrix * t;
- }
+static void GetNodeTransform(aiMatrix4x4 &matrix, const glTF2::Node &node) {
+ if (node.matrix.isPresent) {
+ CopyValue(node.matrix.value, matrix);
+ } else {
+ if (node.translation.isPresent) {
+ aiVector3D trans;
+ CopyValue(node.translation.value, trans);
+ aiMatrix4x4 t;
+ aiMatrix4x4::Translation(trans, t);
+ matrix = matrix * t;
+ }
- if (node.rotation.isPresent) {
- aiQuaternion rot;
- CopyValue(node.rotation.value, rot);
- matrix = matrix * aiMatrix4x4(rot.GetMatrix());
- }
+ if (node.rotation.isPresent) {
+ aiQuaternion rot;
+ CopyValue(node.rotation.value, rot);
+ matrix = matrix * aiMatrix4x4(rot.GetMatrix());
+ }
- if (node.scale.isPresent) {
- aiVector3D scal(1.f);
- CopyValue(node.scale.value, scal);
- aiMatrix4x4 s;
- aiMatrix4x4::Scaling(scal, s);
- matrix = matrix * s;
- }
- }
+ if (node.scale.isPresent) {
+ aiVector3D scal(1.f);
+ CopyValue(node.scale.value, scal);
+ aiMatrix4x4 s;
+ aiMatrix4x4::Scaling(scal, s);
+ matrix = matrix * s;
+ }
+ }
}
-static void BuildVertexWeightMapping(Mesh::Primitive& primitive, std::vector>& map)
-{
- Mesh::Primitive::Attributes& attr = primitive.attributes;
- if (attr.weight.empty() || attr.joint.empty()) {
- return;
- }
- if (attr.weight[0]->count != attr.joint[0]->count) {
- return;
- }
+static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector> &map) {
+ Mesh::Primitive::Attributes &attr = primitive.attributes;
+ if (attr.weight.empty() || attr.joint.empty()) {
+ return;
+ }
+ if (attr.weight[0]->count != attr.joint[0]->count) {
+ return;
+ }
- size_t num_vertices = attr.weight[0]->count;
+ size_t num_vertices = attr.weight[0]->count;
- struct Weights { float values[4]; };
- Weights* weights = nullptr;
- attr.weight[0]->ExtractData(weights);
+ struct Weights {
+ float values[4];
+ };
+ Weights *weights = nullptr;
+ attr.weight[0]->ExtractData(weights);
- struct Indices8 { uint8_t values[4]; };
- struct Indices16 { uint16_t values[4]; };
- Indices8* indices8 = nullptr;
- Indices16* indices16 = nullptr;
- if (attr.joint[0]->GetElementSize() == 4) {
- attr.joint[0]->ExtractData(indices8);
- }else {
- attr.joint[0]->ExtractData(indices16);
- }
- //
- if (nullptr == indices8 && nullptr == indices16) {
- // Something went completely wrong!
- ai_assert(false);
- return;
- }
+ struct Indices8 {
+ uint8_t values[4];
+ };
+ struct Indices16 {
+ uint16_t values[4];
+ };
+ Indices8 *indices8 = nullptr;
+ Indices16 *indices16 = nullptr;
+ if (attr.joint[0]->GetElementSize() == 4) {
+ attr.joint[0]->ExtractData(indices8);
+ } else {
+ attr.joint[0]->ExtractData(indices16);
+ }
+ //
+ if (nullptr == indices8 && nullptr == indices16) {
+ // Something went completely wrong!
+ ai_assert(false);
+ return;
+ }
- for (size_t i = 0; i < num_vertices; ++i) {
- for (int j = 0; j < 4; ++j) {
- const unsigned int bone = (indices8!=nullptr) ? indices8[i].values[j] : indices16[i].values[j];
- const float weight = weights[i].values[j];
- if (weight > 0 && bone < map.size()) {
- map[bone].reserve(8);
- map[bone].emplace_back(static_cast(i), weight);
- }
- }
- }
+ for (size_t i = 0; i < num_vertices; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ const unsigned int bone = (indices8 != nullptr) ? indices8[i].values[j] : indices16[i].values[j];
+ const float weight = weights[i].values[j];
+ if (weight > 0 && bone < map.size()) {
+ map[bone].reserve(8);
+ map[bone].emplace_back(static_cast(i), weight);
+ }
+ }
+ }
- delete[] weights;
- delete[] indices8;
- delete[] indices16;
+ delete[] weights;
+ delete[] indices8;
+ delete[] indices16;
}
-static std::string GetNodeName(const Node& node)
-{
- return node.name.empty() ? node.id : node.name;
+static std::string GetNodeName(const Node &node) {
+ return node.name.empty() ? node.id : node.name;
}
-aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector& meshOffsets, glTF2::Ref& ptr)
-{
- Node& node = *ptr;
+aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector &meshOffsets, glTF2::Ref &ptr) {
+ Node &node = *ptr;
- aiNode* ainode = new aiNode(GetNodeName(node));
+ aiNode *ainode = new aiNode(GetNodeName(node));
- if (!node.children.empty()) {
- ainode->mNumChildren = unsigned(node.children.size());
- ainode->mChildren = new aiNode*[ainode->mNumChildren];
+ if (!node.children.empty()) {
+ ainode->mNumChildren = unsigned(node.children.size());
+ ainode->mChildren = new aiNode *[ainode->mNumChildren];
- for (unsigned int i = 0; i < ainode->mNumChildren; ++i) {
- aiNode* child = ImportNode(pScene, r, meshOffsets, node.children[i]);
- child->mParent = ainode;
- ainode->mChildren[i] = child;
- }
- }
+ for (unsigned int i = 0; i < ainode->mNumChildren; ++i) {
+ aiNode *child = ImportNode(pScene, r, meshOffsets, node.children[i]);
+ child->mParent = ainode;
+ ainode->mChildren[i] = child;
+ }
+ }
- GetNodeTransform(ainode->mTransformation, node);
+ GetNodeTransform(ainode->mTransformation, node);
- if (!node.meshes.empty()) {
- // GLTF files contain at most 1 mesh per node.
- assert(node.meshes.size() == 1);
- int mesh_idx = node.meshes[0].GetIndex();
- int count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx];
+ if (!node.meshes.empty()) {
+ // GLTF files contain at most 1 mesh per node.
+ assert(node.meshes.size() == 1);
+ int mesh_idx = node.meshes[0].GetIndex();
+ int count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx];
- ainode->mNumMeshes = count;
- ainode->mMeshes = new unsigned int[count];
+ ainode->mNumMeshes = count;
+ ainode->mMeshes = new unsigned int[count];
- if (node.skin) {
- for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) {
- aiMesh* mesh = pScene->mMeshes[meshOffsets[mesh_idx]+primitiveNo];
- mesh->mNumBones = static_cast(node.skin->jointNames.size());
- mesh->mBones = new aiBone*[mesh->mNumBones];
+ if (node.skin) {
+ for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) {
+ aiMesh *mesh = pScene->mMeshes[meshOffsets[mesh_idx] + primitiveNo];
+ mesh->mNumBones = static_cast(node.skin->jointNames.size());
+ mesh->mBones = new aiBone *[mesh->mNumBones];
- // GLTF and Assimp choose to store bone weights differently.
- // GLTF has each vertex specify which bones influence the vertex.
- // Assimp has each bone specify which vertices it has influence over.
- // To convert this data, we first read over the vertex data and pull
- // out the bone-to-vertex mapping. Then, when creating the aiBones,
- // we copy the bone-to-vertex mapping into the bone. This is unfortunate
- // both because it's somewhat slow and because, for many applications,
- // we then need to reconvert the data back into the vertex-to-bone
- // mapping which makes things doubly-slow.
- std::vector> weighting(mesh->mNumBones);
- BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting);
+ // GLTF and Assimp choose to store bone weights differently.
+ // GLTF has each vertex specify which bones influence the vertex.
+ // Assimp has each bone specify which vertices it has influence over.
+ // To convert this data, we first read over the vertex data and pull
+ // out the bone-to-vertex mapping. Then, when creating the aiBones,
+ // we copy the bone-to-vertex mapping into the bone. This is unfortunate
+ // both because it's somewhat slow and because, for many applications,
+ // we then need to reconvert the data back into the vertex-to-bone
+ // mapping which makes things doubly-slow.
+ std::vector> weighting(mesh->mNumBones);
+ BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting);
- mat4* pbindMatrices = nullptr;
- node.skin->inverseBindMatrices->ExtractData(pbindMatrices);
+ mat4 *pbindMatrices = nullptr;
+ node.skin->inverseBindMatrices->ExtractData(pbindMatrices);
- for (uint32_t i = 0; i < mesh->mNumBones; ++i) {
- aiBone* bone = new aiBone();
+ for (uint32_t i = 0; i < mesh->mNumBones; ++i) {
+ aiBone *bone = new aiBone();
- Ref joint = node.skin->jointNames[i];
- if (!joint->name.empty()) {
- bone->mName = joint->name;
- } else {
- // Assimp expects each bone to have a unique name.
- static const std::string kDefaultName = "bone_";
- char postfix[10] = {0};
- ASSIMP_itoa10(postfix, i);
- bone->mName = (kDefaultName + postfix);
- }
- GetNodeTransform(bone->mOffsetMatrix, *joint);
+ Ref joint = node.skin->jointNames[i];
+ if (!joint->name.empty()) {
+ bone->mName = joint->name;
+ } else {
+ // Assimp expects each bone to have a unique name.
+ static const std::string kDefaultName = "bone_";
+ char postfix[10] = { 0 };
+ ASSIMP_itoa10(postfix, i);
+ bone->mName = (kDefaultName + postfix);
+ }
+ GetNodeTransform(bone->mOffsetMatrix, *joint);
- CopyValue(pbindMatrices[i], bone->mOffsetMatrix);
+ CopyValue(pbindMatrices[i], bone->mOffsetMatrix);
- std::vector& weights = weighting[i];
+ std::vector &weights = weighting[i];
- bone->mNumWeights = static_cast(weights.size());
- if (bone->mNumWeights > 0) {
- bone->mWeights = new aiVertexWeight[bone->mNumWeights];
- memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight));
- } else {
- // Assimp expects all bones to have at least 1 weight.
- bone->mWeights = new aiVertexWeight[1];
- bone->mNumWeights = 1;
- bone->mWeights->mVertexId = 0;
- bone->mWeights->mWeight = 0.f;
- }
- mesh->mBones[i] = bone;
- }
+ bone->mNumWeights = static_cast(weights.size());
+ if (bone->mNumWeights > 0) {
+ bone->mWeights = new aiVertexWeight[bone->mNumWeights];
+ memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight));
+ } else {
+ // Assimp expects all bones to have at least 1 weight.
+ bone->mWeights = new aiVertexWeight[1];
+ bone->mNumWeights = 1;
+ bone->mWeights->mVertexId = 0;
+ bone->mWeights->mWeight = 0.f;
+ }
+ mesh->mBones[i] = bone;
+ }
- if (pbindMatrices) {
- delete[] pbindMatrices;
- }
- }
- }
+ if (pbindMatrices) {
+ delete[] pbindMatrices;
+ }
+ }
+ }
- int k = 0;
- for (unsigned int j = meshOffsets[mesh_idx]; j < meshOffsets[mesh_idx + 1]; ++j, ++k) {
- ainode->mMeshes[k] = j;
- }
- }
+ int k = 0;
+ for (unsigned int j = meshOffsets[mesh_idx]; j < meshOffsets[mesh_idx + 1]; ++j, ++k) {
+ ainode->mMeshes[k] = j;
+ }
+ }
- if (node.camera) {
- pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
- }
+ if (node.camera) {
+ pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
+ }
- if (node.light) {
- pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
+ if (node.light) {
+ pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
- //range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
- //it is added to meta data of parent node, because there is no other place to put it
- if (node.light->range.isPresent)
- {
- ainode->mMetaData = aiMetadata::Alloc(1);
- ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value);
- }
- }
+ //range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
+ //it is added to meta data of parent node, because there is no other place to put it
+ if (node.light->range.isPresent) {
+ ainode->mMetaData = aiMetadata::Alloc(1);
+ ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value);
+ }
+ }
- return ainode;
+ return ainode;
}
-void glTF2Importer::ImportNodes(glTF2::Asset& r)
-{
- if (!r.scene) return;
+void glTF2Importer::ImportNodes(glTF2::Asset &r) {
+ if (!r.scene) return;
- std::vector< Ref > rootNodes = r.scene->nodes;
+ std::vector[> rootNodes = r.scene->nodes;
- // The root nodes
- unsigned int numRootNodes = unsigned(rootNodes.size());
- if (numRootNodes == 1) { // a single root node: use it
- mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]);
- }
- else if (numRootNodes > 1) { // more than one root node: create a fake root
- aiNode* root = new aiNode("ROOT");
- root->mChildren = new aiNode*[numRootNodes];
- for (unsigned int i = 0; i < numRootNodes; ++i) {
- aiNode* node = ImportNode(mScene, r, meshOffsets, rootNodes[i]);
- node->mParent = root;
- root->mChildren[root->mNumChildren++] = node;
- }
- mScene->mRootNode = root;
- }
-
- //if (!mScene->mRootNode) {
- // mScene->mRootNode = new aiNode("EMPTY");
- //}
+ // The root nodes
+ unsigned int numRootNodes = unsigned(rootNodes.size());
+ if (numRootNodes == 1) { // a single root node: use it
+ mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]);
+ } else if (numRootNodes > 1) { // more than one root node: create a fake root
+ aiNode *root = new aiNode("ROOT");
+ root->mChildren = new aiNode *[numRootNodes];
+ for (unsigned int i = 0; i < numRootNodes; ++i) {
+ aiNode *node = ImportNode(mScene, r, meshOffsets, rootNodes[i]);
+ node->mParent = root;
+ root->mChildren[root->mNumChildren++] = node;
+ }
+ mScene->mRootNode = root;
+ }
}
struct AnimationSamplers {
- AnimationSamplers()
- : translation(nullptr)
- , rotation(nullptr)
- , scale(nullptr)
- , weight(nullptr) {
- // empty
- }
+ AnimationSamplers() :
+ translation(nullptr),
+ rotation(nullptr),
+ scale(nullptr),
+ weight(nullptr) {
+ // empty
+ }
- Animation::Sampler* translation;
- Animation::Sampler* rotation;
- Animation::Sampler* scale;
- Animation::Sampler* weight;
+ Animation::Sampler *translation;
+ Animation::Sampler *rotation;
+ Animation::Sampler *scale;
+ Animation::Sampler *weight;
};
-aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers)
-{
- aiNodeAnim* anim = new aiNodeAnim();
- anim->mNodeName = GetNodeName(node);
+aiNodeAnim *CreateNodeAnim(glTF2::Asset &r, Node &node, AnimationSamplers &samplers) {
+ aiNodeAnim *anim = new aiNodeAnim();
+ anim->mNodeName = GetNodeName(node);
- static const float kMillisecondsFromSeconds = 1000.f;
+ static const float kMillisecondsFromSeconds = 1000.f;
- if (samplers.translation) {
- float* times = nullptr;
- samplers.translation->input->ExtractData(times);
- aiVector3D* values = nullptr;
- samplers.translation->output->ExtractData(values);
- anim->mNumPositionKeys = static_cast(samplers.translation->input->count);
- anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
- for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
- anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
- anim->mPositionKeys[i].mValue = values[i];
- }
- delete[] times;
- delete[] values;
- } else if (node.translation.isPresent) {
- anim->mNumPositionKeys = 1;
- anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
- anim->mPositionKeys->mTime = 0.f;
- anim->mPositionKeys->mValue.x = node.translation.value[0];
- anim->mPositionKeys->mValue.y = node.translation.value[1];
- anim->mPositionKeys->mValue.z = node.translation.value[2];
- }
+ if (samplers.translation) {
+ float *times = nullptr;
+ samplers.translation->input->ExtractData(times);
+ aiVector3D *values = nullptr;
+ samplers.translation->output->ExtractData(values);
+ anim->mNumPositionKeys = static_cast(samplers.translation->input->count);
+ anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
+ for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
+ anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
+ anim->mPositionKeys[i].mValue = values[i];
+ }
+ delete[] times;
+ delete[] values;
+ } else if (node.translation.isPresent) {
+ anim->mNumPositionKeys = 1;
+ anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
+ anim->mPositionKeys->mTime = 0.f;
+ anim->mPositionKeys->mValue.x = node.translation.value[0];
+ anim->mPositionKeys->mValue.y = node.translation.value[1];
+ anim->mPositionKeys->mValue.z = node.translation.value[2];
+ }
- if (samplers.rotation) {
- float* times = nullptr;
- samplers.rotation->input->ExtractData(times);
- aiQuaternion* values = nullptr;
- samplers.rotation->output->ExtractData(values);
- anim->mNumRotationKeys = static_cast(samplers.rotation->input->count);
- anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
- for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
- anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
- anim->mRotationKeys[i].mValue.x = values[i].w;
- anim->mRotationKeys[i].mValue.y = values[i].x;
- anim->mRotationKeys[i].mValue.z = values[i].y;
- anim->mRotationKeys[i].mValue.w = values[i].z;
- }
- delete[] times;
- delete[] values;
- } else if (node.rotation.isPresent) {
- anim->mNumRotationKeys = 1;
- anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
- anim->mRotationKeys->mTime = 0.f;
- anim->mRotationKeys->mValue.x = node.rotation.value[0];
- anim->mRotationKeys->mValue.y = node.rotation.value[1];
- anim->mRotationKeys->mValue.z = node.rotation.value[2];
- anim->mRotationKeys->mValue.w = node.rotation.value[3];
- }
+ if (samplers.rotation) {
+ float *times = nullptr;
+ samplers.rotation->input->ExtractData(times);
+ aiQuaternion *values = nullptr;
+ samplers.rotation->output->ExtractData(values);
+ anim->mNumRotationKeys = static_cast(samplers.rotation->input->count);
+ anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
+ for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
+ anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
+ anim->mRotationKeys[i].mValue.x = values[i].w;
+ anim->mRotationKeys[i].mValue.y = values[i].x;
+ anim->mRotationKeys[i].mValue.z = values[i].y;
+ anim->mRotationKeys[i].mValue.w = values[i].z;
+ }
+ delete[] times;
+ delete[] values;
+ } else if (node.rotation.isPresent) {
+ anim->mNumRotationKeys = 1;
+ anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
+ anim->mRotationKeys->mTime = 0.f;
+ anim->mRotationKeys->mValue.x = node.rotation.value[0];
+ anim->mRotationKeys->mValue.y = node.rotation.value[1];
+ anim->mRotationKeys->mValue.z = node.rotation.value[2];
+ anim->mRotationKeys->mValue.w = node.rotation.value[3];
+ }
- if (samplers.scale) {
- float* times = nullptr;
- samplers.scale->input->ExtractData(times);
- aiVector3D* values = nullptr;
- samplers.scale->output->ExtractData(values);
- anim->mNumScalingKeys = static_cast(samplers.scale->input->count);
- anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys];
- for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) {
- anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
- anim->mScalingKeys[i].mValue = values[i];
- }
- delete[] times;
- delete[] values;
- } else if (node.scale.isPresent) {
- anim->mNumScalingKeys = 1;
- anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys];
- anim->mScalingKeys->mTime = 0.f;
- anim->mScalingKeys->mValue.x = node.scale.value[0];
- anim->mScalingKeys->mValue.y = node.scale.value[1];
- anim->mScalingKeys->mValue.z = node.scale.value[2];
- }
+ if (samplers.scale) {
+ float *times = nullptr;
+ samplers.scale->input->ExtractData(times);
+ aiVector3D *values = nullptr;
+ samplers.scale->output->ExtractData(values);
+ anim->mNumScalingKeys = static_cast(samplers.scale->input->count);
+ anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys];
+ for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) {
+ anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
+ anim->mScalingKeys[i].mValue = values[i];
+ }
+ delete[] times;
+ delete[] values;
+ } else if (node.scale.isPresent) {
+ anim->mNumScalingKeys = 1;
+ anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys];
+ anim->mScalingKeys->mTime = 0.f;
+ anim->mScalingKeys->mValue.x = node.scale.value[0];
+ anim->mScalingKeys->mValue.y = node.scale.value[1];
+ anim->mScalingKeys->mValue.z = node.scale.value[2];
+ }
- return anim;
+ return anim;
}
-aiMeshMorphAnim* CreateMeshMorphAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers)
-{
- aiMeshMorphAnim* anim = new aiMeshMorphAnim();
- anim->mName = GetNodeName(node);
+aiMeshMorphAnim *CreateMeshMorphAnim(glTF2::Asset &r, Node &node, AnimationSamplers &samplers) {
+ aiMeshMorphAnim *anim = new aiMeshMorphAnim();
+ anim->mName = GetNodeName(node);
- static const float kMillisecondsFromSeconds = 1000.f;
+ static const float kMillisecondsFromSeconds = 1000.f;
- if (nullptr != samplers.weight) {
- float* times = nullptr;
- samplers.weight->input->ExtractData(times);
- float* values = nullptr;
- samplers.weight->output->ExtractData(values);
- anim->mNumKeys = static_cast(samplers.weight->input->count);
+ if (nullptr != samplers.weight) {
+ float *times = nullptr;
+ samplers.weight->input->ExtractData(times);
+ float *values = nullptr;
+ samplers.weight->output->ExtractData(values);
+ anim->mNumKeys = static_cast(samplers.weight->input->count);
- const unsigned int numMorphs = samplers.weight->output->count / anim->mNumKeys;
+ const unsigned int numMorphs = (unsigned int)samplers.weight->output->count / anim->mNumKeys;
- anim->mKeys = new aiMeshMorphKey[anim->mNumKeys];
- unsigned int k = 0u;
- for (unsigned int i = 0u; i < anim->mNumKeys; ++i) {
- anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
- anim->mKeys[i].mNumValuesAndWeights = numMorphs;
- anim->mKeys[i].mValues = new unsigned int[numMorphs];
- anim->mKeys[i].mWeights = new double[numMorphs];
+ anim->mKeys = new aiMeshMorphKey[anim->mNumKeys];
+ unsigned int k = 0u;
+ for (unsigned int i = 0u; i < anim->mNumKeys; ++i) {
+ anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
+ anim->mKeys[i].mNumValuesAndWeights = numMorphs;
+ anim->mKeys[i].mValues = new unsigned int[numMorphs];
+ anim->mKeys[i].mWeights = new double[numMorphs];
- for (unsigned int j = 0u; j < numMorphs; ++j, ++k) {
- anim->mKeys[i].mValues[j] = j;
- anim->mKeys[i].mWeights[j] = ( 0.f > values[k] ) ? 0.f : values[k];
- }
- }
+ for (unsigned int j = 0u; j < numMorphs; ++j, ++k) {
+ anim->mKeys[i].mValues[j] = j;
+ anim->mKeys[i].mWeights[j] = (0.f > values[k]) ? 0.f : values[k];
+ }
+ }
- delete[] times;
- delete[] values;
- }
+ delete[] times;
+ delete[] values;
+ }
- return anim;
+ return anim;
}
-std::unordered_map GatherSamplers(Animation& anim)
-{
- std::unordered_map samplers;
- for (unsigned int c = 0; c < anim.channels.size(); ++c) {
- Animation::Channel& channel = anim.channels[c];
- if (channel.sampler >= static_cast(anim.samplers.size())) {
- continue;
- }
+std::unordered_map GatherSamplers(Animation &anim) {
+ std::unordered_map samplers;
+ for (unsigned int c = 0; c < anim.channels.size(); ++c) {
+ Animation::Channel &channel = anim.channels[c];
+ if (channel.sampler >= static_cast(anim.samplers.size())) {
+ continue;
+ }
- const unsigned int node_index = channel.target.node.GetIndex();
+ const unsigned int node_index = channel.target.node.GetIndex();
- AnimationSamplers& sampler = samplers[node_index];
- if (channel.target.path == AnimationPath_TRANSLATION) {
- sampler.translation = &anim.samplers[channel.sampler];
- } else if (channel.target.path == AnimationPath_ROTATION) {
- sampler.rotation = &anim.samplers[channel.sampler];
- } else if (channel.target.path == AnimationPath_SCALE) {
- sampler.scale = &anim.samplers[channel.sampler];
- } else if (channel.target.path == AnimationPath_WEIGHTS) {
- sampler.weight = &anim.samplers[channel.sampler];
- }
- }
+ AnimationSamplers &sampler = samplers[node_index];
+ if (channel.target.path == AnimationPath_TRANSLATION) {
+ sampler.translation = &anim.samplers[channel.sampler];
+ } else if (channel.target.path == AnimationPath_ROTATION) {
+ sampler.rotation = &anim.samplers[channel.sampler];
+ } else if (channel.target.path == AnimationPath_SCALE) {
+ sampler.scale = &anim.samplers[channel.sampler];
+ } else if (channel.target.path == AnimationPath_WEIGHTS) {
+ sampler.weight = &anim.samplers[channel.sampler];
+ }
+ }
- return samplers;
+ return samplers;
}
-void glTF2Importer::ImportAnimations(glTF2::Asset& r)
-{
- if (!r.scene) return;
+void glTF2Importer::ImportAnimations(glTF2::Asset &r) {
+ if (!r.scene) return;
- mScene->mNumAnimations = r.animations.Size();
- if (mScene->mNumAnimations == 0) {
- return;
- }
+ mScene->mNumAnimations = r.animations.Size();
+ if (mScene->mNumAnimations == 0) {
+ return;
+ }
- mScene->mAnimations = new aiAnimation*[mScene->mNumAnimations];
- for (unsigned int i = 0; i < r.animations.Size(); ++i) {
- Animation& anim = r.animations[i];
+ mScene->mAnimations = new aiAnimation *[mScene->mNumAnimations];
+ for (unsigned int i = 0; i < r.animations.Size(); ++i) {
+ Animation &anim = r.animations[i];
- aiAnimation* ai_anim = new aiAnimation();
- ai_anim->mName = anim.name;
- ai_anim->mDuration = 0;
- ai_anim->mTicksPerSecond = 0;
+ aiAnimation *ai_anim = new aiAnimation();
+ ai_anim->mName = anim.name;
+ ai_anim->mDuration = 0;
+ ai_anim->mTicksPerSecond = 0;
- std::unordered_map samplers = GatherSamplers(anim);
+ std::unordered_map samplers = GatherSamplers(anim);
- uint32_t numChannels = 0u;
- uint32_t numMorphMeshChannels = 0u;
+ uint32_t numChannels = 0u;
+ uint32_t numMorphMeshChannels = 0u;
- for (auto& iter : samplers) {
- if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) {
- ++numChannels;
- }
- if (nullptr != iter.second.weight) {
- ++numMorphMeshChannels;
- }
- }
+ for (auto &iter : samplers) {
+ if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) {
+ ++numChannels;
+ }
+ if (nullptr != iter.second.weight) {
+ ++numMorphMeshChannels;
+ }
+ }
- ai_anim->mNumChannels = numChannels;
- if (ai_anim->mNumChannels > 0) {
- ai_anim->mChannels = new aiNodeAnim*[ai_anim->mNumChannels];
- int j = 0;
- for (auto& iter : samplers) {
- if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) {
- ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second);
- ++j;
- }
- }
- }
+ ai_anim->mNumChannels = numChannels;
+ if (ai_anim->mNumChannels > 0) {
+ ai_anim->mChannels = new aiNodeAnim *[ai_anim->mNumChannels];
+ int j = 0;
+ for (auto &iter : samplers) {
+ if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) {
+ ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second);
+ ++j;
+ }
+ }
+ }
- ai_anim->mNumMorphMeshChannels = numMorphMeshChannels;
- if (ai_anim->mNumMorphMeshChannels > 0) {
- ai_anim->mMorphMeshChannels = new aiMeshMorphAnim*[ai_anim->mNumMorphMeshChannels];
- int j = 0;
- for (auto& iter : samplers) {
- if (nullptr != iter.second.weight) {
- ai_anim->mMorphMeshChannels[j] = CreateMeshMorphAnim(r, r.nodes[iter.first], iter.second);
- ++j;
- }
- }
- }
+ ai_anim->mNumMorphMeshChannels = numMorphMeshChannels;
+ if (ai_anim->mNumMorphMeshChannels > 0) {
+ ai_anim->mMorphMeshChannels = new aiMeshMorphAnim *[ai_anim->mNumMorphMeshChannels];
+ int j = 0;
+ for (auto &iter : samplers) {
+ if (nullptr != iter.second.weight) {
+ ai_anim->mMorphMeshChannels[j] = CreateMeshMorphAnim(r, r.nodes[iter.first], iter.second);
+ ++j;
+ }
+ }
+ }
- // Use the latest keyframe for the duration of the animation
- double maxDuration = 0;
- unsigned int maxNumberOfKeys = 0;
- for (unsigned int j = 0; j < ai_anim->mNumChannels; ++j) {
- auto chan = ai_anim->mChannels[j];
- if (chan->mNumPositionKeys) {
- auto lastPosKey = chan->mPositionKeys[chan->mNumPositionKeys - 1];
- if (lastPosKey.mTime > maxDuration) {
- maxDuration = lastPosKey.mTime;
- }
- maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumPositionKeys);
- }
- if (chan->mNumRotationKeys) {
- auto lastRotKey = chan->mRotationKeys[chan->mNumRotationKeys - 1];
- if (lastRotKey.mTime > maxDuration) {
- maxDuration = lastRotKey.mTime;
- }
- maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumRotationKeys);
- }
- if (chan->mNumScalingKeys) {
- auto lastScaleKey = chan->mScalingKeys[chan->mNumScalingKeys - 1];
- if (lastScaleKey.mTime > maxDuration) {
- maxDuration = lastScaleKey.mTime;
- }
- maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumScalingKeys);
- }
- }
+ // Use the latest keyframe for the duration of the animation
+ double maxDuration = 0;
+ unsigned int maxNumberOfKeys = 0;
+ for (unsigned int j = 0; j < ai_anim->mNumChannels; ++j) {
+ auto chan = ai_anim->mChannels[j];
+ if (chan->mNumPositionKeys) {
+ auto lastPosKey = chan->mPositionKeys[chan->mNumPositionKeys - 1];
+ if (lastPosKey.mTime > maxDuration) {
+ maxDuration = lastPosKey.mTime;
+ }
+ maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumPositionKeys);
+ }
+ if (chan->mNumRotationKeys) {
+ auto lastRotKey = chan->mRotationKeys[chan->mNumRotationKeys - 1];
+ if (lastRotKey.mTime > maxDuration) {
+ maxDuration = lastRotKey.mTime;
+ }
+ maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumRotationKeys);
+ }
+ if (chan->mNumScalingKeys) {
+ auto lastScaleKey = chan->mScalingKeys[chan->mNumScalingKeys - 1];
+ if (lastScaleKey.mTime > maxDuration) {
+ maxDuration = lastScaleKey.mTime;
+ }
+ maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumScalingKeys);
+ }
+ }
- for (unsigned int j = 0; j < ai_anim->mNumMorphMeshChannels; ++j) {
- const auto* const chan = ai_anim->mMorphMeshChannels[j];
+ for (unsigned int j = 0; j < ai_anim->mNumMorphMeshChannels; ++j) {
+ const auto *const chan = ai_anim->mMorphMeshChannels[j];
- if (0u != chan->mNumKeys) {
- const auto& lastKey = chan->mKeys[chan->mNumKeys - 1u];
- if (lastKey.mTime > maxDuration) {
- maxDuration = lastKey.mTime;
- }
- maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumKeys);
- }
- }
+ if (0u != chan->mNumKeys) {
+ const auto &lastKey = chan->mKeys[chan->mNumKeys - 1u];
+ if (lastKey.mTime > maxDuration) {
+ maxDuration = lastKey.mTime;
+ }
+ maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumKeys);
+ }
+ }
- ai_anim->mDuration = maxDuration;
- ai_anim->mTicksPerSecond = 1000.0;
+ ai_anim->mDuration = maxDuration;
+ ai_anim->mTicksPerSecond = 1000.0;
- mScene->mAnimations[i] = ai_anim;
- }
+ mScene->mAnimations[i] = ai_anim;
+ }
}
-void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset& r)
-{
- embeddedTexIdxs.resize(r.images.Size(), -1);
+void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
+ embeddedTexIdxs.resize(r.images.Size(), -1);
- int numEmbeddedTexs = 0;
- for (size_t i = 0; i < r.images.Size(); ++i) {
- if (r.images[i].HasData())
- numEmbeddedTexs += 1;
- }
+ int numEmbeddedTexs = 0;
+ for (size_t i = 0; i < r.images.Size(); ++i) {
+ if (r.images[i].HasData())
+ numEmbeddedTexs += 1;
+ }
- if (numEmbeddedTexs == 0)
- return;
+ if (numEmbeddedTexs == 0)
+ return;
- mScene->mTextures = new aiTexture*[numEmbeddedTexs];
+ mScene->mTextures = new aiTexture *[numEmbeddedTexs];
- // Add the embedded textures
- for (size_t i = 0; i < r.images.Size(); ++i) {
- Image &img = r.images[i];
- if (!img.HasData()) continue;
+ // Add the embedded textures
+ for (size_t i = 0; i < r.images.Size(); ++i) {
+ Image &img = r.images[i];
+ if (!img.HasData()) continue;
- int idx = mScene->mNumTextures++;
- embeddedTexIdxs[i] = idx;
+ int idx = mScene->mNumTextures++;
+ embeddedTexIdxs[i] = idx;
- aiTexture* tex = mScene->mTextures[idx] = new aiTexture();
+ aiTexture *tex = mScene->mTextures[idx] = new aiTexture();
- size_t length = img.GetDataLength();
- void* data = img.StealData();
+ size_t length = img.GetDataLength();
+ void *data = img.StealData();
- tex->mWidth = static_cast(length);
- tex->mHeight = 0;
- tex->pcData = reinterpret_cast(data);
+ tex->mWidth = static_cast(length);
+ tex->mHeight = 0;
+ tex->pcData = reinterpret_cast(data);
- if (!img.mimeType.empty()) {
- const char* ext = strchr(img.mimeType.c_str(), '/') + 1;
- if (ext) {
- if (strcmp(ext, "jpeg") == 0) ext = "jpg";
+ if (!img.mimeType.empty()) {
+ const char *ext = strchr(img.mimeType.c_str(), '/') + 1;
+ if (ext) {
+ if (strcmp(ext, "jpeg") == 0) ext = "jpg";
- size_t len = strlen(ext);
- if (len <= 3) {
- strcpy(tex->achFormatHint, ext);
- }
- }
- }
- }
+ size_t len = strlen(ext);
+ if (len <= 3) {
+ strcpy(tex->achFormatHint, ext);
+ }
+ }
+ }
+ }
}
-void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
-{
- // clean all member arrays
- meshOffsets.clear();
- embeddedTexIdxs.clear();
+void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
+ // clean all member arrays
+ meshOffsets.clear();
+ embeddedTexIdxs.clear();
- this->mScene = pScene;
+ this->mScene = pScene;
- // read the asset file
- glTF2::Asset asset(pIOHandler);
- asset.Load(pFile, GetExtension(pFile) == "glb");
+ // read the asset file
+ glTF2::Asset asset(pIOHandler);
+ asset.Load(pFile, GetExtension(pFile) == "glb");
- //
- // Copy the data out
- //
+ //
+ // Copy the data out
+ //
- ImportEmbeddedTextures(asset);
- ImportMaterials(asset);
+ ImportEmbeddedTextures(asset);
+ ImportMaterials(asset);
- ImportMeshes(asset);
+ ImportMeshes(asset);
- ImportCameras(asset);
- ImportLights(asset);
+ ImportCameras(asset);
+ ImportLights(asset);
- ImportNodes(asset);
+ ImportNodes(asset);
- ImportAnimations(asset);
+ ImportAnimations(asset);
- if (pScene->mNumMeshes == 0) {
- pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
- }
+ if (pScene->mNumMeshes == 0) {
+ pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
+ }
}
#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER
-
diff --git a/contrib/zip/.gitignore b/contrib/zip/.gitignore
index a7904a1ef..49b2cb2fd 100644
--- a/contrib/zip/.gitignore
+++ b/contrib/zip/.gitignore
@@ -1,6 +1,7 @@
/build/
/test/build/
/xcodeproj/
+.vscode/
# Object files
*.o
@@ -54,3 +55,4 @@ zip.dir/
test/test.exe.vcxproj.filters
test/test.exe.vcxproj
test/test.exe.dir/
+
diff --git a/contrib/zip/CMakeLists.txt b/contrib/zip/CMakeLists.txt
index b46dbb1db..77916d2e1 100644
--- a/contrib/zip/CMakeLists.txt
+++ b/contrib/zip/CMakeLists.txt
@@ -1,10 +1,14 @@
-cmake_minimum_required(VERSION 2.8)
-project(zip)
-enable_language(C)
+cmake_minimum_required(VERSION 3.0)
+
+project(zip
+ LANGUAGES C
+ VERSION "0.1.15")
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
+option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
+
if (MSVC)
- # Use secure functions by defaualt and suppress warnings about "deprecated" functions
+ # Use secure functions by default and suppress warnings about "deprecated" functions
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
@@ -12,28 +16,80 @@ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
"${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
"${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic")
+ if(ENABLE_COVERAGE)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
+ endif()
endif (MSVC)
# zip
set(SRC src/miniz.h src/zip.h src/zip.c)
add_library(${PROJECT_NAME} ${SRC})
-target_include_directories(${PROJECT_NAME} INTERFACE src)
+target_include_directories(${PROJECT_NAME} PUBLIC
+ $
+ $
+)
# test
if (NOT CMAKE_DISABLE_TESTING)
enable_testing()
add_subdirectory(test)
find_package(Sanitizers)
- add_sanitizers(${PROJECT_NAME} test.exe)
- add_sanitizers(${PROJECT_NAME} test_miniz.exe)
+ add_sanitizers(${PROJECT_NAME} ${test_out} ${test_miniz_out})
endif()
+####
+# Installation (https://github.com/forexample/package-example) {
+
+set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
+set(INCLUDE_INSTALL_DIR "include")
+
+set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
+
+# Configuration
+set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
+set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
+set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
+set(NAMESPACE "${PROJECT_NAME}::")
+
+# Include module with fuction 'write_basic_package_version_file'
+include(CMakePackageConfigHelpers)
+
+# Note: PROJECT_VERSION is used as a VERSION
+write_basic_package_version_file(
+ "${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion
+)
+
+# Use variables:
+# * TARGETS_EXPORT_NAME
+# * PROJECT_NAME
+configure_package_config_file(
+ "cmake/Config.cmake.in"
+ "${PROJECT_CONFIG}"
+ INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
+)
+
+install(
+ FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
+ DESTINATION "${CONFIG_INSTALL_DIR}"
+)
+
+install(
+ EXPORT "${TARGETS_EXPORT_NAME}"
+ NAMESPACE "${NAMESPACE}"
+ DESTINATION "${CONFIG_INSTALL_DIR}"
+)
+
+# }
+
install(TARGETS ${PROJECT_NAME}
+ EXPORT ${TARGETS_EXPORT_NAME}
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
- COMPONENT library)
-install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION include)
+ INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR}
+)
+install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION ${INCLUDE_INSTALL_DIR}/zip)
# uninstall target (https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake)
if(NOT TARGET uninstall)
@@ -45,3 +101,12 @@ if(NOT TARGET uninstall)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
endif()
+
+find_package(Doxygen)
+if(DOXYGEN_FOUND)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
+ add_custom_target(doc
+ ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating API documentation with Doxygen" VERBATIM)
+endif()
diff --git a/contrib/zip/README.md b/contrib/zip/README.md
index d5fb8cd20..14eb9a34c 100644
--- a/contrib/zip/README.md
+++ b/contrib/zip/README.md
@@ -71,7 +71,7 @@ int arg = 2;
zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
```
-* Extract a zip entry into memory.
+* Extract a zip entry into memory.
```c
void *buf = NULL;
size_t bufsize;
@@ -89,7 +89,7 @@ zip_close(zip);
free(buf);
```
-* Extract a zip entry into memory (no internal allocation).
+* Extract a zip entry into memory (no internal allocation).
```c
unsigned char *buf;
size_t bufsize;
@@ -110,7 +110,7 @@ zip_close(zip);
free(buf);
```
-* Extract a zip entry into memory using callback.
+* Extract a zip entry into memory using callback.
```c
struct buffer_t {
char *data;
@@ -144,7 +144,7 @@ free(buf.data);
```
-* Extract a zip entry into a file.
+* Extract a zip entry into a file.
```c
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
@@ -157,7 +157,7 @@ struct zip_t *zip = zip_open("foo.zip", 0, 'r');
zip_close(zip);
```
-* List of all zip entries
+* List of all zip entries
```c
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
int i, n = zip_total_entries(zip);
@@ -174,7 +174,7 @@ for (i = 0; i < n; ++i) {
zip_close(zip);
```
-## Bindings
+# Bindings
Compile zip library as a dynamic library.
```shell
$ mkdir build
diff --git a/contrib/zip/appveyor.yml b/contrib/zip/appveyor.yml
index 0be6373ca..ea17f5de9 100644
--- a/contrib/zip/appveyor.yml
+++ b/contrib/zip/appveyor.yml
@@ -1,4 +1,4 @@
-version: zip-0.1.9.{build}
+version: zip-0.1.15.{build}
build_script:
- cmd: >-
cd c:\projects\zip
diff --git a/contrib/zip/src/miniz.h b/contrib/zip/src/miniz.h
index 2c27a94d8..c4fcfb83e 100644
--- a/contrib/zip/src/miniz.h
+++ b/contrib/zip/src/miniz.h
@@ -221,6 +221,7 @@
#ifndef MINIZ_HEADER_INCLUDED
#define MINIZ_HEADER_INCLUDED
+#include
#include
// Defines to completely disable specific portions of miniz.c:
@@ -284,7 +285,8 @@
/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */
#if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES)
#if MINIZ_X86_OR_X64_CPU
-/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */
+/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient
+ * integer loads and stores from unaligned addresses. */
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
#define MINIZ_UNALIGNED_USE_MEMCPY
#else
@@ -354,6 +356,44 @@ enum {
MZ_FIXED = 4
};
+/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or
+ * modify this enum. */
+typedef enum {
+ MZ_ZIP_NO_ERROR = 0,
+ MZ_ZIP_UNDEFINED_ERROR,
+ MZ_ZIP_TOO_MANY_FILES,
+ MZ_ZIP_FILE_TOO_LARGE,
+ MZ_ZIP_UNSUPPORTED_METHOD,
+ MZ_ZIP_UNSUPPORTED_ENCRYPTION,
+ MZ_ZIP_UNSUPPORTED_FEATURE,
+ MZ_ZIP_FAILED_FINDING_CENTRAL_DIR,
+ MZ_ZIP_NOT_AN_ARCHIVE,
+ MZ_ZIP_INVALID_HEADER_OR_CORRUPTED,
+ MZ_ZIP_UNSUPPORTED_MULTIDISK,
+ MZ_ZIP_DECOMPRESSION_FAILED,
+ MZ_ZIP_COMPRESSION_FAILED,
+ MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE,
+ MZ_ZIP_CRC_CHECK_FAILED,
+ MZ_ZIP_UNSUPPORTED_CDIR_SIZE,
+ MZ_ZIP_ALLOC_FAILED,
+ MZ_ZIP_FILE_OPEN_FAILED,
+ MZ_ZIP_FILE_CREATE_FAILED,
+ MZ_ZIP_FILE_WRITE_FAILED,
+ MZ_ZIP_FILE_READ_FAILED,
+ MZ_ZIP_FILE_CLOSE_FAILED,
+ MZ_ZIP_FILE_SEEK_FAILED,
+ MZ_ZIP_FILE_STAT_FAILED,
+ MZ_ZIP_INVALID_PARAMETER,
+ MZ_ZIP_INVALID_FILENAME,
+ MZ_ZIP_BUF_TOO_SMALL,
+ MZ_ZIP_INTERNAL_ERROR,
+ MZ_ZIP_FILE_NOT_FOUND,
+ MZ_ZIP_ARCHIVE_TOO_LARGE,
+ MZ_ZIP_VALIDATION_FAILED,
+ MZ_ZIP_WRITE_CALLBACK_FAILED,
+ MZ_ZIP_TOTAL_ERRORS
+} mz_zip_error;
+
// Method
#define MZ_DEFLATED 8
@@ -696,6 +736,7 @@ typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs,
void *pBuf, size_t n);
typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
const void *pBuf, size_t n);
+typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque);
struct mz_zip_internal_state_tag;
typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
@@ -707,13 +748,27 @@ typedef enum {
MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
} mz_zip_mode;
-typedef struct mz_zip_archive_tag {
+typedef enum {
+ MZ_ZIP_TYPE_INVALID = 0,
+ MZ_ZIP_TYPE_USER,
+ MZ_ZIP_TYPE_MEMORY,
+ MZ_ZIP_TYPE_HEAP,
+ MZ_ZIP_TYPE_FILE,
+ MZ_ZIP_TYPE_CFILE,
+ MZ_ZIP_TOTAL_TYPES
+} mz_zip_type;
+
+typedef struct {
mz_uint64 m_archive_size;
mz_uint64 m_central_directory_file_ofs;
- mz_uint m_total_files;
- mz_zip_mode m_zip_mode;
- mz_uint m_file_offset_alignment;
+ /* We only support up to UINT32_MAX files in zip64 mode. */
+ mz_uint32 m_total_files;
+ mz_zip_mode m_zip_mode;
+ mz_zip_type m_zip_type;
+ mz_zip_error m_last_error;
+
+ mz_uint64 m_file_offset_alignment;
mz_alloc_func m_pAlloc;
mz_free_func m_pFree;
@@ -722,6 +777,7 @@ typedef struct mz_zip_archive_tag {
mz_file_read_func m_pRead;
mz_file_write_func m_pWrite;
+ mz_file_needs_keepalive m_pNeeds_keepalive;
void *m_pIO_opaque;
mz_zip_internal_state *m_pState;
@@ -1263,6 +1319,9 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
int strategy);
#endif // #ifndef MINIZ_NO_ZLIB_APIS
+#define MZ_UINT16_MAX (0xFFFFU)
+#define MZ_UINT32_MAX (0xFFFFFFFFU)
+
#ifdef __cplusplus
}
#endif
@@ -1311,6 +1370,11 @@ typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
#endif
+#define MZ_READ_LE64(p) \
+ (((mz_uint64)MZ_READ_LE32(p)) | \
+ (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) \
+ << 32U))
+
#ifdef _MSC_VER
#define MZ_FORCEINLINE __forceinline
#elif defined(__GNUC__)
@@ -4160,6 +4224,17 @@ enum {
MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
+
+ /* ZIP64 archive identifier and record sizes */
+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,
+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,
+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,
+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,
+ MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,
+ MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,
+ MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,
+ MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,
+
// Central directory header record offsets
MZ_ZIP_CDH_SIG_OFS = 0,
MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
@@ -4199,6 +4274,31 @@ enum {
MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
+
+ /* ZIP64 End of central directory locator offsets */
+ MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */
+ MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */
+ MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */
+ MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */
+
+ /* ZIP64 End of central directory header offsets */
+ MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */
+ MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */
+ MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */
+ MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */
+ MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */
+ MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */
+ MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */
+ MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */
+ MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */
+ MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */
+ MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,
+ MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,
+ MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,
+ MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,
+ MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,
+ MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,
+ MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11
};
typedef struct {
@@ -4211,7 +4311,24 @@ struct mz_zip_internal_state_tag {
mz_zip_array m_central_dir;
mz_zip_array m_central_dir_offsets;
mz_zip_array m_sorted_central_dir_offsets;
+
+ /* The flags passed in when the archive is initially opened. */
+ uint32_t m_init_flags;
+
+ /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc.
+ */
+ mz_bool m_zip64;
+
+ /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64
+ * will also be slammed to true too, even if we didn't find a zip64 end of
+ * central dir header, etc.) */
+ mz_bool m_zip64_has_extended_info_fields;
+
+ /* These fields are used by the file, FILE, memory, and memory/heap read/write
+ * helpers. */
MZ_FILE *m_pFile;
+ mz_uint64 m_file_archive_start_ofs;
+
void *m_pMem;
size_t m_mem_size;
size_t m_mem_capacity;
@@ -4363,6 +4480,13 @@ static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time,
#endif /* #ifndef MINIZ_NO_STDIO */
#endif /* #ifndef MINIZ_NO_TIME */
+static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip,
+ mz_zip_error err_num) {
+ if (pZip)
+ pZip->m_last_error = err_num;
+ return MZ_FALSE;
+}
+
static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
mz_uint32 flags) {
(void)flags;
@@ -4480,127 +4604,346 @@ mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) {
}
}
-static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
- mz_uint32 flags) {
- mz_uint cdir_size, num_this_disk, cdir_disk_index;
- mz_uint64 cdir_ofs;
+static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip,
+ mz_uint32 record_sig,
+ mz_uint32 record_size,
+ mz_int64 *pOfs) {
mz_int64 cur_file_ofs;
- const mz_uint8 *p;
mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
- mz_bool sort_central_dir =
- ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
- // Basic sanity checks - reject files which are too small, and check the first
- // 4 bytes of the file to make sure a local header is there.
- if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
+
+ /* Basic sanity checks - reject files which are too small */
+ if (pZip->m_archive_size < record_size)
return MZ_FALSE;
- // Find the end of central directory record by scanning the file from the end
- // towards the beginning.
+
+ /* Find the record by scanning the file from the end towards the beginning. */
cur_file_ofs =
MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
for (;;) {
int i,
n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
+
if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
return MZ_FALSE;
- for (i = n - 4; i >= 0; --i)
- if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
- break;
+
+ for (i = n - 4; i >= 0; --i) {
+ mz_uint s = MZ_READ_LE32(pBuf + i);
+ if (s == record_sig) {
+ if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)
+ break;
+ }
+ }
+
if (i >= 0) {
cur_file_ofs += i;
break;
}
+
+ /* Give up if we've searched the entire file, or we've gone back "too far"
+ * (~64kb) */
if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
- (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
+ (MZ_UINT16_MAX + record_size)))
return MZ_FALSE;
+
cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
}
- // Read and verify the end of central directory record.
+
+ *pOfs = cur_file_ofs;
+ return MZ_TRUE;
+}
+
+static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
+ mz_uint flags) {
+ mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0,
+ cdir_disk_index = 0;
+ mz_uint64 cdir_ofs = 0;
+ mz_int64 cur_file_ofs = 0;
+ const mz_uint8 *p;
+
+ mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
+ mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
+ mz_bool sort_central_dir =
+ ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
+ mz_uint32 zip64_end_of_central_dir_locator_u32
+ [(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) /
+ sizeof(mz_uint32)];
+ mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;
+
+ mz_uint32 zip64_end_of_central_dir_header_u32
+ [(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
+ sizeof(mz_uint32)];
+ mz_uint8 *pZip64_end_of_central_dir =
+ (mz_uint8 *)zip64_end_of_central_dir_header_u32;
+
+ mz_uint64 zip64_end_of_central_dir_ofs = 0;
+
+ /* Basic sanity checks - reject files which are too small, and check the first
+ * 4 bytes of the file to make sure a local header is there. */
+ if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
+ return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
+
+ if (!mz_zip_reader_locate_header_sig(
+ pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG,
+ MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))
+ return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);
+
+ /* Read and verify the end of central directory record. */
if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
- return MZ_FALSE;
- if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
- ((pZip->m_total_files =
- MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) !=
- MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
- return MZ_FALSE;
+ return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+ if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
+ MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
+ return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
+
+ if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE +
+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) {
+ if (pZip->m_pRead(pZip->m_pIO_opaque,
+ cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE,
+ pZip64_locator,
+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ==
+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) {
+ if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) ==
+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) {
+ zip64_end_of_central_dir_ofs = MZ_READ_LE64(
+ pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);
+ if (zip64_end_of_central_dir_ofs >
+ (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
+ return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
+
+ if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs,
+ pZip64_end_of_central_dir,
+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ==
+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) {
+ if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) ==
+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) {
+ pZip->m_pState->m_zip64 = MZ_TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);
+ cdir_entries_on_this_disk =
+ MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
+ cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);
+ cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
+
+ if (pZip->m_pState->m_zip64) {
+ mz_uint32 zip64_total_num_of_disks =
+ MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);
+ mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(
+ pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);
+ mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(
+ pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
+ mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(
+ pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);
+ mz_uint64 zip64_size_of_central_directory =
+ MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);
+
+ if (zip64_size_of_end_of_central_dir_record <
+ (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))
+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+ if (zip64_total_num_of_disks != 1U)
+ return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
+
+ /* Check for miniz's practical limits */
+ if (zip64_cdir_total_entries > MZ_UINT32_MAX)
+ return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
+
+ pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;
+
+ if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)
+ return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
+
+ cdir_entries_on_this_disk =
+ (mz_uint32)zip64_cdir_total_entries_on_this_disk;
+
+ /* Check for miniz's current practical limits (sorry, this should be enough
+ * for millions of files) */
+ if (zip64_size_of_central_directory > MZ_UINT32_MAX)
+ return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
+
+ cdir_size = (mz_uint32)zip64_size_of_central_directory;
+
+ num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir +
+ MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);
+
+ cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir +
+ MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);
+
+ cdir_ofs =
+ MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);
+ }
+
+ if (pZip->m_total_files != cdir_entries_on_this_disk)
+ return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
+
if (((num_this_disk | cdir_disk_index) != 0) &&
((num_this_disk != 1) || (cdir_disk_index != 1)))
- return MZ_FALSE;
+ return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
- if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) <
- pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
- return MZ_FALSE;
+ if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
- cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
- return MZ_FALSE;
+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
pZip->m_central_directory_file_ofs = cdir_ofs;
if (pZip->m_total_files) {
mz_uint i, n;
-
- // Read the entire central directory into a heap block, and allocate another
- // heap block to hold the unsorted central dir file record offsets, and
- // another to hold the sorted indices.
+ /* Read the entire central directory into a heap block, and allocate another
+ * heap block to hold the unsorted central dir file record offsets, and
+ * possibly another to hold the sorted indices. */
if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
MZ_FALSE)) ||
(!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
pZip->m_total_files, MZ_FALSE)))
- return MZ_FALSE;
+ return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
if (sort_central_dir) {
if (!mz_zip_array_resize(pZip,
&pZip->m_pState->m_sorted_central_dir_offsets,
pZip->m_total_files, MZ_FALSE))
- return MZ_FALSE;
+ return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
}
if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
pZip->m_pState->m_central_dir.m_p,
cdir_size) != cdir_size)
- return MZ_FALSE;
+ return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
- // Now create an index into the central directory file records, do some
- // basic sanity checking on each record, and check for zip64 entries (which
- // are not yet supported).
+ /* Now create an index into the central directory file records, do some
+ * basic sanity checking on each record */
p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
- mz_uint total_header_size, comp_size, decomp_size, disk_index;
+ mz_uint total_header_size, disk_index, bit_flags, filename_size,
+ ext_data_size;
+ mz_uint64 comp_size, decomp_size, local_header_ofs;
+
if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
(MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
- return MZ_FALSE;
+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
i) =
(mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
+
if (sort_central_dir)
MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
mz_uint32, i) = i;
+
comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
- if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
- (decomp_size != comp_size)) ||
- (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) ||
- (comp_size == 0xFFFFFFFF))
- return MZ_FALSE;
+ local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
+ filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
+ ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
+
+ if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&
+ (ext_data_size) &&
+ (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) ==
+ MZ_UINT32_MAX)) {
+ /* Attempt to find zip64 extended information field in the entry's extra
+ * data */
+ mz_uint32 extra_size_remaining = ext_data_size;
+
+ if (extra_size_remaining) {
+ const mz_uint8 *pExtra_data;
+ void *buf = NULL;
+
+ if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size >
+ n) {
+ buf = MZ_MALLOC(ext_data_size);
+ if (buf == NULL)
+ return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+
+ if (pZip->m_pRead(pZip->m_pIO_opaque,
+ cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
+ filename_size,
+ buf, ext_data_size) != ext_data_size) {
+ MZ_FREE(buf);
+ return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+ }
+
+ pExtra_data = (mz_uint8 *)buf;
+ } else {
+ pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
+ }
+
+ do {
+ mz_uint32 field_id;
+ mz_uint32 field_data_size;
+
+ if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
+ MZ_FREE(buf);
+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+ }
+
+ field_id = MZ_READ_LE16(pExtra_data);
+ field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
+
+ if ((field_data_size + sizeof(mz_uint16) * 2) >
+ extra_size_remaining) {
+ MZ_FREE(buf);
+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+ }
+
+ if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
+ /* Ok, the archive didn't have any zip64 headers but it uses a
+ * zip64 extended information field so mark it as zip64 anyway
+ * (this can occur with infozip's zip util when it reads
+ * compresses files from stdin). */
+ pZip->m_pState->m_zip64 = MZ_TRUE;
+ pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;
+ break;
+ }
+
+ pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
+ extra_size_remaining =
+ extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
+ } while (extra_size_remaining);
+
+ MZ_FREE(buf);
+ }
+ }
+
+ /* I've seen archives that aren't marked as zip64 that uses zip64 ext
+ * data, argh */
+ if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) {
+ if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
+ (decomp_size != comp_size)) ||
+ (decomp_size && !comp_size))
+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+ }
+
disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
- if ((disk_index != num_this_disk) && (disk_index != 1))
- return MZ_FALSE;
- if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
- MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
- return MZ_FALSE;
+ if ((disk_index == MZ_UINT16_MAX) ||
+ ((disk_index != num_this_disk) && (disk_index != 1)))
+ return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
+
+ if (comp_size != MZ_UINT32_MAX) {
+ if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
+ MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+ }
+
+ bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
+ if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)
+ return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
+
if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
n)
- return MZ_FALSE;
+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
n -= total_header_size;
p += total_header_size;
}
diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c
index ff3a8fe1e..1abcfd8fd 100644
--- a/contrib/zip/src/zip.c
+++ b/contrib/zip/src/zip.c
@@ -24,7 +24,6 @@
((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \
(P)[1] == ':')
#define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0)
-#define ISSLASH(C) ((C) == '/' || (C) == '\\')
#else
@@ -48,7 +47,7 @@ int symlink(const char *target, const char *linkpath); // needed on Linux
#endif
#ifndef ISSLASH
-#define ISSLASH(C) ((C) == '/')
+#define ISSLASH(C) ((C) == '/' || (C) == '\\')
#endif
#define CLEANUP(ptr) \
@@ -78,26 +77,34 @@ static const char *base_name(const char *name) {
return base;
}
-static int mkpath(const char *path) {
- char const *p;
+static int mkpath(char *path) {
+ char *p;
char npath[MAX_PATH + 1];
int len = 0;
int has_device = HAS_DEVICE(path);
memset(npath, 0, MAX_PATH + 1);
-
-#ifdef _WIN32
- // only on windows fix the path
- npath[0] = path[0];
- npath[1] = path[1];
- len = 2;
-#endif // _WIN32
-
+ if (has_device) {
+ // only on windows
+ npath[0] = path[0];
+ npath[1] = path[1];
+ len = 2;
+ }
for (p = path + len; *p && len < MAX_PATH; p++) {
if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) {
- if (MKDIR(npath) == -1)
- if (errno != EEXIST)
+#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
+ defined(__MINGW32__)
+#else
+ if ('\\' == *p) {
+ *p = '/';
+ }
+#endif
+
+ if (MKDIR(npath) == -1) {
+ if (errno != EEXIST) {
return -1;
+ }
+ }
}
npath[len++] = *p;
}
@@ -279,7 +286,14 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) {
zip->entry.header_offset = zip->archive.m_archive_size;
memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8));
zip->entry.method = 0;
+
+ // UNIX or APPLE
+#if MZ_PLATFORM == 3 || MZ_PLATFORM == 19
+ // regular file with rw-r--r-- persmissions
+ zip->entry.external_attr = (mz_uint32)(0100644) << 16;
+#else
zip->entry.external_attr = 0;
+#endif
num_alignment_padding_bytes =
mz_zip_writer_compute_padding_needed_for_file_alignment(pzip);
@@ -660,7 +674,7 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
}
if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index,
- buf, bufsize, 0, NULL, 0)) {
+ buf, bufsize, 0, NULL, 0)) {
return -1;
}
@@ -670,10 +684,7 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
int zip_entry_fread(struct zip_t *zip, const char *filename) {
mz_zip_archive *pzip = NULL;
mz_uint idx;
-#if defined(_MSC_VER)
-#else
mz_uint32 xattr = 0;
-#endif
mz_zip_archive_file_stat info;
if (!zip) {
@@ -875,12 +886,19 @@ int zip_extract(const char *zipname, const char *dir,
goto out;
}
- if ((((info.m_version_made_by >> 8) == 3) || ((info.m_version_made_by >> 8) == 19)) // if zip is produced on Unix or macOS (3 and 19 from section 4.4.2.2 of zip standard)
- && info.m_external_attr & (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40 is directory)
+ if ((((info.m_version_made_by >> 8) == 3) ||
+ ((info.m_version_made_by >> 8) ==
+ 19)) // if zip is produced on Unix or macOS (3 and 19 from
+ // section 4.4.2.2 of zip standard)
+ && info.m_external_attr &
+ (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40
+ // is directory)
#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
defined(__MINGW32__)
-#else
- if (info.m_uncomp_size > MAX_PATH || !mz_zip_reader_extract_to_mem_no_alloc(&zip_archive, i, symlink_to, MAX_PATH, 0, NULL, 0)) {
+#else
+ if (info.m_uncomp_size > MAX_PATH ||
+ !mz_zip_reader_extract_to_mem_no_alloc(&zip_archive, i, symlink_to,
+ MAX_PATH, 0, NULL, 0)) {
goto out;
}
symlink_to[info.m_uncomp_size] = '\0';
diff --git a/contrib/zip/src/zip.h b/contrib/zip/src/zip.h
index 5f39df50a..a48d64d6d 100644
--- a/contrib/zip/src/zip.h
+++ b/contrib/zip/src/zip.h
@@ -20,241 +20,240 @@ extern "C" {
#endif
#if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) && \
- !defined(_SSIZE_T) && !defined(_SSIZE_T_) && !defined(__ssize_t_defined)
-#define _SSIZE_T
+ !defined(__DEFINED_ssize_t) && !defined(__ssize_t_defined) && \
+ !defined(_SSIZE_T) && !defined(_SSIZE_T_)
+
// 64-bit Windows is the only mainstream platform
// where sizeof(long) != sizeof(void*)
#ifdef _WIN64
-typedef long long ssize_t; /* byte count or error */
+typedef long long ssize_t; /* byte count or error */
#else
-typedef long ssize_t; /* byte count or error */
+typedef long ssize_t; /* byte count or error */
#endif
+
+#define _SSIZE_T_DEFINED
+#define _SSIZE_T_DEFINED_
+#define __DEFINED_ssize_t
+#define __ssize_t_defined
+#define _SSIZE_T
+#define _SSIZE_T_
+
#endif
#ifndef MAX_PATH
#define MAX_PATH 32767 /* # chars in a path name including NULL */
#endif
+/**
+ * @mainpage
+ *
+ * Documenation for @ref zip.
+ */
+
+/**
+ * @addtogroup zip
+ * @{
+ */
+
+/**
+ * Default zip compression level.
+ */
+
#define ZIP_DEFAULT_COMPRESSION_LEVEL 6
-/*
- This data structure is used throughout the library to represent zip archive
- - forward declaration.
-*/
+/**
+ * @struct zip_t
+ *
+ * This data structure is used throughout the library to represent zip archive -
+ * forward declaration.
+ */
struct zip_t;
-/*
- Opens zip archive with compression level using the given mode.
-
- Args:
- zipname: zip archive file name.
- level: compression level (0-9 are the standard zlib-style levels).
- mode: file access mode.
- 'r': opens a file for reading/extracting (the file must exists).
- 'w': creates an empty file for writing.
- 'a': appends to an existing archive.
-
- Returns:
- The zip archive handler or NULL on error
-*/
+/**
+ * Opens zip archive with compression level using the given mode.
+ *
+ * @param zipname zip archive file name.
+ * @param level compression level (0-9 are the standard zlib-style levels).
+ * @param mode file access mode.
+ * - 'r': opens a file for reading/extracting (the file must exists).
+ * - 'w': creates an empty file for writing.
+ * - 'a': appends to an existing archive.
+ *
+ * @return the zip archive handler or NULL on error
+ */
extern struct zip_t *zip_open(const char *zipname, int level, char mode);
-/*
- Closes the zip archive, releases resources - always finalize.
-
- Args:
- zip: zip archive handler.
-*/
+/**
+ * Closes the zip archive, releases resources - always finalize.
+ *
+ * @param zip zip archive handler.
+ */
extern void zip_close(struct zip_t *zip);
-/*
- Opens an entry by name in the zip archive.
- For zip archive opened in 'w' or 'a' mode the function will append
- a new entry. In readonly mode the function tries to locate the entry
- in global dictionary.
-
- Args:
- zip: zip archive handler.
- entryname: an entry name in local dictionary.
-
- Returns:
- The return code - 0 on success, negative number (< 0) on error.
-*/
+/**
+ * Opens an entry by name in the zip archive.
+ *
+ * For zip archive opened in 'w' or 'a' mode the function will append
+ * a new entry. In readonly mode the function tries to locate the entry
+ * in global dictionary.
+ *
+ * @param zip zip archive handler.
+ * @param entryname an entry name in local dictionary.
+ *
+ * @return the return code - 0 on success, negative number (< 0) on error.
+ */
extern int zip_entry_open(struct zip_t *zip, const char *entryname);
-/*
- Opens a new entry by index in the zip archive.
- This function is only valid if zip archive was opened in 'r' (readonly) mode.
-
- Args:
- zip: zip archive handler.
- index: index in local dictionary.
-
- Returns:
- The return code - 0 on success, negative number (< 0) on error.
-*/
+/**
+ * Opens a new entry by index in the zip archive.
+ *
+ * This function is only valid if zip archive was opened in 'r' (readonly) mode.
+ *
+ * @param zip zip archive handler.
+ * @param index index in local dictionary.
+ *
+ * @return the return code - 0 on success, negative number (< 0) on error.
+ */
extern int zip_entry_openbyindex(struct zip_t *zip, int index);
-/*
- Closes a zip entry, flushes buffer and releases resources.
-
- Args:
- zip: zip archive handler.
-
- Returns:
- The return code - 0 on success, negative number (< 0) on error.
-*/
+/**
+ * Closes a zip entry, flushes buffer and releases resources.
+ *
+ * @param zip zip archive handler.
+ *
+ * @return the return code - 0 on success, negative number (< 0) on error.
+ */
extern int zip_entry_close(struct zip_t *zip);
-/*
- Returns a local name of the current zip entry.
- The main difference between user's entry name and local entry name
- is optional relative path.
- Following .ZIP File Format Specification - the path stored MUST not contain
- a drive or device letter, or a leading slash.
- All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
- for compatibility with Amiga and UNIX file systems etc.
-
- Args:
- zip: zip archive handler.
-
- Returns:
- The pointer to the current zip entry name, or NULL on error.
-*/
+/**
+ * Returns a local name of the current zip entry.
+ *
+ * The main difference between user's entry name and local entry name
+ * is optional relative path.
+ * Following .ZIP File Format Specification - the path stored MUST not contain
+ * a drive or device letter, or a leading slash.
+ * All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
+ * for compatibility with Amiga and UNIX file systems etc.
+ *
+ * @param zip: zip archive handler.
+ *
+ * @return the pointer to the current zip entry name, or NULL on error.
+ */
extern const char *zip_entry_name(struct zip_t *zip);
-/*
- Returns an index of the current zip entry.
-
- Args:
- zip: zip archive handler.
-
- Returns:
- The index on success, negative number (< 0) on error.
-*/
+/**
+ * Returns an index of the current zip entry.
+ *
+ * @param zip zip archive handler.
+ *
+ * @return the index on success, negative number (< 0) on error.
+ */
extern int zip_entry_index(struct zip_t *zip);
-/*
- Determines if the current zip entry is a directory entry.
-
- Args:
- zip: zip archive handler.
-
- Returns:
- The return code - 1 (true), 0 (false), negative number (< 0) on error.
-*/
+/**
+ * Determines if the current zip entry is a directory entry.
+ *
+ * @param zip zip archive handler.
+ *
+ * @return the return code - 1 (true), 0 (false), negative number (< 0) on
+ * error.
+ */
extern int zip_entry_isdir(struct zip_t *zip);
-/*
- Returns an uncompressed size of the current zip entry.
-
- Args:
- zip: zip archive handler.
-
- Returns:
- The uncompressed size in bytes.
-*/
+/**
+ * Returns an uncompressed size of the current zip entry.
+ *
+ * @param zip zip archive handler.
+ *
+ * @return the uncompressed size in bytes.
+ */
extern unsigned long long zip_entry_size(struct zip_t *zip);
-/*
- Returns CRC-32 checksum of the current zip entry.
-
- Args:
- zip: zip archive handler.
-
- Returns:
- The CRC-32 checksum.
-*/
+/**
+ * Returns CRC-32 checksum of the current zip entry.
+ *
+ * @param zip zip archive handler.
+ *
+ * @return the CRC-32 checksum.
+ */
extern unsigned int zip_entry_crc32(struct zip_t *zip);
-/*
- Compresses an input buffer for the current zip entry.
-
- Args:
- zip: zip archive handler.
- buf: input buffer.
- bufsize: input buffer size (in bytes).
-
- Returns:
- The return code - 0 on success, negative number (< 0) on error.
-*/
+/**
+ * Compresses an input buffer for the current zip entry.
+ *
+ * @param zip zip archive handler.
+ * @param buf input buffer.
+ * @param bufsize input buffer size (in bytes).
+ *
+ * @return the return code - 0 on success, negative number (< 0) on error.
+ */
extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
-/*
- Compresses a file for the current zip entry.
-
- Args:
- zip: zip archive handler.
- filename: input file.
-
- Returns:
- The return code - 0 on success, negative number (< 0) on error.
-*/
+/**
+ * Compresses a file for the current zip entry.
+ *
+ * @param zip zip archive handler.
+ * @param filename input file.
+ *
+ * @return the return code - 0 on success, negative number (< 0) on error.
+ */
extern int zip_entry_fwrite(struct zip_t *zip, const char *filename);
-/*
- Extracts the current zip entry into output buffer.
- The function allocates sufficient memory for a output buffer.
-
- Args:
- zip: zip archive handler.
- buf: output buffer.
- bufsize: output buffer size (in bytes).
-
- Note:
- - remember to release memory allocated for a output buffer.
- - for large entries, please take a look at zip_entry_extract function.
-
- Returns:
- The return code - the number of bytes actually read on success.
- Otherwise a -1 on error.
-*/
+/**
+ * Extracts the current zip entry into output buffer.
+ *
+ * The function allocates sufficient memory for a output buffer.
+ *
+ * @param zip zip archive handler.
+ * @param buf output buffer.
+ * @param bufsize output buffer size (in bytes).
+ *
+ * @note remember to release memory allocated for a output buffer.
+ * for large entries, please take a look at zip_entry_extract function.
+ *
+ * @return the return code - the number of bytes actually read on success.
+ * Otherwise a -1 on error.
+ */
extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
-/*
- Extracts the current zip entry into a memory buffer using no memory
- allocation.
+/**
+ * Extracts the current zip entry into a memory buffer using no memory
+ * allocation.
+ *
+ * @param zip zip archive handler.
+ * @param buf preallocated output buffer.
+ * @param bufsize output buffer size (in bytes).
+ *
+ * @note ensure supplied output buffer is large enough.
+ * zip_entry_size function (returns uncompressed size for the current
+ * entry) can be handy to estimate how big buffer is needed. for large
+ * entries, please take a look at zip_entry_extract function.
+ *
+ * @return the return code - the number of bytes actually read on success.
+ * Otherwise a -1 on error (e.g. bufsize is not large enough).
+ */
+extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
+ size_t bufsize);
- Args:
- zip: zip archive handler.
- buf: preallocated output buffer.
- bufsize: output buffer size (in bytes).
-
- Note:
- - ensure supplied output buffer is large enough.
- - zip_entry_size function (returns uncompressed size for the current entry)
- can be handy to estimate how big buffer is needed.
- - for large entries, please take a look at zip_entry_extract function.
-
- Returns:
- The return code - the number of bytes actually read on success.
- Otherwise a -1 on error (e.g. bufsize is not large enough).
-*/
-extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize);
-
-/*
- Extracts the current zip entry into output file.
-
- Args:
- zip: zip archive handler.
- filename: output file.
-
- Returns:
- The return code - 0 on success, negative number (< 0) on error.
-*/
+/**
+ * Extracts the current zip entry into output file.
+ *
+ * @param zip zip archive handler.
+ * @param filename output file.
+ *
+ * @return the return code - 0 on success, negative number (< 0) on error.
+ */
extern int zip_entry_fread(struct zip_t *zip, const char *filename);
-/*
- Extracts the current zip entry using a callback function (on_extract).
-
- Args:
- zip: zip archive handler.
- on_extract: callback function.
- arg: opaque pointer (optional argument,
- which you can pass to the on_extract callback)
-
- Returns:
- The return code - 0 on success, negative number (< 0) on error.
+/**
+ * Extracts the current zip entry using a callback function (on_extract).
+ *
+ * @param zip zip archive handler.
+ * @param on_extract callback function.
+ * @param arg opaque pointer (optional argument, which you can pass to the
+ * on_extract callback)
+ *
+ * @return the return code - 0 on success, negative number (< 0) on error.
*/
extern int
zip_entry_extract(struct zip_t *zip,
@@ -262,53 +261,49 @@ zip_entry_extract(struct zip_t *zip,
const void *data, size_t size),
void *arg);
-/*
- Returns the number of all entries (files and directories) in the zip archive.
-
- Args:
- zip: zip archive handler.
-
- Returns:
- The return code - the number of entries on success,
- negative number (< 0) on error.
-*/
+/**
+ * Returns the number of all entries (files and directories) in the zip archive.
+ *
+ * @param zip zip archive handler.
+ *
+ * @return the return code - the number of entries on success, negative number
+ * (< 0) on error.
+ */
extern int zip_total_entries(struct zip_t *zip);
-/*
- Creates a new archive and puts files into a single zip archive.
-
- Args:
- zipname: zip archive file.
- filenames: input files.
- len: number of input files.
-
- Returns:
- The return code - 0 on success, negative number (< 0) on error.
-*/
+/**
+ * Creates a new archive and puts files into a single zip archive.
+ *
+ * @param zipname zip archive file.
+ * @param filenames input files.
+ * @param len: number of input files.
+ *
+ * @return the return code - 0 on success, negative number (< 0) on error.
+ */
extern int zip_create(const char *zipname, const char *filenames[], size_t len);
-/*
- Extracts a zip archive file into directory.
-
- If on_extract_entry is not NULL, the callback will be called after
- successfully extracted each zip entry.
- Returning a negative value from the callback will cause abort and return an
- error. The last argument (void *arg) is optional, which you can use to pass
- data to the on_extract_entry callback.
-
- Args:
- zipname: zip archive file.
- dir: output directory.
- on_extract_entry: on extract callback.
- arg: opaque pointer.
-
- Returns:
- The return code - 0 on success, negative number (< 0) on error.
-*/
+/**
+ * Extracts a zip archive file into directory.
+ *
+ * If on_extract_entry is not NULL, the callback will be called after
+ * successfully extracted each zip entry.
+ * Returning a negative value from the callback will cause abort and return an
+ * error. The last argument (void *arg) is optional, which you can use to pass
+ * data to the on_extract_entry callback.
+ *
+ * @param zipname zip archive file.
+ * @param dir output directory.
+ * @param on_extract_entry on extract callback.
+ * @param arg opaque pointer.
+ *
+ * @return the return code - 0 on success, negative number (< 0) on error.
+ */
extern int zip_extract(const char *zipname, const char *dir,
int (*on_extract_entry)(const char *filename, void *arg),
void *arg);
+/** @} */
+
#ifdef __cplusplus
}
#endif
diff --git a/contrib/zip/test/CMakeLists.txt b/contrib/zip/test/CMakeLists.txt
index 9b2a8db10..cc060b00f 100644
--- a/contrib/zip/test/CMakeLists.txt
+++ b/contrib/zip/test/CMakeLists.txt
@@ -1,19 +1,16 @@
cmake_minimum_required(VERSION 2.8)
-if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
- if(ENABLE_COVERAGE)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g ")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage")
- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
- endif()
-endif ()
-
# test
-include_directories(../src)
-add_executable(test.exe test.c ../src/zip.c)
-add_executable(test_miniz.exe test_miniz.c)
+set(test_out test.out)
+set(test_miniz_out test_miniz.out)
-add_test(NAME test COMMAND test.exe)
-add_test(NAME test_miniz COMMAND test_miniz.exe)
+add_executable(${test_out} test.c)
+target_link_libraries(${test_out} zip)
+add_executable(${test_miniz_out} test_miniz.c)
+target_link_libraries(${test_miniz_out} zip)
+
+add_test(NAME ${test_out} COMMAND ${test_out})
+add_test(NAME ${test_miniz_out} COMMAND ${test_miniz_out})
+
+set(test_out ${test_out} PARENT_SCOPE)
+set(test_miniz_out ${test_miniz_out} PARENT_SCOPE)
diff --git a/contrib/zip/test/test.c b/contrib/zip/test/test.c
index 454430533..a9b2ddab1 100644
--- a/contrib/zip/test/test.c
+++ b/contrib/zip/test/test.c
@@ -29,6 +29,8 @@
#define XFILE "7.txt\0"
#define XMODE 0100777
+#define UNIXMODE 0100644
+
#define UNUSED(x) (void)x
static int total_entries = 0;
@@ -102,7 +104,8 @@ static void test_read(void) {
assert(0 == zip_entry_close(zip));
free(buf);
buf = NULL;
-
+ bufsize = 0;
+
assert(0 == zip_entry_open(zip, "test/test-2.txt"));
assert(strlen(TESTDATA2) == zip_entry_size(zip));
assert(CRC32DATA2 == zip_entry_crc32(zip));
@@ -131,7 +134,8 @@ static void test_read(void) {
assert(0 == zip_entry_close(zip));
free(buf);
buf = NULL;
-
+ bufsize = 0;
+
buftmp = strlen(TESTDATA1);
buf = calloc(buftmp, sizeof(char));
assert(0 == zip_entry_open(zip, "test/test-1.txt"));
@@ -433,6 +437,35 @@ static void test_mtime(void) {
remove(ZIPNAME);
}
+static void test_unix_permissions(void) {
+#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__)
+#else
+ // UNIX or APPLE
+ struct MZ_FILE_STAT_STRUCT file_stats;
+
+ remove(ZIPNAME);
+
+ struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
+ assert(zip != NULL);
+
+ assert(0 == zip_entry_open(zip, RFILE));
+ assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
+ assert(0 == zip_entry_close(zip));
+
+ zip_close(zip);
+
+ remove(RFILE);
+
+ assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
+
+ assert(0 == MZ_FILE_STAT(RFILE, &file_stats));
+ assert(UNIXMODE == file_stats.st_mode);
+
+ remove(RFILE);
+ remove(ZIPNAME);
+#endif
+}
+
int main(int argc, char *argv[]) {
UNUSED(argc);
UNUSED(argv);
@@ -453,6 +486,7 @@ int main(int argc, char *argv[]) {
test_write_permissions();
test_exe_permissions();
test_mtime();
+ test_unix_permissions();
remove(ZIPNAME);
return 0;
diff --git a/contrib/zip/test/test_miniz.c b/contrib/zip/test/test_miniz.c
index ebc0564dc..babcaecdb 100644
--- a/contrib/zip/test/test_miniz.c
+++ b/contrib/zip/test/test_miniz.c
@@ -23,16 +23,39 @@ int main(int argc, char *argv[]) {
uint step = 0;
int cmp_status;
uLong src_len = (uLong)strlen(s_pStr);
- uLong cmp_len = compressBound(src_len);
uLong uncomp_len = src_len;
+ uLong cmp_len;
uint8 *pCmp, *pUncomp;
+ size_t sz;
uint total_succeeded = 0;
(void)argc, (void)argv;
printf("miniz.c version: %s\n", MZ_VERSION);
do {
+ pCmp = (uint8 *)tdefl_compress_mem_to_heap(s_pStr, src_len, &cmp_len, 0);
+ if (!pCmp) {
+ printf("tdefl_compress_mem_to_heap failed\n");
+ return EXIT_FAILURE;
+ }
+ if (src_len <= cmp_len) {
+ printf("tdefl_compress_mem_to_heap failed: from %u to %u bytes\n",
+ (mz_uint32)uncomp_len, (mz_uint32)cmp_len);
+ free(pCmp);
+ return EXIT_FAILURE;
+ }
+
+ sz = tdefl_compress_mem_to_mem(pCmp, cmp_len, s_pStr, src_len, 0);
+ if (sz != cmp_len) {
+ printf("tdefl_compress_mem_to_mem failed: expected %u, got %u\n",
+ (mz_uint32)cmp_len, (mz_uint32)sz);
+ free(pCmp);
+ return EXIT_FAILURE;
+ }
+
// Allocate buffers to hold compressed and uncompressed data.
+ free(pCmp);
+ cmp_len = compressBound(src_len);
pCmp = (mz_uint8 *)malloc((size_t)cmp_len);
pUncomp = (mz_uint8 *)malloc((size_t)src_len);
if ((!pCmp) || (!pUncomp)) {
diff --git a/include/assimp/version.h b/include/assimp/version.h
index 2fdd37a43..90645a38f 100644
--- a/include/assimp/version.h
+++ b/include/assimp/version.h
@@ -62,6 +62,13 @@ extern "C" {
*/
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.
* @return Minor version of the Assimp runtime the application was
diff --git a/samples/SimpleTexturedDirectx11/CMakeLists.txt b/samples/SimpleTexturedDirectx11/CMakeLists.txt
new file mode 100644
index 000000000..373b5a9db
--- /dev/null
+++ b/samples/SimpleTexturedDirectx11/CMakeLists.txt
@@ -0,0 +1,46 @@
+FIND_PACKAGE(DirectX)
+
+IF ( MSVC )
+ SET(M_LIB)
+ENDIF ( MSVC )
+
+if ( MSVC )
+ ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
+ ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
+ REMOVE_DEFINITIONS( -DUNICODE -D_UNICODE )
+endif ( MSVC )
+
+INCLUDE_DIRECTORIES(
+ ${Assimp_SOURCE_DIR}/include
+ ${Assimp_SOURCE_DIR}/code
+ ${OPENGL_INCLUDE_DIR}
+ ${GLUT_INCLUDE_DIR}
+ ${Assimp_SOURCE_DIR}/samples/freeglut/include
+)
+
+LINK_DIRECTORIES(
+ ${Assimp_BINARY_DIR}
+ ${Assimp_BINARY_DIR}/lib
+)
+
+ADD_EXECUTABLE( assimp_simpletextureddirectx11 WIN32
+ SimpleTexturedDirectx11/Mesh.h
+ SimpleTexturedDirectx11/ModelLoader.cpp
+ SimpleTexturedDirectx11/ModelLoader.h
+ #SimpleTexturedDirectx11/PixelShader.hlsl
+ SimpleTexturedDirectx11/TextureLoader.cpp
+ SimpleTexturedDirectx11/TextureLoader.h
+ #SimpleTexturedDirectx11/VertexShader.hlsl
+ SimpleTexturedDirectx11/main.cpp
+)
+
+SET_PROPERTY(TARGET assimp_simpletextureddirectx11 PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
+
+TARGET_LINK_LIBRARIES( assimp_simpletextureddirectx11 assimp ${DirectX_LIBRARY} comctl32.lib winmm.lib )
+SET_TARGET_PROPERTIES( assimp_simpletextureddirectx11 PROPERTIES
+ OUTPUT_NAME assimp_simpletextureddirectx11
+)
+
+INSTALL( TARGETS assimp_simpletextureddirectx11
+ DESTINATION "${ASSIMP_BIN_INSTALL_DIR}" COMPONENT assimp-dev
+)
diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln
deleted file mode 100644
index 381ac8f94..000000000
--- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln
+++ /dev/null
@@ -1,28 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26228.9
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleTexturedDirectx11", "SimpleTexturedDirectx11\SimpleTexturedDirectx11.vcxproj", "{E3B160B5-E71F-4F3F-9310-B8F156F736D8}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.ActiveCfg = Debug|x64
- {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.Build.0 = Debug|x64
- {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.ActiveCfg = Debug|Win32
- {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.Build.0 = Debug|Win32
- {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.ActiveCfg = Release|x64
- {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.Build.0 = Release|x64
- {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.ActiveCfg = Release|Win32
- {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp
index a2d3faeb3..10ba07a98 100644
--- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp
+++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp
@@ -180,6 +180,8 @@ string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat
{
return "textures are on disk";
}
+
+ return ".";
}
int ModelLoader::getTextureIndex(aiString * str)
diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj
deleted file mode 100644
index 6584b7d7c..000000000
--- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj
+++ /dev/null
@@ -1,146 +0,0 @@
-
-
-
-
- Debug
- Win32
-
-
- Release
- Win32
-
-
- Debug
- x64
-
-
- Release
- x64
-
-
-
- 15.0
- {E3B160B5-E71F-4F3F-9310-B8F156F736D8}
- SimpleTexturedDirectx11
- 10.0.14393.0
-
-
-
- Application
- true
- v141
- MultiByte
-
-
- Application
- false
- v141
- true
- MultiByte
-
-
- Application
- true
- v141
- MultiByte
-
-
- Application
- false
- v141
- true
- MultiByte
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- $(IncludePath);E:\OpenGL VS Files\include
- $(LibraryPath);E:\OpenGL VS Files\lib
-
-
-
- Level3
- Disabled
- true
-
-
- assimp-vc140-mt.lib;%(AdditionalDependencies)
-
-
-
-
- Level3
- Disabled
- true
-
-
-
-
- Level3
- MaxSpeed
- true
- true
- true
-
-
- true
- true
-
-
-
-
- Level3
- MaxSpeed
- true
- true
- true
-
-
- true
- true
-
-
-
-
-
-
-
-
-
- Pixel
- Pixel
- Pixel
- Pixel
-
-
- Vertex
- Vertex
- Vertex
- Vertex
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters
deleted file mode 100644
index 3568b73c5..000000000
--- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-
- {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
- cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
-
-
- {93995380-89BD-4b04-88EB-625FBE52EBFB}
- h;hh;hpp;hxx;hm;inl;inc;xsd
-
-
- {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
- rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
-
-
- {b6a86d3e-70a5-4d1e-ba05-c20902300206}
-
-
-
-
- Source Files
-
-
- Source Files
-
-
- Source Files
-
-
-
-
- Shaders
-
-
- Shaders
-
-
-
-
- Header Files
-
-
- Header Files
-
-
- Header Files
-
-
-
\ No newline at end of file
diff --git a/test/models/glTF2/textureTransform/Arrow.png b/test/models/glTF2/textureTransform/Arrow.png
new file mode 100644
index 000000000..fe3405b3f
Binary files /dev/null and b/test/models/glTF2/textureTransform/Arrow.png differ
diff --git a/test/models/glTF2/textureTransform/Correct.png b/test/models/glTF2/textureTransform/Correct.png
new file mode 100644
index 000000000..e332824fb
Binary files /dev/null and b/test/models/glTF2/textureTransform/Correct.png differ
diff --git a/test/models/glTF2/textureTransform/Error.png b/test/models/glTF2/textureTransform/Error.png
new file mode 100644
index 000000000..35acf6e94
Binary files /dev/null and b/test/models/glTF2/textureTransform/Error.png differ
diff --git a/test/models/glTF2/textureTransform/License.txt b/test/models/glTF2/textureTransform/License.txt
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/models/glTF2/textureTransform/NotSupported.png b/test/models/glTF2/textureTransform/NotSupported.png
new file mode 100644
index 000000000..721e7fd76
Binary files /dev/null and b/test/models/glTF2/textureTransform/NotSupported.png differ
diff --git a/test/models/glTF2/textureTransform/TextureTransformTest.bin b/test/models/glTF2/textureTransform/TextureTransformTest.bin
new file mode 100644
index 000000000..6765a1300
Binary files /dev/null and b/test/models/glTF2/textureTransform/TextureTransformTest.bin differ
diff --git a/test/models/glTF2/textureTransform/TextureTransformTest.gltf b/test/models/glTF2/textureTransform/TextureTransformTest.gltf
new file mode 100644
index 000000000..6dde51d9a
--- /dev/null
+++ b/test/models/glTF2/textureTransform/TextureTransformTest.gltf
@@ -0,0 +1,540 @@
+{
+ "accessors": [
+ {
+ "bufferView": 0,
+ "componentType": 5126,
+ "count": 4,
+ "type": "VEC3",
+ "max": [
+ 0.5,
+ 0.5,
+ 0.0
+ ],
+ "min": [
+ -0.5,
+ -0.5,
+ 0.0
+ ],
+ "name": "Positions"
+ },
+ {
+ "bufferView": 1,
+ "componentType": 5126,
+ "count": 4,
+ "type": "VEC2",
+ "name": "UV0"
+ },
+ {
+ "bufferView": 2,
+ "componentType": 5126,
+ "count": 4,
+ "type": "VEC2",
+ "name": "UV1"
+ },
+ {
+ "bufferView": 3,
+ "componentType": 5125,
+ "count": 6,
+ "type": "SCALAR",
+ "name": "Indices"
+ }
+ ],
+ "asset": {
+ "version": "2.0"
+ },
+ "buffers": [
+ {
+ "uri": "TextureTransformTest.bin",
+ "byteLength": 136
+ }
+ ],
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteLength": 48,
+ "name": "Positions"
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 48,
+ "byteLength": 32,
+ "name": "UV0"
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 80,
+ "byteLength": 32,
+ "name": "UV1"
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 112,
+ "byteLength": 24,
+ "name": "Indices"
+ }
+ ],
+ "extensionsUsed": [
+ "KHR_texture_transform"
+ ],
+ "images": [
+ {
+ "uri": "UV.png"
+ },
+ {
+ "uri": "Arrow.png"
+ },
+ {
+ "uri": "Correct.png"
+ },
+ {
+ "uri": "NotSupported.png"
+ },
+ {
+ "uri": "Error.png"
+ }
+ ],
+ "materials": [
+ {
+ "name": "Offset U",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 0,
+ "extensions": {
+ "KHR_texture_transform": {
+ "offset": [
+ 0.5,
+ 0.0
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "Offset V",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 0,
+ "extensions": {
+ "KHR_texture_transform": {
+ "offset": [
+ 0.0,
+ 0.5
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "Offset UV",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 0,
+ "extensions": {
+ "KHR_texture_transform": {
+ "offset": [
+ 0.5,
+ 0.5
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "Rotation",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 1,
+ "extensions": {
+ "KHR_texture_transform": {
+ "rotation": 0.39269908169872415480783042290994
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "Scale",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 1,
+ "extensions": {
+ "KHR_texture_transform": {
+ "scale": [
+ 1.5,
+ 1.5
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "All",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 1,
+ "extensions": {
+ "KHR_texture_transform": {
+ "offset": [
+ -0.2,
+ -0.1
+ ],
+ "rotation": 0.3,
+ "scale": [
+ 1.5,
+ 1.5
+ ]
+ }
+ }
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "Correct",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 2
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "NotSupported",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 3
+ },
+ "metallicFactor": 0
+ }
+ },
+ {
+ "name": "Error",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 4
+ },
+ "metallicFactor": 0
+ }
+ }
+ ],
+ "meshes": [
+ {
+ "name": "Offset U",
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "TEXCOORD_0": 2
+ },
+ "indices": 3,
+ "material": 0
+ }
+ ]
+ },
+ {
+ "name": "Offset V",
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "TEXCOORD_0": 2
+ },
+ "indices": 3,
+ "material": 1
+ }
+ ]
+ },
+ {
+ "name": "Offset UV",
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "TEXCOORD_0": 2
+ },
+ "indices": 3,
+ "material": 2
+ }
+ ]
+ },
+ {
+ "name": "Rotation",
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "TEXCOORD_0": 1
+ },
+ "indices": 3,
+ "material": 3
+ }
+ ]
+ },
+ {
+ "name": "Scale",
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "TEXCOORD_0": 1
+ },
+ "indices": 3,
+ "material": 4
+ }
+ ]
+ },
+ {
+ "name": "All",
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "TEXCOORD_0": 1
+ },
+ "indices": 3,
+ "material": 5
+ }
+ ]
+ },
+ {
+ "name": "Correct Marker",
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "TEXCOORD_0": 1
+ },
+ "indices": 3,
+ "material": 6
+ }
+ ]
+ },
+ {
+ "name": "Not Supported Marker",
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "TEXCOORD_0": 1
+ },
+ "indices": 3,
+ "material": 7
+ }
+ ]
+ },
+ {
+ "name": "Error Marker",
+ "primitives": [
+ {
+ "attributes": {
+ "POSITION": 0,
+ "TEXCOORD_0": 1
+ },
+ "indices": 3,
+ "material": 8
+ }
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "name": "Offset U",
+ "mesh": 0,
+ "translation": [
+ -1.1,
+ 0.55,
+ 0
+ ]
+ },
+ {
+ "name": "Offset V",
+ "mesh": 1,
+ "translation": [
+ 0,
+ 0.55,
+ 0
+ ]
+ },
+ {
+ "name": "Offset UV",
+ "mesh": 2,
+ "translation": [
+ 1.1,
+ 0.55,
+ 0
+ ]
+ },
+ {
+ "name": "Rotation",
+ "mesh": 3,
+ "translation": [
+ -1.1,
+ -0.55,
+ 0
+ ],
+ "children": [
+ 4,
+ 5,
+ 6
+ ]
+ },
+ {
+ "name": "Rotation - Correct",
+ "mesh": 6,
+ "translation": [
+ -0.07904822439840125109869401756656,
+ -0.51626748576241543174100150833647,
+ 0.01
+ ],
+ "scale": [
+ 0.15,
+ 0.15,
+ 0.15
+ ]
+ },
+ {
+ "name": "Rotation - Not Supported",
+ "mesh": 7,
+ "translation": [
+ 0.27781745930520227684092879831533,
+ -0.27781745930520227684092879831533,
+ 0.01
+ ],
+ "scale": [
+ 0.15,
+ 0.15,
+ 0.15
+ ]
+ },
+ {
+ "name": "Rotation - Error",
+ "mesh": 8,
+ "translation": [
+ 0.51626748576241543174100150833647,
+ 0.07904822439840125109869401756656,
+ 0.01
+ ],
+ "scale": [
+ 0.15,
+ 0.15,
+ 0.15
+ ]
+ },
+ {
+ "name": "Scale",
+ "mesh": 4,
+ "translation": [
+ 0,
+ -0.55,
+ 0
+ ],
+ "children": [
+ 8,
+ 9
+ ]
+ },
+ {
+ "name": "Scale - Correct",
+ "mesh": 6,
+ "translation": [
+ 0.01854497287013485122728586554355,
+ -0.01854497287013485122728586554355,
+ 0.01
+ ],
+ "scale": [
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ },
+ {
+ "name": "Scale - Not Supported",
+ "mesh": 7,
+ "translation": [
+ 0.27781745930520227684092879831533,
+ -0.27781745930520227684092879831533,
+ 0.01
+ ],
+ "scale": [
+ 0.15,
+ 0.15,
+ 0.15
+ ]
+ },
+ {
+ "name": "All",
+ "mesh": 5,
+ "translation": [
+ 1.1,
+ -0.55,
+ 0
+ ],
+ "children": [
+ 11
+ ]
+ },
+ {
+ "name": "All - Correct",
+ "mesh": 6,
+ "translation": [
+ -0.07,
+ -0.25,
+ 0.01
+ ],
+ "scale": [
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ }
+ ],
+ "scene": 0,
+ "scenes": [
+ {
+ "nodes": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 7,
+ 10
+ ]
+ }
+ ],
+ "textures": [
+ {
+ "source": 0,
+ "sampler": 0
+ },
+ {
+ "source": 1,
+ "sampler": 0
+ },
+ {
+ "source": 2
+ },
+ {
+ "source": 3
+ },
+ {
+ "source": 4
+ }
+ ],
+ "samplers": [
+ {
+ "wrapS": 33071,
+ "wrapT": 33071,
+ "magFilter": 9729,
+ "minFilter": 9729
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/models/glTF2/textureTransform/UV.png b/test/models/glTF2/textureTransform/UV.png
new file mode 100644
index 000000000..c1a6d4d37
Binary files /dev/null and b/test/models/glTF2/textureTransform/UV.png differ
diff --git a/test/unit/utM3DImportExport.cpp b/test/unit/utM3DImportExport.cpp
index c3a0fb08c..31028235d 100644
--- a/test/unit/utM3DImportExport.cpp
+++ b/test/unit/utM3DImportExport.cpp
@@ -54,7 +54,7 @@ class utM3DImportExport : public AbstractImportExportBase {
public:
virtual bool importerTest() {
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
return nullptr != scene;
#else
diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp
index 3c1f6fea6..ef1316fb7 100644
--- a/test/unit/utglTF2ImportExport.cpp
+++ b/test/unit/utglTF2ImportExport.cpp
@@ -405,6 +405,13 @@ TEST_F(utglTF2ImportExport, incorrect_vertex_arrays) {
EXPECT_EQ(scene->mMeshes[7]->mNumFaces, 17u);
}
+TEST_F( utglTF2ImportExport, texture_transform_test ) {
+ Assimp::Importer importer;
+ const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/textureTransform/TextureTransformTest.gltf",
+ aiProcess_ValidateDataStructure);
+ EXPECT_NE(nullptr, scene);
+}
+
#ifndef ASSIMP_BUILD_NO_EXPORT
TEST_F( utglTF2ImportExport, exportglTF2FromFileTest ) {
EXPECT_TRUE( exporterTest() );
]