|
@@ -0,0 +1,577 @@
|
|
|
|
+/*
|
|
|
|
+---------------------------------------------------------------------------
|
|
|
|
+Open Asset Import Library (ASSIMP)
|
|
|
|
+---------------------------------------------------------------------------
|
|
|
|
+
|
|
|
|
+Copyright (c) 2006-2008, ASSIMP Development Team
|
|
|
|
+
|
|
|
|
+All rights reserved.
|
|
|
|
+
|
|
|
|
+Redistribution and use of this software in source and binary forms,
|
|
|
|
+with or without modification, are permitted provided that the following
|
|
|
|
+conditions are met:
|
|
|
|
+
|
|
|
|
+* Redistributions of source code must retain the above
|
|
|
|
+ copyright notice, this list of conditions and the
|
|
|
|
+ following disclaimer.
|
|
|
|
+
|
|
|
|
+* Redistributions in binary form must reproduce the above
|
|
|
|
+ copyright notice, this list of conditions and the
|
|
|
|
+ following disclaimer in the documentation and/or other
|
|
|
|
+ materials provided with the distribution.
|
|
|
|
+
|
|
|
|
+* Neither the name of the ASSIMP team, nor the names of its
|
|
|
|
+ contributors may be used to endorse or promote products
|
|
|
|
+ derived from this software without specific prior
|
|
|
|
+ written permission of the ASSIMP Development Team.
|
|
|
|
+
|
|
|
|
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
+---------------------------------------------------------------------------
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+/** @file Implementation of the Q3D importer class */
|
|
|
|
+
|
|
|
|
+#include "AssimpPCH.h"
|
|
|
|
+
|
|
|
|
+// internal headers
|
|
|
|
+#include "Q3DLoader.h"
|
|
|
|
+#include "StreamReader.h"
|
|
|
|
+#include "fast_atof.h"
|
|
|
|
+
|
|
|
|
+using namespace Assimp;
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Constructor to be privately used by Importer
|
|
|
|
+Q3DImporter::Q3DImporter()
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Destructor, private as well
|
|
|
|
+Q3DImporter::~Q3DImporter()
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Returns whether the class can handle the format of the given file.
|
|
|
|
+bool Q3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
|
|
|
|
+{
|
|
|
|
+ // simple check of file extension is enough for the moment
|
|
|
|
+ std::string::size_type pos = pFile.find_last_of('.');
|
|
|
|
+ // no file extension - can't read
|
|
|
|
+ if( pos == std::string::npos)return false;
|
|
|
|
+
|
|
|
|
+ std::string extension = pFile.substr( pos);
|
|
|
|
+ for (std::string::iterator it = extension.begin();
|
|
|
|
+ it != extension.end(); ++it)
|
|
|
|
+ *it = ::tolower(*it);
|
|
|
|
+
|
|
|
|
+ return (extension == ".q3o" || extension == ".q3s");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ------------------------------------------------------------------------------------------------
|
|
|
|
+// Imports the given file into the given scene structure.
|
|
|
|
+void Q3DImporter::InternReadFile( const std::string& pFile,
|
|
|
|
+ aiScene* pScene, IOSystem* pIOHandler)
|
|
|
|
+{
|
|
|
|
+ StreamReaderLE stream(pIOHandler->Open(pFile,"rb"));
|
|
|
|
+
|
|
|
|
+ // The header is 22 bytes large
|
|
|
|
+ if (stream.GetRemainingSize() < 22)
|
|
|
|
+ throw new ImportErrorException("File is either empty or corrupt: " + pFile);
|
|
|
|
+
|
|
|
|
+ // Check the file signature
|
|
|
|
+ if (ASSIMP_strincmp( (const char*)stream.GetPtr(), "quick3Do", 8 ) &&
|
|
|
|
+ ASSIMP_strincmp( (const char*)stream.GetPtr(), "quick3Ds", 8 ))
|
|
|
|
+ {
|
|
|
|
+ throw new ImportErrorException("No Quick3D file. Signature is: " +
|
|
|
|
+ std::string((const char*)stream.GetPtr(),8));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Print the file format version
|
|
|
|
+ DefaultLogger::get()->info("Quick3D File format version: " +
|
|
|
|
+ std::string(&((const char*)stream.GetPtr())[8],2));
|
|
|
|
+
|
|
|
|
+ // ... an store it
|
|
|
|
+ unsigned int ff = strtol10(&((const char*)stream.GetPtr())[8]);
|
|
|
|
+
|
|
|
|
+ stream.IncPtr(10);
|
|
|
|
+ unsigned int numMeshes = (unsigned int)stream.GetI4();
|
|
|
|
+ unsigned int numMats = (unsigned int)stream.GetI4();
|
|
|
|
+ unsigned int numTextures = (unsigned int)stream.GetI4();
|
|
|
|
+
|
|
|
|
+ std::vector<Material> materials;
|
|
|
|
+ materials.reserve(numMats);
|
|
|
|
+
|
|
|
|
+ std::vector<Mesh> meshes;
|
|
|
|
+ meshes.reserve(numMeshes);
|
|
|
|
+
|
|
|
|
+ // Allocate the scene root node
|
|
|
|
+ pScene->mRootNode = new aiNode();
|
|
|
|
+
|
|
|
|
+ aiColor3D fgColor (0.6f,0.6f,0.6f);
|
|
|
|
+
|
|
|
|
+ // Now read all file chunks
|
|
|
|
+ while (true)
|
|
|
|
+ {
|
|
|
|
+ if (stream.GetRemainingSize() < 1)break;
|
|
|
|
+ char c = stream.GetI1();
|
|
|
|
+ switch (c)
|
|
|
|
+ {
|
|
|
|
+ // Meshes chunk
|
|
|
|
+ case 'm':
|
|
|
|
+ {
|
|
|
|
+ for (unsigned int quak = 0; quak < numMeshes; ++quak)
|
|
|
|
+ {
|
|
|
|
+ meshes.push_back(Mesh());
|
|
|
|
+ Mesh& mesh = meshes.back();
|
|
|
|
+
|
|
|
|
+ // read all vertices
|
|
|
|
+ unsigned int numVerts = (unsigned int)stream.GetI4();
|
|
|
|
+ if (!numVerts)
|
|
|
|
+ throw new ImportErrorException("Quick3D: Found mesh with zero vertices");
|
|
|
|
+
|
|
|
|
+ std::vector<aiVector3D>& verts = mesh.verts;
|
|
|
|
+ verts.resize(numVerts);
|
|
|
|
+
|
|
|
|
+ for (unsigned int i = 0; i < numVerts;++i)
|
|
|
|
+ {
|
|
|
|
+ verts[i].x = stream.GetF4();
|
|
|
|
+ verts[i].y = stream.GetF4();
|
|
|
|
+ verts[i].z = stream.GetF4();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // read all faces
|
|
|
|
+ numVerts = (unsigned int)stream.GetI4();
|
|
|
|
+ if (!numVerts)
|
|
|
|
+ throw new ImportErrorException("Quick3D: Found mesh with zero faces");
|
|
|
|
+
|
|
|
|
+ std::vector<Face >& faces = mesh.faces;
|
|
|
|
+ faces.reserve(numVerts);
|
|
|
|
+
|
|
|
|
+ // number of indices
|
|
|
|
+ for (unsigned int i = 0; i < numVerts;++i)
|
|
|
|
+ {
|
|
|
|
+ faces.push_back(Face(stream.GetI2()) );
|
|
|
|
+ if (faces.back().indices.empty())
|
|
|
|
+ throw new ImportErrorException("Quick3D: Found face with zero indices");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // indices
|
|
|
|
+ for (unsigned int i = 0; i < numVerts;++i)
|
|
|
|
+ {
|
|
|
|
+ Face& vec = faces[i];
|
|
|
|
+ for (unsigned int a = 0; a < (unsigned int)vec.indices.size();++a)
|
|
|
|
+ vec.indices[a] = stream.GetI4();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // material indices
|
|
|
|
+ for (unsigned int i = 0; i < numVerts;++i)
|
|
|
|
+ {
|
|
|
|
+ faces[i].mat = (unsigned int)stream.GetI4();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // read all normals
|
|
|
|
+ numVerts = (unsigned int)stream.GetI4();
|
|
|
|
+ std::vector<aiVector3D>& normals = mesh.normals;
|
|
|
|
+ normals.resize(numVerts);
|
|
|
|
+
|
|
|
|
+ for (unsigned int i = 0; i < numVerts;++i)
|
|
|
|
+ {
|
|
|
|
+ normals[i].x = stream.GetF4();
|
|
|
|
+ normals[i].y = stream.GetF4();
|
|
|
|
+ normals[i].z = stream.GetF4();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (numTextures)
|
|
|
|
+ {
|
|
|
|
+ // read all texture coordinates
|
|
|
|
+ numVerts = (unsigned int)stream.GetI4();
|
|
|
|
+ std::vector<aiVector3D>& uv = mesh.uv;
|
|
|
|
+ uv.resize(numVerts);
|
|
|
|
+
|
|
|
|
+ for (unsigned int i = 0; i < numVerts;++i)
|
|
|
|
+ {
|
|
|
|
+ uv[i].x = stream.GetF4();
|
|
|
|
+ uv[i].y = stream.GetF4();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // UV indices
|
|
|
|
+ for (unsigned int i = 0; i < (unsigned int)faces.size();++i)
|
|
|
|
+ {
|
|
|
|
+ Face& vec = faces[i];
|
|
|
|
+ for (unsigned int a = 0; a < (unsigned int)vec.indices.size();++a)
|
|
|
|
+ {
|
|
|
|
+ vec.indices[a] = stream.GetI4();
|
|
|
|
+ if (!i && !a)
|
|
|
|
+ mesh.prevUVIdx = vec.indices[a];
|
|
|
|
+ else if (vec.indices[a] != mesh.prevUVIdx)
|
|
|
|
+ mesh.prevUVIdx = 0xffffffff;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // we don't need the rest, but we need to get to the next chunk
|
|
|
|
+ stream.IncPtr(36 + ((ff > 30 ? 12 : 0 )));
|
|
|
|
+ }
|
|
|
|
+ stream.IncPtr(4 + (ff > 30 ? 24 : 0 )); // unknown value here
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ // materials chunk
|
|
|
|
+ case 'c':
|
|
|
|
+
|
|
|
|
+ for (unsigned int i = 0; i < numMats; ++i)
|
|
|
|
+ {
|
|
|
|
+ materials.push_back(Material());
|
|
|
|
+ Material& mat = materials.back();
|
|
|
|
+
|
|
|
|
+ // read the material name
|
|
|
|
+ while (( c = stream.GetI1()))
|
|
|
|
+ mat.name.data[mat.name.length++] = c;
|
|
|
|
+
|
|
|
|
+ // add the terminal character
|
|
|
|
+ mat.name.data[mat.name.length] = '\0';
|
|
|
|
+
|
|
|
|
+ // read the ambient color
|
|
|
|
+ mat.ambient.r = stream.GetF4();
|
|
|
|
+ mat.ambient.g = stream.GetF4();
|
|
|
|
+ mat.ambient.b = stream.GetF4();
|
|
|
|
+
|
|
|
|
+ // read the diffuse color
|
|
|
|
+ mat.diffuse.r = stream.GetF4();
|
|
|
|
+ mat.diffuse.g = stream.GetF4();
|
|
|
|
+ mat.diffuse.b = stream.GetF4();
|
|
|
|
+
|
|
|
|
+ // read the ambient color
|
|
|
|
+ mat.specular.r = stream.GetF4();
|
|
|
|
+ mat.specular.g = stream.GetF4();
|
|
|
|
+ mat.specular.b = stream.GetF4();
|
|
|
|
+
|
|
|
|
+ // read the transparency
|
|
|
|
+ mat.transparency = stream.GetF4();
|
|
|
|
+
|
|
|
|
+ // unknown value here
|
|
|
|
+ stream.IncPtr(4);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ // texture chunk
|
|
|
|
+ case 't':
|
|
|
|
+
|
|
|
|
+ pScene->mNumTextures = numTextures;
|
|
|
|
+ if (!numTextures)break;
|
|
|
|
+ pScene->mTextures = new aiTexture*[pScene->mNumTextures];
|
|
|
|
+ // to make sure we won't crash if we leave through an exception
|
|
|
|
+ ::memset(pScene->mTextures,0,sizeof(void*)*pScene->mNumTextures);
|
|
|
|
+ for (unsigned int i = 0; i < pScene->mNumTextures; ++i)
|
|
|
|
+ {
|
|
|
|
+ aiTexture* tex = pScene->mTextures[i] = new aiTexture();
|
|
|
|
+
|
|
|
|
+ // skip the texture name
|
|
|
|
+ while (stream.GetI1());
|
|
|
|
+
|
|
|
|
+ // read texture width and height
|
|
|
|
+ tex->mWidth = (unsigned int)stream.GetI4();
|
|
|
|
+ tex->mHeight = (unsigned int)stream.GetI4();
|
|
|
|
+
|
|
|
|
+ if (!tex->mWidth || !tex->mHeight)
|
|
|
|
+ throw new ImportErrorException("Quick3D: Invalid texture. Width or height is zero");
|
|
|
|
+
|
|
|
|
+ register unsigned int mul = tex->mWidth * tex->mHeight;
|
|
|
|
+ aiTexel* begin = tex->pcData = new aiTexel[mul];
|
|
|
|
+ aiTexel* const end = & begin [mul];
|
|
|
|
+
|
|
|
|
+ for (;begin != end; ++begin)
|
|
|
|
+ {
|
|
|
|
+ begin->r = stream.GetI1();
|
|
|
|
+ begin->g = stream.GetI1();
|
|
|
|
+ begin->b = stream.GetI1();
|
|
|
|
+ begin->a = 0xff;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ // scene chunk
|
|
|
|
+ case 's':
|
|
|
|
+ {
|
|
|
|
+ // skip position and rotation
|
|
|
|
+ stream.IncPtr(12);
|
|
|
|
+
|
|
|
|
+ for (unsigned int i = 0; i < 4;++i)
|
|
|
|
+ for (unsigned int a = 0; a < 4;++a)
|
|
|
|
+ pScene->mRootNode->mTransformation[i][a] = stream.GetF4();
|
|
|
|
+
|
|
|
|
+ stream.IncPtr(16);
|
|
|
|
+
|
|
|
|
+ // now setup a single camera
|
|
|
|
+ pScene->mNumCameras = 1;
|
|
|
|
+ pScene->mCameras = new aiCamera*[1];
|
|
|
|
+ aiCamera* cam = pScene->mCameras[0] = new aiCamera();
|
|
|
|
+ cam->mPosition.x = stream.GetF4();
|
|
|
|
+ cam->mPosition.y = stream.GetF4();
|
|
|
|
+ cam->mPosition.z = stream.GetF4();
|
|
|
|
+ cam->mName.Set("Q3DCamera");
|
|
|
|
+
|
|
|
|
+ // skip eye rotation for the moment
|
|
|
|
+ stream.IncPtr(12);
|
|
|
|
+
|
|
|
|
+ // read the default material color
|
|
|
|
+ fgColor .r = stream.GetF4();
|
|
|
|
+ fgColor .g = stream.GetF4();
|
|
|
|
+ fgColor .b = stream.GetF4();
|
|
|
|
+
|
|
|
|
+ // skip some unimportant properties
|
|
|
|
+ stream.IncPtr(29);
|
|
|
|
+
|
|
|
|
+ // setup a single point light with no attenuation
|
|
|
|
+ pScene->mNumLights = 1;
|
|
|
|
+ pScene->mLights = new aiLight*[1];
|
|
|
|
+ aiLight* light = pScene->mLights[0] = new aiLight();
|
|
|
|
+ light->mName.Set("Q3DLight");
|
|
|
|
+ light->mType = aiLightSource_POINT;
|
|
|
|
+
|
|
|
|
+ light->mAttenuationConstant = 1;
|
|
|
|
+ light->mAttenuationLinear = 0;
|
|
|
|
+ light->mAttenuationQuadratic = 0;
|
|
|
|
+
|
|
|
|
+ light->mColorDiffuse.r = stream.GetF4();
|
|
|
|
+ light->mColorDiffuse.g = stream.GetF4();
|
|
|
|
+ light->mColorDiffuse.b = stream.GetF4();
|
|
|
|
+
|
|
|
|
+ light->mColorSpecular = light->mColorDiffuse;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // We don't need the rest, but we need to know where
|
|
|
|
+ // this fucking chunk ends.
|
|
|
|
+ unsigned int temp = (unsigned int)(stream.GetI4() * stream.GetI4());
|
|
|
|
+
|
|
|
|
+ // skip the background file name
|
|
|
|
+ while (stream.GetI1());
|
|
|
|
+
|
|
|
|
+ // skip background texture data + the remaining fields
|
|
|
|
+ stream.IncPtr(temp*3 + 20); // 4 bytes of unknown data here
|
|
|
|
+
|
|
|
|
+ // TODO
|
|
|
|
+ goto outer;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ default:
|
|
|
|
+ throw new ImportErrorException("Quick3D: Unknown chunk");
|
|
|
|
+ break;
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
+outer:
|
|
|
|
+
|
|
|
|
+ // If we have no mesh loaded - break here
|
|
|
|
+ if (meshes.empty())
|
|
|
|
+ throw new ImportErrorException("Quick3D: No meshes loaded");
|
|
|
|
+
|
|
|
|
+ // If we have no materials loaded - generate a default mat
|
|
|
|
+ if (materials.empty())
|
|
|
|
+ {
|
|
|
|
+ DefaultLogger::get()->info("Quick3D: No material found, generating one");
|
|
|
|
+ materials.push_back(Material());
|
|
|
|
+ materials.back().diffuse = fgColor ;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // find out which materials we'll need
|
|
|
|
+ typedef std::pair<unsigned int, unsigned int> FaceIdx;
|
|
|
|
+ typedef std::vector< FaceIdx > FaceIdxArray;
|
|
|
|
+ FaceIdxArray* fidx = new FaceIdxArray[materials.size()];
|
|
|
|
+
|
|
|
|
+ unsigned int p = 0;
|
|
|
|
+ for (std::vector<Mesh>::iterator it = meshes.begin(), end = meshes.end();
|
|
|
|
+ it != end; ++it,++p)
|
|
|
|
+ {
|
|
|
|
+ unsigned int q = 0;
|
|
|
|
+ for (std::vector<Face>::iterator fit = (*it).faces.begin(), fend = (*it).faces.end();
|
|
|
|
+ fit != fend; ++fit,++q)
|
|
|
|
+ {
|
|
|
|
+ if ((*fit).mat >= materials.size())
|
|
|
|
+ {
|
|
|
|
+ DefaultLogger::get()->warn("Quick3D: Material index overflow");
|
|
|
|
+ (*fit).mat = 0;
|
|
|
|
+ }
|
|
|
|
+ if (fidx[(*fit).mat].empty())++pScene->mNumMeshes;
|
|
|
|
+ fidx[(*fit).mat].push_back( FaceIdx(p,q) );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ pScene->mNumMaterials = pScene->mNumMeshes;
|
|
|
|
+ pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
|
|
|
|
+ pScene->mMeshes = new aiMesh*[pScene->mNumMaterials];
|
|
|
|
+
|
|
|
|
+ for (unsigned int i = 0, real = 0; i < (unsigned int)materials.size(); ++i)
|
|
|
|
+ {
|
|
|
|
+ if (fidx[i].empty())continue;
|
|
|
|
+
|
|
|
|
+ // Allocate a mesh and a material
|
|
|
|
+ aiMesh* mesh = pScene->mMeshes[real] = new aiMesh();
|
|
|
|
+ MaterialHelper* mat = new MaterialHelper();
|
|
|
|
+ pScene->mMaterials[real] = mat;
|
|
|
|
+
|
|
|
|
+ mesh->mMaterialIndex = real;
|
|
|
|
+
|
|
|
|
+ // Build the output material
|
|
|
|
+ Material& srcMat = materials[i];
|
|
|
|
+ mat->AddProperty(&srcMat.diffuse, 1,AI_MATKEY_COLOR_DIFFUSE);
|
|
|
|
+ mat->AddProperty(&srcMat.specular, 1,AI_MATKEY_COLOR_SPECULAR);
|
|
|
|
+ mat->AddProperty(&srcMat.ambient, 1,AI_MATKEY_COLOR_AMBIENT);
|
|
|
|
+
|
|
|
|
+ //srcMat.transparency = 1.0f - srcMat.transparency;
|
|
|
|
+ mat->AddProperty(&srcMat.transparency, 1, AI_MATKEY_OPACITY);
|
|
|
|
+
|
|
|
|
+ // add shininess - Quick3D seems to use it ins its viewer
|
|
|
|
+ srcMat.transparency = 16.f;
|
|
|
|
+ mat->AddProperty(&srcMat.transparency, 1, AI_MATKEY_SHININESS);
|
|
|
|
+
|
|
|
|
+ int m = (int)aiShadingMode_Phong;
|
|
|
|
+ mat->AddProperty(&m, 1, AI_MATKEY_SHADING_MODEL);
|
|
|
|
+
|
|
|
|
+ if (srcMat.name.length)
|
|
|
|
+ mat->AddProperty(&srcMat.name,AI_MATKEY_NAME);
|
|
|
|
+
|
|
|
|
+ // Add a texture
|
|
|
|
+ if (real < pScene->mNumTextures)
|
|
|
|
+ {
|
|
|
|
+ srcMat.name.data[0] = '*';
|
|
|
|
+ srcMat.name.length = itoa10(&srcMat.name.data[1],1000,real);
|
|
|
|
+ mat->AddProperty(&srcMat.name,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ mesh->mNumFaces = (unsigned int)fidx[i].size();
|
|
|
|
+ aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
|
|
|
|
+
|
|
|
|
+ // Now build the output mesh. First find out how many
|
|
|
|
+ // vertices we'll need
|
|
|
|
+ for (FaceIdxArray::const_iterator it = fidx[i].begin(),end = fidx[i].end();
|
|
|
|
+ it != end; ++it)
|
|
|
|
+ {
|
|
|
|
+ mesh->mNumVertices += (unsigned int)meshes[(*it).first].faces[
|
|
|
|
+ (*it).second].indices.size();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
|
|
|
+ aiVector3D* norms = mesh->mNormals = new aiVector3D[mesh->mNumVertices];
|
|
|
|
+ aiVector3D* uv;
|
|
|
|
+ if (real < pScene->mNumTextures)
|
|
|
|
+ {
|
|
|
|
+ uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
|
|
|
|
+ mesh->mNumUVComponents[0] = 2;
|
|
|
|
+ }
|
|
|
|
+ else uv = NULL;
|
|
|
|
+
|
|
|
|
+ // Build the final array
|
|
|
|
+ unsigned int cnt = 0;
|
|
|
|
+ for (FaceIdxArray::const_iterator it = fidx[i].begin(),end = fidx[i].end();
|
|
|
|
+ it != end; ++it, ++faces)
|
|
|
|
+ {
|
|
|
|
+ Mesh& m = meshes[(*it).first];
|
|
|
|
+ Face& face = m.faces[(*it).second];
|
|
|
|
+ faces->mNumIndices = (unsigned int)face.indices.size();
|
|
|
|
+ faces->mIndices = new unsigned int [faces->mNumIndices];
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ aiVector3D faceNormal;
|
|
|
|
+ bool fnOK = false;
|
|
|
|
+
|
|
|
|
+ for (unsigned int n = 0; n < faces->mNumIndices;++n, ++cnt, ++norms, ++verts)
|
|
|
|
+ {
|
|
|
|
+ if (face.indices[n] >= m.verts.size())
|
|
|
|
+ {
|
|
|
|
+ DefaultLogger::get()->warn("Quick3D: Vertex index overflow");
|
|
|
|
+ face.indices[n] = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // copy vertices
|
|
|
|
+ *verts = m.verts[ face.indices[n] ];
|
|
|
|
+
|
|
|
|
+ if (face.indices[n] >= m.normals.size() && faces->mNumIndices >= 3)
|
|
|
|
+ {
|
|
|
|
+ // we have no normal here - assign the face normal
|
|
|
|
+ if (!fnOK)
|
|
|
|
+ {
|
|
|
|
+ const aiVector3D& pV1 = m.verts[ face.indices[0] ];
|
|
|
|
+ const aiVector3D& pV2 = m.verts[ face.indices[1] ];
|
|
|
|
+ const aiVector3D& pV3 = m.verts[ face.indices.size() - 1 ];
|
|
|
|
+ faceNormal = (pV2 - pV1) ^ (pV3 - pV1).Normalize();
|
|
|
|
+ fnOK = true;
|
|
|
|
+ }
|
|
|
|
+ *norms = faceNormal;
|
|
|
|
+ }
|
|
|
|
+ else *norms = m.normals[ face.indices[n] ];
|
|
|
|
+
|
|
|
|
+ // copy texture coordinates
|
|
|
|
+ if (uv)
|
|
|
|
+ {
|
|
|
|
+ if (m.prevUVIdx != 0xffffffff && m.uv.size() >= m.verts.size()) // workaround
|
|
|
|
+ {
|
|
|
|
+ *uv++ = m.uv[face.indices[n]];
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ if (face.uvindices[n] >= m.uv.size())
|
|
|
|
+ {
|
|
|
|
+ DefaultLogger::get()->warn("Quick3D: Texture coordinate index overflow");
|
|
|
|
+ face.uvindices[n] = 0;
|
|
|
|
+ }
|
|
|
|
+ *uv++ = m.uv[face.uvindices[n]];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // setup the new vertex index
|
|
|
|
+ faces->mIndices[n] = cnt;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ ++real;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Delete our nice helper array
|
|
|
|
+ delete[] fidx;
|
|
|
|
+
|
|
|
|
+ // Now we need to attach the meshes to the root node of the scene
|
|
|
|
+ pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
|
|
|
|
+ pScene->mRootNode->mMeshes = new unsigned int [pScene->mNumMeshes];
|
|
|
|
+ for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
|
|
|
+ pScene->mRootNode->mMeshes[i] = i;
|
|
|
|
+
|
|
|
|
+ pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
|
|
|
+ 1.f, 0.f, 0.f, 0.f,
|
|
|
|
+ 0.f, -1.f,0.f, 0.f,
|
|
|
|
+ 0.f, 0.f, 1.f, 0.f,
|
|
|
|
+ 0.f, 0.f, 0.f, 1.f);
|
|
|
|
+
|
|
|
|
+ // Add cameras and light sources to the scene root node
|
|
|
|
+ pScene->mRootNode->mNumChildren = pScene->mNumLights+pScene->mNumCameras;
|
|
|
|
+ if (pScene->mRootNode->mNumChildren)
|
|
|
|
+ {
|
|
|
|
+ pScene->mRootNode->mChildren = new aiNode* [ pScene->mRootNode->mNumChildren ];
|
|
|
|
+
|
|
|
|
+ // the light source
|
|
|
|
+ aiNode* nd = pScene->mRootNode->mChildren[0] = new aiNode();
|
|
|
|
+ nd->mParent = pScene->mRootNode;
|
|
|
|
+ nd->mName.Set("Q3DLight");
|
|
|
|
+ nd->mTransformation = pScene->mRootNode->mTransformation;
|
|
|
|
+ nd->mTransformation.Inverse();
|
|
|
|
+
|
|
|
|
+ // camera
|
|
|
|
+ nd = pScene->mRootNode->mChildren[1] = new aiNode();
|
|
|
|
+ nd->mParent = pScene->mRootNode;
|
|
|
|
+ nd->mName.Set("Q3DCamera");
|
|
|
|
+ nd->mTransformation = pScene->mRootNode->mChildren[0]->mTransformation;
|
|
|
|
+ }
|
|
|
|
+}
|