2008-09-16 16:17:32 +00:00
|
|
|
/*
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
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 RAW importer class */
|
|
|
|
|
|
|
|
// internal headers
|
2008-09-30 13:05:48 +00:00
|
|
|
#include "RawLoader.h"
|
2008-09-16 16:17:32 +00:00
|
|
|
#include "MaterialSystem.h"
|
|
|
|
#include "ParsingUtils.h"
|
|
|
|
#include "fast_atof.h"
|
|
|
|
|
|
|
|
// public assimp headers
|
|
|
|
#include "../include/IOStream.h"
|
|
|
|
#include "../include/IOSystem.h"
|
|
|
|
#include "../include/aiScene.h"
|
|
|
|
#include "../include/aiAssert.h"
|
|
|
|
#include "../include/DefaultLogger.h"
|
|
|
|
|
|
|
|
// boost headers
|
|
|
|
#include <boost/scoped_ptr.hpp>
|
|
|
|
|
|
|
|
using namespace Assimp;
|
|
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Constructor to be privately used by Importer
|
|
|
|
RAWImporter::RAWImporter()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Destructor, private as well
|
|
|
|
RAWImporter::~RAWImporter()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Returns whether the class can handle the format of the given file.
|
|
|
|
bool RAWImporter::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);
|
|
|
|
|
|
|
|
if (extension.length() < 4)return false;
|
|
|
|
if (extension[0] != '.')return false;
|
|
|
|
|
|
|
|
return !(extension.length() != 4 || extension[0] != '.' ||
|
|
|
|
extension[1] != 'r' && extension[1] != 'R' ||
|
|
|
|
extension[2] != 'a' && extension[2] != 'A' ||
|
|
|
|
extension[3] != 'w' && extension[3] != 'W');
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#define AI_RAW_IS_NON_INTEGRAL(sz) \
|
|
|
|
((*sz < '0' || *sz > '9') && *sz != '+' && *sz != '-')
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Imports the given file into the given scene structure.
|
|
|
|
void RAWImporter::InternReadFile( const std::string& pFile,
|
|
|
|
aiScene* pScene, IOSystem* pIOHandler)
|
|
|
|
{
|
|
|
|
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
|
|
|
|
|
|
|
// Check whether we can read from the file
|
|
|
|
if( file.get() == NULL)
|
|
|
|
throw new ImportErrorException( "Failed to open RAW file " + pFile + ".");
|
|
|
|
|
|
|
|
unsigned int fileSize = (unsigned int)file->FileSize();
|
|
|
|
|
|
|
|
// allocate storage and copy the contents of the file to a memory buffer
|
|
|
|
// (terminate it with zero)
|
|
|
|
std::vector<char> mBuffer2(fileSize+1);
|
|
|
|
|
|
|
|
file->Read(&mBuffer2[0], 1, fileSize);
|
|
|
|
mBuffer2[fileSize] = '\0';
|
|
|
|
const char* buffer = &mBuffer2[0];
|
|
|
|
|
|
|
|
// list of groups loaded from the file
|
|
|
|
std::vector< GroupInformation > outGroups(1,GroupInformation("<default>"));
|
|
|
|
std::vector< GroupInformation >::iterator curGroup = outGroups.begin();
|
|
|
|
|
|
|
|
// now read all lines
|
|
|
|
char line[4096];
|
|
|
|
while (GetNextLine(buffer,line))
|
|
|
|
{
|
|
|
|
// if the line starts with a non-numeric identifier, it marks
|
|
|
|
// the beginning of a new group
|
|
|
|
const char* sz = line;SkipSpaces(&sz);
|
|
|
|
if (IsLineEnd(*sz))continue;
|
|
|
|
if (AI_RAW_IS_NON_INTEGRAL(sz))
|
|
|
|
{
|
|
|
|
const char* sz2 = sz;
|
|
|
|
while (!IsSpaceOrNewLine(*sz2))++sz2;
|
|
|
|
const unsigned int length = (unsigned int)(sz2-sz);
|
|
|
|
|
|
|
|
// find an existing group with this name
|
|
|
|
for (std::vector< GroupInformation >::iterator it = outGroups.begin(), end = outGroups.end();
|
|
|
|
it != end;++it)
|
|
|
|
{
|
|
|
|
if (length == (*it).name.length() && !::strcmp(sz,(*it).name.c_str()))
|
|
|
|
{
|
|
|
|
curGroup = it;sz2 = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sz2)
|
|
|
|
{
|
|
|
|
outGroups.push_back(GroupInformation(std::string(sz,length)));
|
|
|
|
curGroup = outGroups.end()-1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// there can be maximally 12 floats plus an extra texture file name
|
|
|
|
float data[12];
|
|
|
|
unsigned int num;
|
|
|
|
for (num = 0; num < 12;++num)
|
|
|
|
{
|
|
|
|
if(!SkipSpaces(&sz) || AI_RAW_IS_NON_INTEGRAL(sz))break;
|
|
|
|
sz = fast_atof_move(sz,data[num]);
|
|
|
|
}
|
|
|
|
if (num != 12 && num != 9)
|
|
|
|
{
|
|
|
|
DefaultLogger::get()->error("A line may have either 9 or 12 floats and an optional texture");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
MeshInformation* output = NULL;
|
|
|
|
|
|
|
|
const char* sz2 = sz;
|
|
|
|
unsigned int length;
|
|
|
|
if (!IsLineEnd(*sz))
|
|
|
|
{
|
|
|
|
while (!IsSpaceOrNewLine(*sz2))++sz2;
|
|
|
|
length = (unsigned int)(sz2-sz);
|
|
|
|
}
|
|
|
|
else if (9 == num)
|
|
|
|
{
|
|
|
|
sz = "%default%";
|
|
|
|
length = 9;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sz = "";
|
|
|
|
length = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// search in the list of meshes whether we have one with this texture
|
|
|
|
for (std::vector< MeshInformation >::iterator it = (*curGroup).meshes.begin(),
|
|
|
|
end = (*curGroup).meshes.end(); it != end; ++it)
|
|
|
|
{
|
|
|
|
if (length == (*it).name.length() && (length ? !::strcmp(sz,(*it).name.c_str()) : true))
|
|
|
|
{
|
|
|
|
output = &(*it);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if we don't have the mesh, create it
|
|
|
|
if (!output)
|
|
|
|
{
|
|
|
|
(*curGroup).meshes.push_back(MeshInformation(std::string(sz,length)));
|
|
|
|
output = &((*curGroup).meshes.back());
|
|
|
|
}
|
|
|
|
if (12 == num)
|
|
|
|
{
|
|
|
|
aiColor4D v(data[0],data[1],data[2],1.0f);
|
|
|
|
output->colors.push_back(v);
|
|
|
|
output->colors.push_back(v);
|
|
|
|
output->colors.push_back(v);
|
|
|
|
|
|
|
|
output->vertices.push_back(aiVector3D(data[3],data[4],data[5]));
|
|
|
|
output->vertices.push_back(aiVector3D(data[6],data[7],data[8]));
|
|
|
|
output->vertices.push_back(aiVector3D(data[9],data[10],data[11]));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
output->vertices.push_back(aiVector3D(data[0],data[1],data[2]));
|
|
|
|
output->vertices.push_back(aiVector3D(data[3],data[4],data[5]));
|
|
|
|
output->vertices.push_back(aiVector3D(data[6],data[7],data[8]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pScene->mRootNode = new aiNode();
|
|
|
|
pScene->mRootNode->mName.Set("<RawRoot>");
|
|
|
|
|
|
|
|
// count the number of valid groups
|
|
|
|
// (meshes can't be empty)
|
|
|
|
for (std::vector< GroupInformation >::iterator it = outGroups.begin(), end = outGroups.end();
|
|
|
|
it != end;++it)
|
|
|
|
{
|
|
|
|
if (!(*it).meshes.empty())
|
|
|
|
{
|
|
|
|
++pScene->mRootNode->mNumChildren;
|
|
|
|
pScene->mNumMeshes += (unsigned int)(*it).meshes.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pScene->mNumMeshes)
|
|
|
|
{
|
|
|
|
throw new ImportErrorException("RAW: No meshes loaded. The file seems to be corrupt or empty.");
|
|
|
|
}
|
|
|
|
|
|
|
|
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
|
|
|
aiNode** cc;
|
|
|
|
if (1 == pScene->mRootNode->mNumChildren)
|
|
|
|
{
|
|
|
|
cc = &pScene->mRootNode;
|
|
|
|
pScene->mRootNode->mNumChildren = 0;
|
|
|
|
}
|
|
|
|
else cc = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren];
|
|
|
|
|
|
|
|
pScene->mNumMaterials = pScene->mNumMeshes;
|
|
|
|
aiMaterial** mats = pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
|
|
|
|
|
|
|
|
unsigned int meshIdx = 0;
|
|
|
|
for (std::vector< GroupInformation >::iterator it = outGroups.begin(), end = outGroups.end();
|
|
|
|
it != end;++it)
|
|
|
|
{
|
|
|
|
if ((*it).meshes.empty())continue;
|
|
|
|
|
|
|
|
aiNode* node;
|
|
|
|
if (pScene->mRootNode->mNumChildren)
|
|
|
|
{
|
|
|
|
node = *cc = new aiNode();
|
|
|
|
node->mParent = pScene->mRootNode;
|
|
|
|
}
|
|
|
|
else node = *cc;++cc;
|
|
|
|
node->mName.Set((*it).name);
|
|
|
|
|
|
|
|
// add all meshes
|
|
|
|
node->mNumMeshes = (unsigned int)(*it).meshes.size();
|
|
|
|
unsigned int* pi = node->mMeshes = new unsigned int[ node->mNumMeshes ];
|
|
|
|
for (std::vector< MeshInformation >::iterator it2 = (*it).meshes.begin(),
|
|
|
|
end2 = (*it).meshes.end(); it2 != end2; ++it2)
|
|
|
|
{
|
|
|
|
ai_assert(!(*it2).vertices.empty());
|
|
|
|
|
|
|
|
// allocate the mesh
|
|
|
|
*pi++ = meshIdx;
|
|
|
|
aiMesh* mesh = pScene->mMeshes[meshIdx] = new aiMesh();
|
|
|
|
mesh->mMaterialIndex = meshIdx++;
|
|
|
|
|
2008-09-30 20:20:56 +00:00
|
|
|
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
|
|
|
|
2008-09-16 16:17:32 +00:00
|
|
|
// allocate storage for the vertex components and copy them
|
|
|
|
mesh->mNumVertices = (unsigned int)(*it2).vertices.size();
|
|
|
|
mesh->mVertices = new aiVector3D[ mesh->mNumVertices ];
|
|
|
|
::memcpy(mesh->mVertices,&(*it2).vertices[0],sizeof(aiVector3D)*mesh->mNumVertices);
|
|
|
|
|
|
|
|
if ((*it2).colors.size())
|
|
|
|
{
|
|
|
|
ai_assert((*it2).colors.size() == mesh->mNumVertices);
|
|
|
|
|
|
|
|
mesh->mColors[0] = new aiColor4D[ mesh->mNumVertices ];
|
|
|
|
::memcpy(mesh->mColors[0],&(*it2).colors[0],sizeof(aiColor4D)*mesh->mNumVertices);
|
|
|
|
}
|
|
|
|
|
|
|
|
// generate triangles
|
|
|
|
ai_assert(0 == mesh->mNumVertices % 3);
|
|
|
|
aiFace* fc = mesh->mFaces = new aiFace[ mesh->mNumFaces = mesh->mNumVertices/3 ];
|
|
|
|
aiFace* const fcEnd = fc + mesh->mNumFaces;
|
|
|
|
unsigned int n = 0;
|
|
|
|
while (fc != fcEnd)
|
|
|
|
{
|
|
|
|
aiFace& f = *fc++;
|
|
|
|
f.mIndices = new unsigned int[f.mNumIndices = 3];
|
|
|
|
for (unsigned int m = 0; m < 3;++m)
|
|
|
|
f.mIndices[m] = n++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// generate a material for the mesh
|
|
|
|
MaterialHelper* mat = new MaterialHelper();
|
|
|
|
|
|
|
|
aiColor4D clr(1.0f,1.0f,1.0f,1.0f);
|
|
|
|
if ("%default%" == (*it2).name) // a gray default material
|
|
|
|
{
|
|
|
|
clr.r = clr.g = clr.b = 0.6f;
|
|
|
|
}
|
|
|
|
else if ((*it2).name.length() > 0) // a texture
|
|
|
|
{
|
|
|
|
aiString s;
|
|
|
|
s.Set((*it2).name);
|
|
|
|
mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
|
|
|
}
|
|
|
|
mat->AddProperty<aiColor4D>(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
|
|
|
|
*mats++ = mat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|