Further work on the IRR, AC, LWS loaders. Further work on the - still unfinished - OptimizeGraph step. SceneCombiner works now properly in all cases I tested yet.
Added missing 'typename' in Colladaparser.h First implementation of spherical and cylindrical mapping, already in use for IRR and LWO models. For the latter the coordinate system is not yet correct. Moved vec2d to a separate header and added operators similar to vec3. Added plane and ray helper classes. Just the data is wrapped, no operators required for the moment. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@249 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
9ca66fb999
commit
fd9e6edc19
|
@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "ACLoader.h"
|
||||
#include "ParsingUtils.h"
|
||||
#include "fast_atof.h"
|
||||
|
||||
//#include "Subdivision.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
@ -159,7 +159,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
|||
Object& obj = objects.back();
|
||||
|
||||
aiLight* light = NULL;
|
||||
if (!ASSIMP_stricmp(buffer,"light"))
|
||||
if (!ASSIMP_strincmp(buffer,"light",5))
|
||||
{
|
||||
// This is a light source. Add it to the list
|
||||
mLights->push_back(light = new aiLight());
|
||||
|
@ -173,7 +173,22 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
|||
light->mName.length = ::sprintf(light->mName.data,"ACLight_%i",mLights->size()-1);
|
||||
obj.name = std::string( light->mName.data );
|
||||
|
||||
DefaultLogger::get()->debug("AC3D: Light source encountered");
|
||||
obj.type = Object::Light;
|
||||
}
|
||||
else if (!ASSIMP_strincmp(buffer,"group",5))
|
||||
{
|
||||
obj.type = Object::Group;
|
||||
}
|
||||
else if (!ASSIMP_strincmp(buffer,"poly",4))
|
||||
{
|
||||
obj.type = Object::Poly;
|
||||
}
|
||||
else if (!ASSIMP_strincmp(buffer,"world",5))
|
||||
{
|
||||
obj.type = Object::World;
|
||||
}
|
||||
|
||||
|
||||
while (GetNextLine())
|
||||
{
|
||||
|
@ -213,6 +228,11 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
|||
SkipSpaces(&buffer);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat);
|
||||
}
|
||||
else if (TokenMatch(buffer,"texoff",6))
|
||||
{
|
||||
SkipSpaces(&buffer);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset);
|
||||
}
|
||||
else if (TokenMatch(buffer,"rot",3))
|
||||
{
|
||||
SkipSpaces(&buffer);
|
||||
|
@ -223,6 +243,11 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
|||
SkipSpaces(&buffer);
|
||||
AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation);
|
||||
}
|
||||
else if (TokenMatch(buffer,"subdiv",6))
|
||||
{
|
||||
SkipSpaces(&buffer);
|
||||
obj.subDiv = strtol10(buffer,&buffer);
|
||||
}
|
||||
else if (TokenMatch(buffer,"numvert",7))
|
||||
{
|
||||
SkipSpaces(&buffer);
|
||||
|
@ -352,6 +377,17 @@ void AC3DImporter::ConvertMaterial(const Object& object,
|
|||
{
|
||||
s.Set(object.texture);
|
||||
matDest.AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
|
||||
// UV transformation
|
||||
if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y ||
|
||||
object.texOffset.x || object.texOffset.y)
|
||||
{
|
||||
aiUVTransform transform;
|
||||
transform.mScaling = object.texRepeat;
|
||||
transform.mTranslation = object.texOffset;
|
||||
matDest.AddProperty<float>((float*)&transform,sizeof(aiUVTransform),
|
||||
AI_MATKEY_UVTRANSFORM_DIFFUSE(0));
|
||||
}
|
||||
}
|
||||
|
||||
matDest.AddProperty<aiColor3D>(&matSrc.rgb,1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
|
@ -377,9 +413,11 @@ void AC3DImporter::ConvertMaterial(const Object& object,
|
|||
aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
||||
std::vector<aiMesh*>& meshes,
|
||||
std::vector<MaterialHelper*>& outMaterials,
|
||||
const std::vector<Material>& materials)
|
||||
const std::vector<Material>& materials,
|
||||
aiNode* parent)
|
||||
{
|
||||
aiNode* node = new aiNode();
|
||||
node->mParent = parent;
|
||||
if (object.vertices.size())
|
||||
{
|
||||
if (!object.surfaces.size() || !object.numRefs)
|
||||
|
@ -434,7 +472,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
register unsigned int idx = (*it).mat;
|
||||
if (idx >= needMat.size())
|
||||
{
|
||||
DefaultLogger::get()->error("AC3D: material index os out of range");
|
||||
DefaultLogger::get()->error("AC3D: material index is out of range");
|
||||
idx = 0;
|
||||
}
|
||||
if ((*it).entries.empty())
|
||||
|
@ -539,13 +577,14 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
face.mIndices[i] = cur++;
|
||||
|
||||
// copy vertex positions
|
||||
*vertices = object.vertices[entry.first];
|
||||
*vertices = object.vertices[entry.first] + object.translation;
|
||||
|
||||
// copy texture coordinates (apply the UV offset)
|
||||
|
||||
// copy texture coordinates
|
||||
if (uv)
|
||||
{
|
||||
uv->x = entry.second.x * object.texRepeat.x;
|
||||
uv->y = entry.second.y * object.texRepeat.y;
|
||||
uv->x = entry.second.x;
|
||||
uv->y = entry.second.y;
|
||||
++uv;
|
||||
}
|
||||
}
|
||||
|
@ -571,11 +610,11 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
// copy vertex positions
|
||||
*vertices++ = object.vertices[(*it2).first];
|
||||
|
||||
// copy texture coordinates (apply the UV offset)
|
||||
// copy texture coordinates
|
||||
if (uv)
|
||||
{
|
||||
uv->x = (*it2).second.x * object.texRepeat.x;
|
||||
uv->y = (*it2).second.y * object.texRepeat.y;
|
||||
uv->x = (*it2).second.x;
|
||||
uv->y = (*it2).second.y;
|
||||
++uv;
|
||||
}
|
||||
|
||||
|
@ -591,18 +630,65 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
|
||||
if (uv)
|
||||
{
|
||||
uv->x = (*it2).second.x * object.texRepeat.x;
|
||||
uv->y = (*it2).second.y * object.texRepeat.y;
|
||||
uv->x = (*it2).second.x;
|
||||
uv->y = (*it2).second.y;
|
||||
++uv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
// Now apply catmull clark subdivision if necessary. However, this is
|
||||
// not *absolutely* correct: it might be we split a mesh up into
|
||||
// multiple sub meshes, one for each material. AC3D doesn't do that
|
||||
// in its subdivision implementation, so our output *could* look
|
||||
// different in some cases.
|
||||
|
||||
if (object.subDiv)
|
||||
{
|
||||
Subdivider* div = Subdivider::Create(Subdivider::CATMULL_CLARKE);
|
||||
div->Subdivide(mesh,object.subDiv);
|
||||
delete div;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (object.name.length())
|
||||
node->mName.Set(object.name);
|
||||
else
|
||||
{
|
||||
// generate a name depending on the type of the node
|
||||
switch (object.type)
|
||||
{
|
||||
case Object::Group:
|
||||
node->mName.length = ::sprintf(node->mName.data,"ACGroup_%i",groups++);
|
||||
break;
|
||||
case Object::Poly:
|
||||
node->mName.length = ::sprintf(node->mName.data,"ACPoly_%i",polys++);
|
||||
break;
|
||||
case Object::Light:
|
||||
node->mName.length = ::sprintf(node->mName.data,"ACLight_%i",lights++);
|
||||
break;
|
||||
|
||||
// there shouldn't be more than one world, but we don't care
|
||||
case Object::World:
|
||||
node->mName.length = ::sprintf(node->mName.data,"ACWorld_%i",worlds++);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// setup the local transformation matrix of the object
|
||||
// compute the transformation offset to the parent node
|
||||
node->mTransformation = aiMatrix4x4 ( object.rotation );
|
||||
|
||||
node->mTransformation.a4 = object.translation.x;
|
||||
node->mTransformation.b4 = object.translation.y;
|
||||
node->mTransformation.c4 = object.translation.z;
|
||||
|
||||
// add children to the object
|
||||
if (object.children.size())
|
||||
{
|
||||
|
@ -610,20 +696,10 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
node->mChildren = new aiNode*[node->mNumChildren];
|
||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
||||
{
|
||||
node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials);
|
||||
node->mChildren[i]->mParent = node;
|
||||
node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials,node);
|
||||
}
|
||||
}
|
||||
|
||||
node->mName.Set(object.name);
|
||||
|
||||
// setup the local transformation matrix of the object
|
||||
node->mTransformation = aiMatrix4x4 ( object.rotation );
|
||||
|
||||
node->mTransformation.a4 = object.translation.x;
|
||||
node->mTransformation.b4 = -object.translation.y;
|
||||
node->mTransformation.c4 = object.translation.z;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -653,6 +729,8 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
|
|||
buffer = &mBuffer2[0];
|
||||
mNumMeshes = 0;
|
||||
|
||||
lights = polys = worlds = groups = 0;
|
||||
|
||||
if (::strncmp(buffer,"AC3D",4))
|
||||
throw new ImportErrorException("AC3D: No valid AC3D file, magic sequence not found");
|
||||
|
||||
|
@ -731,7 +809,7 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
|
|||
if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4))
|
||||
pScene->mRootNode->mName.Set("<AC3DWorld>");
|
||||
|
||||
// build output arrays
|
||||
// copy meshes
|
||||
if (meshes.empty())
|
||||
{
|
||||
throw new ImportErrorException("An unknown error occured during converting");
|
||||
|
@ -740,11 +818,12 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
|
|||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
||||
::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*));
|
||||
|
||||
|
||||
// copy materials
|
||||
pScene->mNumMaterials = (unsigned int)omaterials.size();
|
||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
|
||||
::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*));
|
||||
|
||||
// copy lights
|
||||
pScene->mNumLights = (unsigned int)lights.size();
|
||||
if (lights.size())
|
||||
{
|
||||
|
|
|
@ -113,9 +113,20 @@ protected:
|
|||
// Represents an AC3D object
|
||||
struct Object
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
World = 0x0,
|
||||
Poly = 0x1,
|
||||
Group = 0x2,
|
||||
Light = 0x4
|
||||
} type;
|
||||
|
||||
|
||||
Object()
|
||||
: texRepeat(1.f,1.f)
|
||||
, numRefs (0)
|
||||
, subDiv (0)
|
||||
, type (World)
|
||||
{}
|
||||
|
||||
// name of the object
|
||||
|
@ -128,7 +139,7 @@ protected:
|
|||
std::string texture;
|
||||
|
||||
// texture repat factors (scaling for all coordinates)
|
||||
aiVector2D texRepeat;
|
||||
aiVector2D texRepeat, texOffset;
|
||||
|
||||
// rotation matrix
|
||||
aiMatrix3x3 rotation;
|
||||
|
@ -144,6 +155,10 @@ protected:
|
|||
|
||||
// number of indices (= num verts in verbose format)
|
||||
unsigned int numRefs;
|
||||
|
||||
// number of subdivisions to be performed on the
|
||||
// imported data
|
||||
unsigned int subDiv;
|
||||
};
|
||||
|
||||
|
||||
|
@ -208,7 +223,8 @@ private:
|
|||
aiNode* ConvertObjectSection(Object& object,
|
||||
std::vector<aiMesh*>& meshes,
|
||||
std::vector<MaterialHelper*>& outMaterials,
|
||||
const std::vector<Material>& materials);
|
||||
const std::vector<Material>& materials,
|
||||
aiNode* parent = NULL);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
@ -239,6 +255,9 @@ private:
|
|||
|
||||
// current list of light sources
|
||||
std::vector<aiLight*>* mLights;
|
||||
|
||||
// name counters
|
||||
unsigned int lights, groups, polys, worlds;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -109,14 +109,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
# include "../include/BoostWorkaround/boost/scoped_ptr.hpp"
|
||||
# include "../include/BoostWorkaround/boost/scoped_array.hpp"
|
||||
# include "../include/BoostWorkaround/boost/format.hpp"
|
||||
# include "../include/BoostWorkaround/boost/common_factor_rt.hpp"
|
||||
# include "../include/BoostWorkaround/boost/foreach.hpp"
|
||||
|
||||
#else
|
||||
|
||||
# include <boost/scoped_ptr.hpp>
|
||||
# include <boost/scoped_array.hpp>
|
||||
# include <boost/format.hpp>
|
||||
# include <boost/math/common_factor_rt.hpp>
|
||||
# include <boost/foreach.hpp>
|
||||
|
||||
#endif
|
||||
|
|
|
@ -175,6 +175,9 @@ struct BatchData
|
|||
|
||||
// List of all imports
|
||||
std::list<LoadRequest> requests;
|
||||
|
||||
// Base path
|
||||
std::string pathBase;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -202,21 +205,64 @@ BatchLoader::~BatchLoader()
|
|||
delete data;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BatchLoader::SetBasePath (const std::string& pBase)
|
||||
{
|
||||
BatchData* data = ( BatchData* )pimpl;
|
||||
data->pathBase = pBase;
|
||||
|
||||
// file name? we just need the directory
|
||||
std::string::size_type ss,ss2;
|
||||
if (std::string::npos != (ss = data->pathBase.find_first_of('.')))
|
||||
{
|
||||
if (std::string::npos != (ss2 = data->pathBase.find_last_of('\\')) ||
|
||||
std::string::npos != (ss2 = data->pathBase.find_last_of('/')))
|
||||
{
|
||||
if (ss > ss2)
|
||||
data->pathBase.erase(ss2,data->pathBase.length()-ss2);
|
||||
}
|
||||
else return;
|
||||
}
|
||||
|
||||
// make sure the directory is terminated properly
|
||||
char s;
|
||||
if ((s = *(data->pathBase.end()-1)) != '\\' && s != '/')
|
||||
data->pathBase.append("\\");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BatchLoader::AddLoadRequest (const std::string& file,
|
||||
unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/)
|
||||
{
|
||||
ai_assert(!file.empty());
|
||||
|
||||
// no threaded implementation for the moment
|
||||
BatchData* data = ( BatchData* )pimpl;
|
||||
std::list<LoadRequest>::iterator it = std::find(data->requests.begin(),
|
||||
data->requests.end(), file);
|
||||
|
||||
if (it != data->requests.end())
|
||||
std::string real;
|
||||
|
||||
// build a full path if this is a relative path and
|
||||
// we have a new base directory given
|
||||
if (file.length() > 2 && file[1] != ':' && data->pathBase.length())
|
||||
{
|
||||
(*it).refCnt++;
|
||||
return;
|
||||
real = data->pathBase + file;
|
||||
}
|
||||
data->requests.push_back(LoadRequest(file,steps,map));
|
||||
else real = file;
|
||||
|
||||
// check whether we have this loading request already
|
||||
std::list<LoadRequest>::iterator it;
|
||||
for (it = data->requests.begin();it != data->requests.end(); ++it)
|
||||
{
|
||||
// Call IOSystem's path comparison function here
|
||||
if (data->pIOSystem->ComparePaths((*it).file,real))
|
||||
{
|
||||
(*it).refCnt++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// no, we don't have it. So add it to the queue ...
|
||||
data->requests.push_back(LoadRequest(real,steps,map));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -224,16 +270,27 @@ aiScene* BatchLoader::GetImport (const std::string& file)
|
|||
{
|
||||
// no threaded implementation for the moment
|
||||
BatchData* data = ( BatchData* )pimpl;
|
||||
std::list<LoadRequest>::iterator it = std::find(data->requests.begin(),
|
||||
data->requests.end(), file);
|
||||
if (it != data->requests.end() && (*it).loaded)
|
||||
std::string real;
|
||||
|
||||
// build a full path if this is a relative path and
|
||||
// we have a new base directory given
|
||||
if (file.length() > 2 && file[1] != ':' && data->pathBase.length())
|
||||
{
|
||||
aiScene* sc = (*it).scene;
|
||||
if (!(--(*it).refCnt))
|
||||
real = data->pathBase + file;
|
||||
}
|
||||
else real = file;
|
||||
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it)
|
||||
{
|
||||
// Call IOSystem's path comparison function here
|
||||
if (data->pIOSystem->ComparePaths((*it).file,real) && (*it).loaded)
|
||||
{
|
||||
data->requests.erase(it);
|
||||
aiScene* sc = (*it).scene;
|
||||
if (!(--(*it).refCnt))
|
||||
{
|
||||
data->requests.erase(it);
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -257,9 +314,16 @@ void BatchLoader::LoadAll()
|
|||
data->pImporter->mIntProperties = (*it).map.ints;
|
||||
data->pImporter->mStringProperties = (*it).map.strings;
|
||||
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
{
|
||||
DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%");
|
||||
DefaultLogger::get()->info("File: " + (*it).file);
|
||||
}
|
||||
data->pImporter->ReadFile((*it).file,pp);
|
||||
(*it).scene = const_cast<aiScene*>(data->pImporter->GetOrphanedScene());
|
||||
(*it).loaded = true;
|
||||
|
||||
DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -275,6 +275,17 @@ public:
|
|||
~BatchLoader();
|
||||
|
||||
|
||||
/** Sets the base path to be used for all subsequent load
|
||||
* calls. This is the working directory of Assimp.
|
||||
*
|
||||
* Every (inplicit) occurence of '.\' will be replaced with it.
|
||||
*
|
||||
* @param pBase Base path. This *may* also be the path to
|
||||
* a file (the directory of the file is taken then, of course)
|
||||
*/
|
||||
void SetBasePath (const std::string& pBase);
|
||||
|
||||
|
||||
/** Add a new file to the list of files to be loaded.
|
||||
*
|
||||
* @param file File to be loaded
|
||||
|
|
|
@ -293,7 +293,7 @@ protected:
|
|||
template <typename Type>
|
||||
const Type& ColladaParser::ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const
|
||||
{
|
||||
std::map<std::string, Type>::const_iterator it = pLibrary.find( pURL);
|
||||
typename std::map<std::string, Type>::const_iterator it = pLibrary.find( pURL);
|
||||
if( it == pLibrary.end())
|
||||
ThrowException( boost::str( boost::format( "Unable to resolve library reference \"%s\".") % pURL));
|
||||
return it->second;
|
||||
|
|
|
@ -70,31 +70,305 @@ bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,aiAxis axis)
|
||||
// Compute the AABB of a mesh
|
||||
inline void FindAABB (aiMesh* mesh, aiVector3D& min, aiVector3D& max)
|
||||
{
|
||||
DefaultLogger::get()->error("Mapping type currently not implemented");
|
||||
return 0;
|
||||
min = aiVector3D (10e10f, 10e10f, 10e10f);
|
||||
max = aiVector3D (-10e10f,-10e10f,-10e10f);
|
||||
for (unsigned int i = 0;i < mesh->mNumVertices;++i)
|
||||
{
|
||||
const aiVector3D& v = mesh->mVertices[i];
|
||||
min.x = ::std::min(v.x,min.x);
|
||||
min.y = ::std::min(v.y,min.y);
|
||||
min.z = ::std::min(v.z,min.z);
|
||||
max.x = ::std::max(v.x,max.x);
|
||||
max.y = ::std::max(v.y,max.y);
|
||||
max.z = ::std::max(v.z,max.z);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,aiAxis axis)
|
||||
// Helper function to determine the 'real' center of a mesh
|
||||
inline void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max)
|
||||
{
|
||||
DefaultLogger::get()->error("Mapping type currently not implemented");
|
||||
return 0;
|
||||
FindAABB(mesh,min,max);
|
||||
out = min + (max-min)*0.5f;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,aiAxis axis)
|
||||
// Helper function to determine the 'real' center of a mesh
|
||||
inline void FindMeshCenter (aiMesh* mesh, aiVector3D& out)
|
||||
{
|
||||
DefaultLogger::get()->error("Mapping type currently not implemented");
|
||||
return 0;
|
||||
aiVector3D min,max;
|
||||
FindMeshCenter(mesh,out,min,max);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ComputeUVMappingProcess::ComputeBoxMapping(aiMesh* mesh)
|
||||
// Check whether a ray intersects a plane and find the intersection point
|
||||
inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos,
|
||||
const aiVector3D& planeNormal, aiVector3D& pos)
|
||||
{
|
||||
const float b = planeNormal * (planePos - ray.pos);
|
||||
float h = ray.dir * planeNormal;
|
||||
if (h < 10e-5f && h > -10e-5f || (h = b/h) < 0)
|
||||
return false;
|
||||
|
||||
pos = ray.pos + (ray.dir * h);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Find the first empty UV channel in a mesh
|
||||
inline unsigned int FindEmptyUVChannel (aiMesh* mesh)
|
||||
{
|
||||
for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m)
|
||||
if (!mesh->mTextureCoords[m])return m;
|
||||
|
||||
DefaultLogger::get()->error("Unable to compute UV coordinates, no free UV slot found");
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Try to remove UV seams
|
||||
void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
|
||||
{
|
||||
// TODO: just a very rough algorithm. I think it could be done
|
||||
// much easier, but I don't know how and am currently too tired to
|
||||
// to think about a better solution.
|
||||
|
||||
const static float LOWER_LIMIT = 0.1f;
|
||||
const static float UPPER_LIMIT = 0.9f;
|
||||
|
||||
const static float LOWER_EPSILON = 1e-3f;
|
||||
const static float UPPER_EPSILON = 1.f-1e-3f;
|
||||
|
||||
for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx)
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[fidx];
|
||||
if (face.mNumIndices < 3) continue; // triangles and polygons only, please
|
||||
|
||||
unsigned int small = face.mNumIndices, large = small;
|
||||
bool zero = false, one = false, round_to_zero = false;
|
||||
|
||||
// Check whether this face lies on a UV seam. We can just guess,
|
||||
// but the assumption that a face with at least one very small
|
||||
// on the one side and one very large U coord on the other side
|
||||
// lies on a UV seam should work for most cases.
|
||||
for (unsigned int n = 0; n < face.mNumIndices;++n)
|
||||
{
|
||||
if (out[face.mIndices[n]].x < LOWER_LIMIT)
|
||||
{
|
||||
small = n;
|
||||
|
||||
// If we have a U value very close to 0 we can't
|
||||
// round the others to 0, too.
|
||||
if (out[face.mIndices[n]].x <= LOWER_EPSILON)
|
||||
zero = true;
|
||||
else round_to_zero = true;
|
||||
}
|
||||
if (out[face.mIndices[n]].x > UPPER_LIMIT)
|
||||
{
|
||||
large = n;
|
||||
|
||||
// If we have a U value very close to 1 we can't
|
||||
// round the others to 1, too.
|
||||
if (out[face.mIndices[n]].x >= UPPER_EPSILON)
|
||||
one = true;
|
||||
}
|
||||
}
|
||||
if (small != face.mNumIndices && large != face.mNumIndices)
|
||||
{
|
||||
for (unsigned int n = 0; n < face.mNumIndices;++n)
|
||||
{
|
||||
// If the u value is over the upper limit and no other u
|
||||
// value of that face is 0, round it to 0
|
||||
if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero)
|
||||
out[face.mIndices[n]].x = 0.f;
|
||||
|
||||
// If the u value is below the lower limit and no other u
|
||||
// value of that face is 1, round it to 1
|
||||
else if (out[face.mIndices[n]].x < LOWER_LIMIT && !one)
|
||||
out[face.mIndices[n]].x = 1.f;
|
||||
|
||||
// The face contains both 0 and 1 as UV coords. This can occur
|
||||
// for faces which have an edge that lies directly on the seam.
|
||||
// Due to numerical inaccuracies one U coord becomes 0, the
|
||||
// other 1. But we do still have a third UV coord to determine
|
||||
// to which side we must round to.
|
||||
else if (one && zero)
|
||||
{
|
||||
if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON)
|
||||
out[face.mIndices[n]].x = 0.f;
|
||||
else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON)
|
||||
out[face.mIndices[n]].x = 1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,aiAxis axis, aiVector3D* out)
|
||||
{
|
||||
aiVector3D center;
|
||||
FindMeshCenter (mesh, center);
|
||||
|
||||
// For each point get a normalized projection vector in the sphere,
|
||||
// get its longitude and latitude and map them to their respective
|
||||
// UV axes. Problems occur around the poles ... unsolvable.
|
||||
//
|
||||
// The spherical coordinate system looks like this:
|
||||
// x = cos(lon)*cos(lat)
|
||||
// y = sin(lon)*cos(lat)
|
||||
// z = sin(lat)
|
||||
//
|
||||
// Thus we can derive:
|
||||
// lat = arcsin (z)
|
||||
// lon = arctan (y/x)
|
||||
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)
|
||||
{
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
float lat, lon;
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case aiAxis_X:
|
||||
lat = asin (diff.x);
|
||||
lon = atan2 (diff.z, diff.y);
|
||||
break;
|
||||
case aiAxis_Y:
|
||||
lat = asin (diff.y);
|
||||
lon = atan2 (diff.x, diff.z);
|
||||
break;
|
||||
case aiAxis_Z:
|
||||
lat = asin (diff.z);
|
||||
lon = atan2 (diff.y, diff.x);
|
||||
break;
|
||||
}
|
||||
out[pnt] = aiVector3D((lon + (float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI,
|
||||
(lat + (float)AI_MATH_HALF_PI) / (float)AI_MATH_PI, 0.f);
|
||||
}
|
||||
|
||||
// Now find and remove UV seams. A seam occurs if a face has a tcoord
|
||||
// close to zero on the one side, and a tcoord close to one on the
|
||||
// other side.
|
||||
RemoveUVSeams(mesh,out);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,aiAxis axis, aiVector3D* out)
|
||||
{
|
||||
aiVector3D center, min, max;
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
|
||||
ai_assert(0 == aiAxis_X);
|
||||
const float diff = max[axis] - min[axis];
|
||||
if (!diff)
|
||||
{
|
||||
DefaultLogger::get()->error("Can't compute cylindrical mapping, the mesh is "
|
||||
"flat in the requested axis");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If the main axis is 'z', the z coordinate of a point 'p' is mapped
|
||||
// directly to the texture V axis. The other axis is derived from
|
||||
// the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where
|
||||
// 'c' is the center point of the mesh.
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)
|
||||
{
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case aiAxis_X:
|
||||
uv.y = (pos.x - min.x) / diff;
|
||||
uv.x = atan2 ( pos.z - center.z, pos.y - center.y);
|
||||
break;
|
||||
case aiAxis_Y:
|
||||
uv.y = (pos.y - min.y) / diff;
|
||||
uv.x = atan2 ( pos.x - center.x, pos.z - center.z);
|
||||
break;
|
||||
case aiAxis_Z:
|
||||
uv.y = (pos.z - min.z) / diff;
|
||||
uv.x = atan2 ( pos.y - center.y, pos.x - center.x);
|
||||
break;
|
||||
}
|
||||
uv.x = (uv.x +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
||||
uv.z = 0.f;
|
||||
}
|
||||
|
||||
// Now find and remove UV seams. A seam occurs if a face has a tcoord
|
||||
// close to zero on the one side, and a tcoord close to one on the
|
||||
// other side.
|
||||
RemoveUVSeams(mesh,out);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,aiAxis axis, aiVector3D* out)
|
||||
{
|
||||
aiVector3D center, min, max;
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
|
||||
float diffu,diffv;
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case aiAxis_X:
|
||||
diffu = max.z - min.z;
|
||||
diffv = max.y - min.y;
|
||||
break;
|
||||
case aiAxis_Y:
|
||||
diffu = max.x - min.x;
|
||||
diffv = max.z - min.z;
|
||||
break;
|
||||
case aiAxis_Z:
|
||||
diffu = max.y - min.y;
|
||||
diffv = max.z - min.z;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!diffu || !diffv)
|
||||
{
|
||||
DefaultLogger::get()->error("Can't compute plane mapping, the mesh is "
|
||||
"flat in the requested axis");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// That's rather simple. We just project the vertices onto a plane
|
||||
// that lies on the two coordinate aces orthogonal to the main axis
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt)
|
||||
{
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case aiAxis_X:
|
||||
uv.x = (pos.z - min.z) / diffu;
|
||||
uv.y = (pos.y - min.y) / diffv;
|
||||
break;
|
||||
case aiAxis_Y:
|
||||
uv.x = (pos.x - min.x) / diffu;
|
||||
uv.y = (pos.z - min.z) / diffv;
|
||||
break;
|
||||
case aiAxis_Z:
|
||||
uv.x = (pos.y - min.y) / diffu;
|
||||
uv.y = (pos.x - min.x) / diffv;
|
||||
break;
|
||||
}
|
||||
uv.z = 0.f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputeBoxMapping(aiMesh* mesh, aiVector3D* out)
|
||||
{
|
||||
DefaultLogger::get()->error("Mapping type currently not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -103,17 +377,23 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
|
|||
DefaultLogger::get()->debug("GenUVCoordsProcess begin");
|
||||
char buffer[1024];
|
||||
|
||||
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT)
|
||||
throw new ImportErrorException("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
|
||||
|
||||
std::list<MappingInfo> mappingStack;
|
||||
|
||||
/* Iterate through all materials and search for non-UV mapped textures
|
||||
*/
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
||||
{
|
||||
mappingStack.clear();
|
||||
aiMaterial* mat = pScene->mMaterials[i];
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a)
|
||||
{
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
if (!::strcmp( prop->mKey.data, "$tex.mapping"))
|
||||
{
|
||||
aiTextureMapping mapping = *((aiTextureMapping*)prop->mData);
|
||||
aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData);
|
||||
if (aiTextureMapping_UV != mapping)
|
||||
{
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
|
@ -125,7 +405,10 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
|
|||
DefaultLogger::get()->info(buffer);
|
||||
}
|
||||
|
||||
aiAxis axis;
|
||||
if (aiTextureMapping_OTHER == mapping)
|
||||
continue;
|
||||
|
||||
MappingInfo info (mapping);
|
||||
|
||||
// Get further properties - currently only the major axis
|
||||
for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2)
|
||||
|
@ -136,40 +419,73 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
|
|||
|
||||
if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis"))
|
||||
{
|
||||
axis = *((aiAxis*)prop2->mData);
|
||||
info.axis = *((aiAxis*)prop2->mData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have found a non-UV mapped texture. Now
|
||||
* we need to find all meshes using this material
|
||||
* that we can compute UV channels for them.
|
||||
*/
|
||||
for (unsigned int m = 0; m < pScene->mNumMeshes;++m)
|
||||
unsigned int idx;
|
||||
|
||||
// Check whether we have this mapping mode already
|
||||
std::list<MappingInfo>::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info);
|
||||
if (mappingStack.end() != it)
|
||||
{
|
||||
aiMesh* mesh = pScene->mMeshes[m];
|
||||
if (mesh->mMaterialIndex != i) continue;
|
||||
|
||||
switch (mapping)
|
||||
{
|
||||
case aiTextureMapping_SPHERE:
|
||||
ComputeSphereMapping(mesh,axis);
|
||||
break;
|
||||
case aiTextureMapping_CYLINDER:
|
||||
ComputeCylinderMapping(mesh,axis);
|
||||
break;
|
||||
case aiTextureMapping_PLANE:
|
||||
ComputePlaneMapping(mesh,axis);
|
||||
break;
|
||||
case aiTextureMapping_BOX:
|
||||
ComputeBoxMapping(mesh);
|
||||
break;
|
||||
}
|
||||
idx = (*it).uv;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have found a non-UV mapped texture. Now
|
||||
* we need to find all meshes using this material
|
||||
* that we can compute UV channels for them.
|
||||
*/
|
||||
for (unsigned int m = 0; m < pScene->mNumMeshes;++m)
|
||||
{
|
||||
aiMesh* mesh = pScene->mMeshes[m];
|
||||
unsigned int outIdx;
|
||||
if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == 0xffffffff ||
|
||||
!mesh->mNumVertices)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allocate output storage
|
||||
aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
|
||||
|
||||
switch (mapping)
|
||||
{
|
||||
case aiTextureMapping_SPHERE:
|
||||
ComputeSphereMapping(mesh,info.axis,p);
|
||||
break;
|
||||
case aiTextureMapping_CYLINDER:
|
||||
ComputeCylinderMapping(mesh,info.axis,p);
|
||||
break;
|
||||
case aiTextureMapping_PLANE:
|
||||
ComputePlaneMapping(mesh,info.axis,p);
|
||||
break;
|
||||
case aiTextureMapping_BOX:
|
||||
ComputeBoxMapping(mesh,p);
|
||||
break;
|
||||
default:
|
||||
ai_assert(false);
|
||||
}
|
||||
if (m && idx != outIdx)
|
||||
{
|
||||
DefaultLogger::get()->warn("UV index mismatch. Not all meshes assigned to "
|
||||
"this material have equal numbers of UV channels. The UV index stored in "
|
||||
"the material structure does therefore not apply for all meshes. ");
|
||||
}
|
||||
idx = outIdx;
|
||||
}
|
||||
info.uv = idx;
|
||||
mappingStack.push_back(info);
|
||||
}
|
||||
|
||||
// Update the material property list
|
||||
mapping = aiTextureMapping_UV;
|
||||
((MaterialHelper*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DefaultLogger::get()->debug("GenUVCoordsProcess finished");
|
||||
}
|
||||
|
|
|
@ -89,35 +89,59 @@ protected:
|
|||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param axis Main axis
|
||||
* @return Index of the newly generated UV channel
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
unsigned int ComputeSphereMapping(aiMesh* mesh,aiAxis axis);
|
||||
void ComputeSphereMapping(aiMesh* mesh,aiAxis axis,
|
||||
aiVector3D* out);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes cylindrical UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param axis Main axis
|
||||
* @return Index of the newly generated UV channel
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
unsigned int ComputeCylinderMapping(aiMesh* mesh,aiAxis axis);
|
||||
void ComputeCylinderMapping(aiMesh* mesh,aiAxis axis,
|
||||
aiVector3D* out);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes planar UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param axis Main axis
|
||||
* @return Index of the newly generated UV channel
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
unsigned int ComputePlaneMapping(aiMesh* mesh,aiAxis axis);
|
||||
void ComputePlaneMapping(aiMesh* mesh,aiAxis axis,
|
||||
aiVector3D* out);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes cubic UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @return Index of the newly generated UV channel
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
unsigned int ComputeBoxMapping(aiMesh* mesh);
|
||||
void ComputeBoxMapping(aiMesh* mesh, aiVector3D* out);
|
||||
|
||||
private:
|
||||
|
||||
// temporary structure to describe a mapping
|
||||
struct MappingInfo
|
||||
{
|
||||
MappingInfo(aiTextureMapping _type)
|
||||
: type (_type)
|
||||
, axis (aiAxis_X)
|
||||
, uv (0u)
|
||||
{}
|
||||
|
||||
aiTextureMapping type;
|
||||
aiAxis axis;
|
||||
unsigned int uv;
|
||||
|
||||
bool operator== (const MappingInfo& other)
|
||||
{
|
||||
return type == other.type && axis == other.axis;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor.
|
||||
DefaultIOSystem::DefaultIOSystem()
|
||||
|
@ -103,3 +104,42 @@ std::string DefaultIOSystem::getOsSeparator() const
|
|||
#endif
|
||||
return sep;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// IOSystem default implementation (ComparePaths isn't a pure virtual function)
|
||||
bool IOSystem::ComparePaths (const std::string& one,
|
||||
const std::string& second)
|
||||
{
|
||||
return !ASSIMP_stricmp(one,second);
|
||||
}
|
||||
|
||||
// this should be sufficient for all platforms :D
|
||||
#define PATHLIMIT 1024
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a relative path into an absolute path
|
||||
inline void MakeAbsolutePath (const std::string& in, char* _out)
|
||||
{
|
||||
::_fullpath(_out, in.c_str(),PATHLIMIT);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// DefaultIOSystem's more specialized implementation
|
||||
bool DefaultIOSystem::ComparePaths (const std::string& one,
|
||||
const std::string& second)
|
||||
{
|
||||
// chances are quite good both paths are formatted identically,
|
||||
// so we can hopefully return here already
|
||||
if( !ASSIMP_stricmp(one,second) )
|
||||
return true;
|
||||
|
||||
char temp1[PATHLIMIT];
|
||||
char temp2[PATHLIMIT];
|
||||
|
||||
MakeAbsolutePath (one, temp1);
|
||||
MakeAbsolutePath (second, temp2);
|
||||
|
||||
return !ASSIMP_stricmp(temp1,temp2);
|
||||
}
|
||||
|
||||
#undef PATHLIMIT
|
||||
|
|
|
@ -73,6 +73,10 @@ public:
|
|||
// -------------------------------------------------------------------
|
||||
/** Closes the given file and releases all resources associated with it. */
|
||||
void Close( IOStream* pFile);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Compare two paths */
|
||||
bool ComparePaths (const std::string& one, const std::string& second);
|
||||
};
|
||||
|
||||
} //!ns Assimp
|
||||
|
|
|
@ -76,6 +76,9 @@ void GenFaceNormalsProcess::Execute( aiScene* pScene)
|
|||
{
|
||||
DefaultLogger::get()->debug("GenFaceNormalsProcess begin");
|
||||
|
||||
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT)
|
||||
throw new ImportErrorException("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
|
||||
|
||||
bool bHas = false;
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
||||
{
|
||||
|
|
|
@ -88,6 +88,9 @@ void GenVertexNormalsProcess::Execute( aiScene* pScene)
|
|||
{
|
||||
DefaultLogger::get()->debug("GenVertexNormalsProcess begin");
|
||||
|
||||
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT)
|
||||
throw new ImportErrorException("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
|
||||
|
||||
bool bHas = false;
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
||||
{
|
||||
|
|
|
@ -51,8 +51,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "SceneCombiner.h"
|
||||
#include "StandardShapes.h"
|
||||
|
||||
|
||||
// We need boost::common_factor to compute the lcm/gcd of a number
|
||||
#ifdef ASSIMP_BUILD_BOOST_WORKAROUND
|
||||
# include "../include/BoostWorkaround/boost/common_factor_rt.hpp"
|
||||
#else
|
||||
# include <boost/math/common_factor_rt.hpp>
|
||||
#endif
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// Transformation matrix to convert from Assimp to IRR space
|
||||
static aiMatrix4x4 AI_TO_IRR_MATRIX = aiMatrix4x4 ( 1.0f, 0.0f, 0.0f,
|
||||
0.f, 0.0f, 0.0f, -1.0f, 0.f, 0.0f, 1.0f, 0.0f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
|
@ -163,7 +174,7 @@ aiMesh* IRRImporter::BuildSingleQuadMesh(const SkyboxVertex& v1,
|
|||
*vec = v4.normal;
|
||||
|
||||
// copy texture coordinates
|
||||
out->mTextureCoords[0] = new aiVector3D[4];
|
||||
vec = out->mTextureCoords[0] = new aiVector3D[4];
|
||||
*vec++ = v1.uv;
|
||||
*vec++ = v2.uv;
|
||||
*vec++ = v3.uv;
|
||||
|
@ -240,12 +251,12 @@ void IRRImporter::BuildSkybox(std::vector<aiMesh*>& meshes, std::vector<aiMateri
|
|||
SkyboxVertex( l,-l, l, 0, 1, 0, 0.f,0.f),
|
||||
SkyboxVertex( l,-l,-l, 0, 1, 0, 1.f,0.f),
|
||||
SkyboxVertex(-l,-l,-l, 0, 1, 0, 1.f,1.f),
|
||||
SkyboxVertex(-l,-l,-l, 0, 1, 0, 0.f,1.f)) );
|
||||
SkyboxVertex(-l,-l, l, 0, 1, 0, 0.f,1.f)) );
|
||||
meshes.back()->mMaterialIndex = materials.size()-1u;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IRRImporter::CopyMaterial(std::vector<aiMaterial*> materials,
|
||||
void IRRImporter::CopyMaterial(std::vector<aiMaterial*>& materials,
|
||||
std::vector< std::pair<aiMaterial*, unsigned int> >& inmaterials,
|
||||
unsigned int& defMatIdx,
|
||||
aiMesh* mesh)
|
||||
|
@ -297,44 +308,71 @@ inline void FindSuitableMultiple(int& angle)
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void IRRImporter::ComputeAnimations(Node* root, std::vector<aiNodeAnim*>& anims,
|
||||
const aiMatrix4x4& transform)
|
||||
void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNodeAnim*>& anims)
|
||||
{
|
||||
ai_assert(NULL != root);
|
||||
ai_assert(NULL != root && NULL != real);
|
||||
|
||||
if (root->animators.empty())return;
|
||||
const aiMatrix4x4& transform = real->mTransformation;
|
||||
|
||||
typedef std::pair< TemporaryAnim, Animator* > AnimPair;
|
||||
const unsigned int resolution = 1;
|
||||
|
||||
std::vector<AnimPair> temp;
|
||||
temp.reserve(root->animators.size());
|
||||
|
||||
unsigned int total = 0;
|
||||
for (std::list<Animator>::iterator it = root->animators.begin();
|
||||
it != root->animators.end(); ++it)
|
||||
{
|
||||
if ((*it).type == Animator::UNKNOWN ||
|
||||
(*it).type == Animator::OTHER)
|
||||
if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER)
|
||||
{
|
||||
DefaultLogger::get()->warn("IRR: Skipping unknown or unsupported animator");
|
||||
continue;
|
||||
}
|
||||
temp.push_back(AnimPair(TemporaryAnim(),&(*it)));
|
||||
++total;
|
||||
}
|
||||
if (!total)return;
|
||||
else if (1 == total)
|
||||
{
|
||||
DefaultLogger::get()->warn("IRR: Generating dummy nodes to simulate multiple animators");
|
||||
}
|
||||
|
||||
if (temp.empty())return;
|
||||
// NOTE: 1 tick == i millisecond
|
||||
|
||||
// All animators are applied one after another. We generate a set of
|
||||
// transformation matrices for each of it. Then we combine all
|
||||
// transformation matrices, decompose them and build an output animation.
|
||||
|
||||
for (std::vector<AnimPair>::iterator it = temp.begin();
|
||||
it != temp.end(); ++it)
|
||||
unsigned int cur = 0;
|
||||
for (std::list<Animator>::iterator it = root->animators.begin();
|
||||
it != root->animators.end(); ++it)
|
||||
{
|
||||
TemporaryAnim& out = (*it).first;
|
||||
Animator* in = (*it).second;
|
||||
if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER)continue;
|
||||
|
||||
switch (in->type)
|
||||
Animator& in = *it ;
|
||||
aiNodeAnim* anim = new aiNodeAnim();
|
||||
|
||||
if (cur != total-1)
|
||||
{
|
||||
// Build a new name - a prefix instead of a suffix because it is
|
||||
// easier to check against
|
||||
anim->mNodeName.length = ::sprintf(anim->mNodeName.data,
|
||||
"$INST_DUMMY_%i_%s",total-1,
|
||||
(root->name.length() ? root->name.c_str() : ""));
|
||||
|
||||
// we'll also need to insert a dummy in the node hierarchy.
|
||||
aiNode* dummy = new aiNode();
|
||||
|
||||
for (unsigned int i = 0; i < real->mParent->mNumChildren;++i)
|
||||
if (real->mParent->mChildren[i] == real)
|
||||
real->mParent->mChildren[i] = dummy;
|
||||
|
||||
dummy->mParent = real->mParent;
|
||||
dummy->mName = anim->mNodeName;
|
||||
|
||||
dummy->mNumChildren = 1;
|
||||
dummy->mChildren = new aiNode*[dummy->mNumChildren];
|
||||
dummy->mChildren[0] = real;
|
||||
|
||||
// the transformation matrix of the dummy node is the identity
|
||||
|
||||
real->mParent = dummy;
|
||||
}
|
||||
else anim->mNodeName.Set(root->name);
|
||||
++cur;
|
||||
|
||||
switch (in.type)
|
||||
{
|
||||
case Animator::ROTATION:
|
||||
{
|
||||
|
@ -347,17 +385,20 @@ void IRRImporter::ComputeAnimations(Node* root, std::vector<aiNodeAnim*>& anims,
|
|||
// here in order to get good results.
|
||||
// -----------------------------------------------------
|
||||
int angles[3];
|
||||
angles[0] = (int)(in->direction.x*100);
|
||||
angles[1] = (int)(in->direction.y*100);
|
||||
angles[2] = (int)(in->direction.z*100);
|
||||
angles[0] = (int)(in.direction.x*100);
|
||||
angles[1] = (int)(in.direction.y*100);
|
||||
angles[2] = (int)(in.direction.z*100);
|
||||
|
||||
angles[0] %= 360;
|
||||
angles[1] %= 360;
|
||||
angles[2] %= 360;
|
||||
|
||||
FindSuitableMultiple(angles[0]);
|
||||
FindSuitableMultiple(angles[1]);
|
||||
FindSuitableMultiple(angles[2]);
|
||||
if ((angles[0]*angles[1]) && (angles[1]*angles[2]))
|
||||
{
|
||||
FindSuitableMultiple(angles[0]);
|
||||
FindSuitableMultiple(angles[1]);
|
||||
FindSuitableMultiple(angles[2]);
|
||||
}
|
||||
|
||||
int lcm = 360;
|
||||
|
||||
|
@ -390,87 +431,136 @@ void IRRImporter::ComputeAnimations(Node* root, std::vector<aiNodeAnim*>& anims,
|
|||
max = std::max(max, (float)lcm / angles[2]);
|
||||
|
||||
|
||||
// Allocate transformation matrices
|
||||
out.SetupMatrices((unsigned int)(max*fps));
|
||||
anim->mNumRotationKeys = (unsigned int)(max*fps);
|
||||
anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
|
||||
|
||||
|
||||
// begin with a zero angle
|
||||
aiVector3D angle;
|
||||
for (unsigned int i = 0; i < out.last;++i)
|
||||
for (unsigned int i = 0; i < anim->mNumRotationKeys;++i)
|
||||
{
|
||||
// build the rotation matrix for the given euler angles
|
||||
aiMatrix4x4& m = out.matrices[i];
|
||||
// build the quaternion for the given euler angles
|
||||
aiQuatKey& q = anim->mRotationKeys[i];
|
||||
|
||||
// we start with the node transformation
|
||||
m = transform;
|
||||
|
||||
aiMatrix4x4 m2;
|
||||
|
||||
if (angle.x)
|
||||
m *= aiMatrix4x4::RotationX(angle.x,m2);
|
||||
|
||||
if (angle.y)
|
||||
m *= aiMatrix4x4::RotationX(angle.y,m2);
|
||||
|
||||
if (angle.z)
|
||||
m *= aiMatrix4x4::RotationZ(angle.z,m2);
|
||||
q.mValue = aiQuaternion(angle.x, angle.y, angle.z);
|
||||
q.mTime = (double)i;
|
||||
|
||||
// increase the angle
|
||||
angle += in->direction;
|
||||
angle += in.direction;
|
||||
}
|
||||
|
||||
// This animation is repeated and repeated ...
|
||||
out.post = aiAnimBehaviour_REPEAT;
|
||||
anim->mPostState = aiAnimBehaviour_REPEAT;
|
||||
anim->mPreState = aiAnimBehaviour_CONSTANT;
|
||||
}
|
||||
break;
|
||||
|
||||
case Animator::FLY_CIRCLE:
|
||||
{
|
||||
|
||||
anim->mPostState = aiAnimBehaviour_REPEAT;
|
||||
anim->mPreState = aiAnimBehaviour_CONSTANT;
|
||||
|
||||
// -----------------------------------------------------
|
||||
// Find out how much time we'll need to perform a
|
||||
// full circle.
|
||||
// -----------------------------------------------------
|
||||
const double seconds = (1. / in.speed) / 1000.;
|
||||
const double tdelta = 1000. / fps;
|
||||
|
||||
anim->mNumPositionKeys = (unsigned int) (fps * seconds);
|
||||
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
|
||||
|
||||
// from Irrlicht, what else should we do than copying it?
|
||||
aiVector3D vecU,vecV;
|
||||
if (in.direction.y)
|
||||
{
|
||||
vecV = aiVector3D(50,0,0) ^ in.direction;
|
||||
}
|
||||
else vecV = aiVector3D(0,50,00) ^ in.direction;
|
||||
vecV.Normalize();
|
||||
vecU = (vecV ^ in.direction).Normalize();
|
||||
|
||||
// build the output keys
|
||||
for (unsigned int i = 0; i < anim->mNumPositionKeys;++i)
|
||||
{
|
||||
aiVectorKey& key = anim->mPositionKeys[i];
|
||||
key.mTime = i * tdelta;
|
||||
|
||||
const float t = (float) ( in.speed * key.mTime );
|
||||
key.mValue = in.circleCenter + in.circleRadius * ((vecU*::cos(t)) + (vecV*::sin(t)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Animator::FLY_STRAIGHT:
|
||||
{
|
||||
|
||||
anim->mPostState = (in.loop ? aiAnimBehaviour_REPEAT : aiAnimBehaviour_CONSTANT);
|
||||
anim->mPreState = aiAnimBehaviour_CONSTANT;
|
||||
|
||||
const double seconds = in.timeForWay / 1000.;
|
||||
const double tdelta = 1000. / fps;
|
||||
|
||||
anim->mNumPositionKeys = (unsigned int) (fps * seconds);
|
||||
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
|
||||
|
||||
aiVector3D diff = in.direction - in.circleCenter;
|
||||
const float lengthOfWay = diff.Length();
|
||||
diff.Normalize();
|
||||
|
||||
const double timeFactor = lengthOfWay / in.timeForWay;
|
||||
|
||||
// build the output keys
|
||||
for (unsigned int i = 0; i < anim->mNumPositionKeys;++i)
|
||||
{
|
||||
aiVectorKey& key = anim->mPositionKeys[i];
|
||||
key.mTime = i * tdelta;
|
||||
key.mValue = in.circleCenter + diff * float(timeFactor * key.mTime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Animator::FOLLOW_SPLINE:
|
||||
{
|
||||
out.post = aiAnimBehaviour_REPEAT;
|
||||
const int size = (int)in->splineKeys.size();
|
||||
anim->mPostState = aiAnimBehaviour_REPEAT;
|
||||
anim->mPreState = aiAnimBehaviour_CONSTANT;
|
||||
|
||||
const int size = (int)in.splineKeys.size();
|
||||
if (!size)
|
||||
{
|
||||
// We have no point in the spline. That's bad. Really bad.
|
||||
DefaultLogger::get()->warn("IRR: Spline animators with no points defined");
|
||||
|
||||
delete anim;anim = NULL;
|
||||
break;
|
||||
}
|
||||
else if (size == 1)
|
||||
{
|
||||
// We have just one point in the spline
|
||||
out.SetupMatrices(1);
|
||||
out.matrices[0].a4 = in->splineKeys[0].mValue.x;
|
||||
out.matrices[0].b4 = in->splineKeys[0].mValue.y;
|
||||
out.matrices[0].c4 = in->splineKeys[0].mValue.z;
|
||||
// We have just one point in the spline so we don't need the full calculation
|
||||
anim->mNumPositionKeys = 1;
|
||||
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
|
||||
|
||||
anim->mPositionKeys[0].mValue = in.splineKeys[0].mValue;
|
||||
anim->mPositionKeys[0].mTime = 0.f;
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned int ticksPerFull = 15;
|
||||
out.SetupMatrices(ticksPerFull*fps);
|
||||
anim->mNumPositionKeys = (unsigned int) ( ticksPerFull * fps );
|
||||
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
|
||||
|
||||
for (unsigned int i = 0; i < out.last;++i)
|
||||
for (unsigned int i = 0; i < anim->mNumPositionKeys;++i)
|
||||
{
|
||||
aiMatrix4x4& m = out.matrices[i];
|
||||
aiVectorKey& key = anim->mPositionKeys[i];
|
||||
|
||||
const float dt = (i * in->speed * 0.001f );
|
||||
const float dt = (i * in.speed * 0.001f );
|
||||
const float u = dt - floor(dt);
|
||||
const int idx = (int)floor(dt) % size;
|
||||
|
||||
// get the 4 current points to evaluate the spline
|
||||
const aiVector3D& p0 = in->splineKeys[ ClampSpline( idx - 1, size ) ].mValue;
|
||||
const aiVector3D& p1 = in->splineKeys[ ClampSpline( idx + 0, size ) ].mValue;
|
||||
const aiVector3D& p2 = in->splineKeys[ ClampSpline( idx + 1, size ) ].mValue;
|
||||
const aiVector3D& p3 = in->splineKeys[ ClampSpline( idx + 2, size ) ].mValue;
|
||||
const aiVector3D& p0 = in.splineKeys[ ClampSpline( idx - 1, size ) ].mValue;
|
||||
const aiVector3D& p1 = in.splineKeys[ ClampSpline( idx + 0, size ) ].mValue;
|
||||
const aiVector3D& p2 = in.splineKeys[ ClampSpline( idx + 1, size ) ].mValue;
|
||||
const aiVector3D& p3 = in.splineKeys[ ClampSpline( idx + 2, size ) ].mValue;
|
||||
|
||||
// compute polynomials
|
||||
const float u2 = u*u;
|
||||
|
@ -482,54 +572,90 @@ void IRRImporter::ComputeAnimations(Node* root, std::vector<aiNodeAnim*>& anims,
|
|||
const float h4 = u3 - u2;
|
||||
|
||||
// compute the spline tangents
|
||||
const aiVector3D t1 = ( p2 - p0 ) * in->tightness;
|
||||
aiVector3D t2 = ( p3 - p1 ) * in->tightness;
|
||||
const aiVector3D t1 = ( p2 - p0 ) * in.tightness;
|
||||
aiVector3D t2 = ( p3 - p1 ) * in.tightness;
|
||||
|
||||
// and use them to get the interpolated point
|
||||
t2 = (h1 * p1 + p2 * h2 + t1 * h3 + h4 * t2);
|
||||
|
||||
// build a simple translation matrix from it
|
||||
m.a4 = t2.x;
|
||||
m.b4 = t2.y;
|
||||
m.c4 = t2.z;
|
||||
key.mValue = t2.x;
|
||||
key.mTime = (double) i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
aiNodeAnim* out = new aiNodeAnim();
|
||||
out->mNodeName.Set(root->name);
|
||||
|
||||
if (temp.size() == 1)
|
||||
{
|
||||
// If there's just one animator to be processed our
|
||||
// task is quite easy
|
||||
TemporaryAnim& one = temp[0].first;
|
||||
|
||||
out->mPostState = one.post;
|
||||
out->mNumPositionKeys = one.last;
|
||||
out->mNumScalingKeys = one.last;
|
||||
out->mNumRotationKeys = one.last;
|
||||
|
||||
out->mPositionKeys = new aiVectorKey[one.last];
|
||||
out->mScalingKeys = new aiVectorKey[one.last];
|
||||
out->mRotationKeys = new aiQuatKey[one.last];
|
||||
|
||||
for (unsigned int i = 0; i < one.last;++i)
|
||||
if (anim)
|
||||
{
|
||||
aiVectorKey& scaling = out->mScalingKeys[i];
|
||||
aiVectorKey& position = out->mPositionKeys[i];
|
||||
aiQuatKey& rotation = out->mRotationKeys[i];
|
||||
|
||||
scaling.mTime = position.mTime = rotation.mTime = (double)i;
|
||||
one.matrices[i].Decompose(scaling.mValue, rotation.mValue, position.mValue);
|
||||
anims.push_back(anim);
|
||||
++total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: It is possible that some of the tracks we're returning
|
||||
// are dummy tracks, but the ScenePreprocessor will fix that, hopefully
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// This function is maybe more generic than we'd need it here
|
||||
void SetupMapping (MaterialHelper* mat, aiTextureMapping mode, aiAxis axis = aiAxis_Y)
|
||||
{
|
||||
// Check whether there are texture properties defined - setup
|
||||
// the desired texture mapping mode for all of them and ignore
|
||||
// all UV settings we might encounter. WE HAVE NO UVS!
|
||||
|
||||
std::vector<aiMaterialProperty*> p;
|
||||
p.reserve(mat->mNumProperties+1);
|
||||
|
||||
for (unsigned int i = 0; i < mat->mNumProperties;++i)
|
||||
{
|
||||
aiMaterialProperty* prop = mat->mProperties[i];
|
||||
if (!::strcmp( prop->mKey.data, "$tex.file"))
|
||||
{
|
||||
// Setup the mapping key
|
||||
aiMaterialProperty* m = new aiMaterialProperty();
|
||||
m->mKey.Set("$tex.mapping");
|
||||
m->mIndex = prop->mIndex;
|
||||
m->mSemantic = prop->mSemantic;
|
||||
m->mType = aiPTI_Integer;
|
||||
|
||||
m->mDataLength = 4;
|
||||
m->mData = new char[4];
|
||||
*((int*)m->mData) = mode;
|
||||
|
||||
p.push_back(prop);
|
||||
p.push_back(m);
|
||||
|
||||
// Setup the mapping axis
|
||||
if (mode == aiTextureMapping_CYLINDER || mode == aiTextureMapping_PLANE ||
|
||||
mode == aiTextureMapping_SPHERE)
|
||||
{
|
||||
m = new aiMaterialProperty();
|
||||
m->mKey.Set("$tex.mapaxis");
|
||||
m->mIndex = prop->mIndex;
|
||||
m->mSemantic = prop->mSemantic;
|
||||
m->mType = aiPTI_Integer;
|
||||
|
||||
m->mDataLength = 4;
|
||||
m->mData = new char[4];
|
||||
*((int*)m->mData) = axis;
|
||||
p.push_back(m);
|
||||
}
|
||||
}
|
||||
else if (! ::strcmp( prop->mKey.data, "$tex.uvwsrc"))
|
||||
{
|
||||
delete mat->mProperties[i];
|
||||
}
|
||||
else p.push_back(prop);
|
||||
}
|
||||
|
||||
if (p.empty())return;
|
||||
|
||||
// rebuild the output array
|
||||
if (p.size() > mat->mNumAllocated)
|
||||
{
|
||||
delete[] mat->mProperties;
|
||||
mat->mProperties = new aiMaterialProperty*[p.size()];
|
||||
}
|
||||
mat->mNumProperties = (unsigned int)p.size();
|
||||
::memcpy(mat->mProperties,&p[0],sizeof(void*)*mat->mNumProperties);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -538,10 +664,11 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
std::vector<aiMesh*>& meshes,
|
||||
std::vector<aiNodeAnim*>& anims,
|
||||
std::vector<AttachmentInfo>& attach,
|
||||
std::vector<aiMaterial*> materials,
|
||||
std::vector<aiMaterial*>& materials,
|
||||
unsigned int& defMatIdx)
|
||||
{
|
||||
unsigned int oldMeshSize = (unsigned int)meshes.size();
|
||||
unsigned int meshTrafoAssign = 0;
|
||||
|
||||
// Now determine the type of the node
|
||||
switch (root->type)
|
||||
|
@ -549,7 +676,10 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
case Node::ANIMMESH:
|
||||
case Node::MESH:
|
||||
{
|
||||
// get the loaded mesh from the scene and add it to
|
||||
if (!root->meshPath.length())
|
||||
break;
|
||||
|
||||
// Get the loaded mesh from the scene and add it to
|
||||
// the list of all scenes to be attached to the
|
||||
// graph we're currently building
|
||||
aiScene* scene = batch.GetImport(root->meshPath);
|
||||
|
@ -560,9 +690,45 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
break;
|
||||
}
|
||||
attach.push_back(AttachmentInfo(scene,rootOut));
|
||||
meshTrafoAssign = 1;
|
||||
|
||||
// now combine the material we've loaded for this mesh
|
||||
// with the real meshes we got from the file. As we
|
||||
// If the root node of the scene is animated - and *this* node
|
||||
// is animated, too, we need to insert a dummy node into the
|
||||
// hierarchy in order to avoid interferences with animations
|
||||
for (unsigned int i = 0; i < scene->mNumAnimations;++i)
|
||||
{
|
||||
aiAnimation* anim = scene->mAnimations[i];
|
||||
for (unsigned int a = 0; a < anim->mNumChannels;++a)
|
||||
{
|
||||
if (scene->mRootNode->mName == anim->mChannels[a]->mNodeName)
|
||||
{
|
||||
if (root->animators.empty())
|
||||
{
|
||||
meshTrafoAssign = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
meshTrafoAssign = 3;
|
||||
aiNode* dummy = new aiNode();
|
||||
dummy->mName.Set("$CSpaceSeam$");
|
||||
dummy->mNumChildren = 1;
|
||||
dummy->mChildren = new aiNode*[1];
|
||||
dummy->mChildren[0] = scene->mRootNode;
|
||||
|
||||
scene->mRootNode->mParent = dummy;
|
||||
scene->mRootNode = dummy;
|
||||
scene->mRootNode->mTransformation = AI_TO_IRR_MATRIX;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (1 == meshTrafoAssign)
|
||||
scene->mRootNode->mTransformation *= AI_TO_IRR_MATRIX;
|
||||
|
||||
|
||||
// Now combine the material we've loaded for this mesh
|
||||
// with the real materials we got from the file. As we
|
||||
// don't execute any pp-steps on the file, the numbers
|
||||
// should be equal. If they are not, we can impossibly
|
||||
// do this ...
|
||||
|
@ -575,7 +741,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
}
|
||||
for (unsigned int i = 0; i < scene->mNumMaterials;++i)
|
||||
{
|
||||
// delete the old material
|
||||
// Delete the old material, we don't need it anymore
|
||||
delete scene->mMaterials[i];
|
||||
|
||||
std::pair<aiMaterial*, unsigned int>& src = root->materials[i];
|
||||
|
@ -599,8 +765,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
mesh->mMaterialIndex];
|
||||
|
||||
MaterialHelper* mat = (MaterialHelper*)src.first;
|
||||
if (mesh->HasVertexColors(0) &&
|
||||
src.second & AI_IRRMESH_MAT_trans_vertex_alpha)
|
||||
if (mesh->HasVertexColors(0) && src.second & AI_IRRMESH_MAT_trans_vertex_alpha)
|
||||
{
|
||||
bool bdo = true;
|
||||
for (unsigned int a = 1; a < mesh->mNumVertices;++a)
|
||||
|
@ -624,14 +789,13 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
}
|
||||
|
||||
// If we have a second texture coordinate set and a second texture
|
||||
// (either lightmap, normalmap, 2layered material we need to
|
||||
// setup the correct UV index for it). The texture can either
|
||||
// (either lightmap, normalmap, 2layered material) we need to
|
||||
// setup the correct UV index for it. The texture can either
|
||||
// be diffuse (lightmap & 2layer) or a normal map (normal & parallax)
|
||||
if (mesh->HasTextureCoords(1))
|
||||
{
|
||||
int idx = 1;
|
||||
if (src.second & (AI_IRRMESH_MAT_solid_2layer |
|
||||
AI_IRRMESH_MAT_lightmap))
|
||||
if (src.second & (AI_IRRMESH_MAT_solid_2layer | AI_IRRMESH_MAT_lightmap))
|
||||
{
|
||||
mat->AddProperty(&idx,1,AI_MATKEY_UVWSRC_DIFFUSE(0));
|
||||
}
|
||||
|
@ -653,11 +817,11 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
|
||||
case Node::SPHERE:
|
||||
{
|
||||
// generate the sphere model. Our input parameter to
|
||||
// Generate the sphere model. Our input parameter to
|
||||
// the sphere generation algorithm is the number of
|
||||
// subdivisions of each triangle - but here we have
|
||||
// the number of poylgons on a specific axis. Just
|
||||
// use some limits ...
|
||||
// use some hardcoded limits to approximate this ...
|
||||
unsigned int mul = root->spherePolyCountX*root->spherePolyCountY;
|
||||
if (mul < 100)mul = 2;
|
||||
else if (mul < 300)mul = 3;
|
||||
|
@ -667,10 +831,14 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
&StandardShapes::MakeSphere));
|
||||
|
||||
// Adjust scaling
|
||||
root->scaling *= root->sphereRadius;
|
||||
root->scaling *= root->sphereRadius/2;
|
||||
|
||||
// Copy one output material
|
||||
CopyMaterial(materials, root->materials, defMatIdx, meshes.back());
|
||||
|
||||
// Now adjust this output material - if there is a first texture
|
||||
// set, setup spherical UV mapping around the Y axis.
|
||||
SetupMapping ( (MaterialHelper*) materials.back(), aiTextureMapping_SPHERE, aiAxis_Y );
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -685,6 +853,10 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
|
||||
// Copy one output material
|
||||
CopyMaterial(materials, root->materials, defMatIdx, meshes.back());
|
||||
|
||||
// Now adjust this output material - if there is a first texture
|
||||
// set, setup cubic UV mapping
|
||||
SetupMapping ( (MaterialHelper*) materials.back(), aiTextureMapping_BOX );
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -745,10 +917,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
// Now compute the final local transformation matrix of the
|
||||
// node from the given translation, rotation and scaling values.
|
||||
// (the rotation is given in Euler angles, XYZ order)
|
||||
aiMatrix4x4 m;
|
||||
rootOut->mTransformation = aiMatrix4x4::RotationX(AI_DEG_TO_RAD(root->rotation.x),m)
|
||||
* aiMatrix4x4::RotationY(AI_DEG_TO_RAD(root->rotation.y),m)
|
||||
* aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(root->rotation.z),m);
|
||||
rootOut->mTransformation.FromEulerAngles(AI_DEG_TO_RAD(root->rotation) );
|
||||
|
||||
// apply scaling
|
||||
aiMatrix4x4& mat = rootOut->mTransformation;
|
||||
|
@ -763,12 +932,15 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
|||
mat.c3 *= root->scaling.z;
|
||||
|
||||
// apply translation
|
||||
mat.a4 = root->position.x;
|
||||
mat.b4 = root->position.y;
|
||||
mat.c4 = root->position.z;
|
||||
mat.a4 += root->position.x;
|
||||
mat.b4 += root->position.y;
|
||||
mat.c4 += root->position.z;
|
||||
|
||||
if (meshTrafoAssign == 2)
|
||||
mat *= AI_TO_IRR_MATRIX;
|
||||
|
||||
// now compute animations for the node
|
||||
ComputeAnimations(root,anims,mat);
|
||||
ComputeAnimations(root,rootOut, anims);
|
||||
|
||||
// Add all children recursively. First allocate enough storage
|
||||
// for them, then call us again
|
||||
|
@ -804,6 +976,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
// The root node of the scene
|
||||
Node* root = new Node(Node::DUMMY);
|
||||
root->parent = NULL;
|
||||
root->name = "<IRRSceneRoot>";
|
||||
|
||||
// Current node parent
|
||||
Node* curParent = root;
|
||||
|
@ -819,6 +992,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
// Batch loader used to load external models
|
||||
BatchLoader batch(pIOHandler);
|
||||
batch.SetBasePath(pFile);
|
||||
|
||||
cameras.reserve(5);
|
||||
lights.reserve(5);
|
||||
|
@ -848,6 +1022,8 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
* and join its animation channels with ours.
|
||||
* "empty" - A dummy node
|
||||
* "camera" - A camera
|
||||
* "terrain" - a terrain node (data comes from a heightmap)
|
||||
* "billboard", ""
|
||||
*
|
||||
* Each of these nodes can be animated and all can have multiple
|
||||
* materials assigned (except lights, cameras and dummies, of course).
|
||||
|
@ -855,8 +1031,9 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
// ***********************************************************************
|
||||
const char* sz = reader->getAttributeValueSafe("type");
|
||||
Node* nd;
|
||||
if (!ASSIMP_stricmp(sz,"mesh"))
|
||||
if (!ASSIMP_stricmp(sz,"mesh") || !ASSIMP_stricmp(sz,"octTree"))
|
||||
{
|
||||
// OctTree's and meshes are treated equally
|
||||
nd = new Node(Node::MESH);
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"cube"))
|
||||
|
@ -868,7 +1045,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
else if (!ASSIMP_stricmp(sz,"skybox"))
|
||||
{
|
||||
nd = new Node(Node::SKYBOX);
|
||||
++guessedMeshCnt;
|
||||
guessedMeshCnt += 6;
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"camera"))
|
||||
{
|
||||
|
@ -901,6 +1078,16 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
{
|
||||
nd = new Node(Node::DUMMY);
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"terrain"))
|
||||
{
|
||||
nd = new Node(Node::TERRAIN);
|
||||
}
|
||||
else if (!ASSIMP_stricmp(sz,"billBoard"))
|
||||
{
|
||||
// We don't support billboards, so ignore them
|
||||
DefaultLogger::get()->error("IRR: Billboards are not supported by Assimp");
|
||||
nd = new Node(Node::DUMMY);
|
||||
}
|
||||
else
|
||||
{
|
||||
DefaultLogger::get()->warn("IRR: Found unknown node: " + std::string(sz));
|
||||
|
@ -929,19 +1116,21 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
else if (!ASSIMP_stricmp(reader->getNodeName(),"attributes"))
|
||||
{
|
||||
/* We should have a valid node here
|
||||
* FIX: no ... the scene root node is also contained in an attributes block
|
||||
*/
|
||||
if (!curNode)
|
||||
{
|
||||
#if 0
|
||||
DefaultLogger::get()->error("IRR: Encountered <attributes> element, but "
|
||||
"there is no node active");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
Animator* curAnim = NULL;
|
||||
|
||||
// FIX: Materials can occur for nearly any type of node
|
||||
if (inMaterials /* && curNode->type == Node::ANIMMESH ||
|
||||
curNode->type == Node::MESH */)
|
||||
// Materials can occur for nearly any type of node
|
||||
if (inMaterials && curNode->type != Node::DUMMY)
|
||||
{
|
||||
/* This is a material description - parse it!
|
||||
*/
|
||||
|
@ -976,10 +1165,6 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
VectorProperty prop;
|
||||
ReadVectorProperty(prop);
|
||||
|
||||
// Convert to our coordinate system
|
||||
std::swap( (float&)prop.value.z, (float&)prop.value.y );
|
||||
prop.value.y *= -1.f;
|
||||
|
||||
if (inAnimator)
|
||||
{
|
||||
if (curAnim->type == Animator::ROTATION && prop.name == "Rotation")
|
||||
|
@ -999,7 +1184,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
// and parse its properties
|
||||
key.mValue = prop.value;
|
||||
key.mTime = strtol10(&prop.name.c_str()[5]);
|
||||
key.mTime = strtol10(&prop.name[5]);
|
||||
}
|
||||
}
|
||||
else if (curAnim->type == Animator::FLY_CIRCLE)
|
||||
|
@ -1127,7 +1312,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
else if (Node::LIGHT == curNode->type)
|
||||
{
|
||||
/* Additional light information
|
||||
*/
|
||||
*/
|
||||
if (prop.name == "Attenuation")
|
||||
{
|
||||
lights.back()->mAttenuationLinear = prop.value;
|
||||
|
@ -1204,6 +1389,22 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
}
|
||||
else if (Node::LIGHT == curNode->type && "LightType" == prop.name)
|
||||
{
|
||||
if (prop.value == "Spot")
|
||||
lights.back()->mType = aiLightSource_SPOT;
|
||||
else if (prop.value == "Point")
|
||||
lights.back()->mType = aiLightSource_POINT;
|
||||
else if (prop.value == "Directional")
|
||||
lights.back()->mType = aiLightSource_DIRECTIONAL;
|
||||
else
|
||||
{
|
||||
// We won't pass the validation with aiLightSourceType_UNDEFINED,
|
||||
// so we remove the light and replace it with a silly dummy node
|
||||
delete lights.back();
|
||||
lights.pop_back();
|
||||
curNode->type = Node::DUMMY;
|
||||
|
||||
DefaultLogger::get()->error("Ignoring light of unknown type: " + prop.value);
|
||||
}
|
||||
}
|
||||
else if (prop.name == "Mesh" && Node::MESH == curNode->type ||
|
||||
Node::ANIMMESH == curNode->type)
|
||||
|
@ -1224,8 +1425,35 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS);
|
||||
}
|
||||
|
||||
batch.AddLoadRequest(prop.value,pp,&map);
|
||||
curNode->meshPath = prop.value;
|
||||
/* TODO: maybe implement the protection against recursive
|
||||
* loading calls directly in BatchLoader? The current
|
||||
* implementation is not absolutely safe. A LWS and an IRR
|
||||
* file referencing each other *could* cause the system to
|
||||
* recurse forever.
|
||||
*/
|
||||
std::string::size_type pos = prop.value.find_last_of('.');
|
||||
|
||||
// no file extension - can't read, so we don't need to try it
|
||||
if( pos == std::string::npos)
|
||||
{
|
||||
DefaultLogger::get()->error("IRR: Can't load files without a file extension");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string extension = prop.value.substr( pos);
|
||||
for (std::string::iterator i = extension.begin(); i != extension.end();++i)
|
||||
*i = ::tolower(*i);
|
||||
|
||||
if (".irr" == prop.value)
|
||||
{
|
||||
DefaultLogger::get()->error("IRR: Can't load another IRR file recursively");
|
||||
}
|
||||
else
|
||||
{
|
||||
batch.AddLoadRequest(prop.value,pp,&map);
|
||||
curNode->meshPath = prop.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (inAnimator && prop.name == "Type")
|
||||
{
|
||||
|
@ -1275,12 +1503,12 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
{
|
||||
// currently is no node set. We need to go
|
||||
// back in the node hierarchy
|
||||
curParent = curParent->parent;
|
||||
if (!curParent)
|
||||
{
|
||||
curParent = root;
|
||||
DefaultLogger::get()->error("IRR: Too many closing <node> elements");
|
||||
}
|
||||
else curParent = curParent->parent;
|
||||
}
|
||||
else curNode = NULL;
|
||||
}
|
||||
|
@ -1314,6 +1542,8 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
else DefaultLogger::get()->warn("IRR: Camera aspect is not given, can't compute horizontal FOV");
|
||||
}
|
||||
|
||||
batch.LoadAll();
|
||||
|
||||
/* Allocate a tempoary scene data structure
|
||||
*/
|
||||
aiScene* tempScene = new aiScene();
|
||||
|
@ -1322,15 +1552,21 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
|
||||
/* Copy the cameras to the output array
|
||||
*/
|
||||
tempScene->mNumCameras = (unsigned int)cameras.size();
|
||||
tempScene->mCameras = new aiCamera*[tempScene->mNumCameras];
|
||||
::memcpy(tempScene->mCameras,&cameras[0],sizeof(void*)*tempScene->mNumCameras);
|
||||
if (!cameras.empty())
|
||||
{
|
||||
tempScene->mNumCameras = (unsigned int)cameras.size();
|
||||
tempScene->mCameras = new aiCamera*[tempScene->mNumCameras];
|
||||
::memcpy(tempScene->mCameras,&cameras[0],sizeof(void*)*tempScene->mNumCameras);
|
||||
}
|
||||
|
||||
/* Copy the light sources to the output array
|
||||
*/
|
||||
tempScene->mNumLights = (unsigned int)lights.size();
|
||||
tempScene->mLights = new aiLight*[tempScene->mNumLights];
|
||||
::memcpy(tempScene->mLights,&lights[0],sizeof(void*)*tempScene->mNumLights);
|
||||
if (!lights.empty())
|
||||
{
|
||||
tempScene->mNumLights = (unsigned int)lights.size();
|
||||
tempScene->mLights = new aiLight*[tempScene->mNumLights];
|
||||
::memcpy(tempScene->mLights,&lights[0],sizeof(void*)*tempScene->mNumLights);
|
||||
}
|
||||
|
||||
// temporary data
|
||||
std::vector< aiNodeAnim*> anims;
|
||||
|
@ -1370,27 +1606,51 @@ void IRRImporter::InternReadFile( const std::string& pFile,
|
|||
an->mChannels = new aiNodeAnim*[an->mNumChannels];
|
||||
::memcpy(an->mChannels, & anims [0], sizeof(void*)*an->mNumChannels);
|
||||
}
|
||||
if (meshes.empty())
|
||||
{
|
||||
// There are no meshes in the scene - the scene is incomplete
|
||||
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
|
||||
DefaultLogger::get()->info("IRR: No Meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE flag");
|
||||
}
|
||||
else
|
||||
if (!meshes.empty())
|
||||
{
|
||||
// copy all meshes to the temporary scene
|
||||
tempScene->mNumMeshes = (unsigned int)meshes.size();
|
||||
tempScene->mMeshes = new aiMesh*[tempScene->mNumMeshes];
|
||||
::memcpy(tempScene->mMeshes,&meshes[0],tempScene->mNumMeshes);
|
||||
::memcpy(tempScene->mMeshes,&meshes[0],tempScene->mNumMeshes*
|
||||
sizeof(void*));
|
||||
}
|
||||
|
||||
/* Copy all materials to the output array
|
||||
*/
|
||||
if (!materials.empty())
|
||||
{
|
||||
tempScene->mNumMaterials = (unsigned int)materials.size();
|
||||
tempScene->mMaterials = new aiMaterial*[tempScene->mNumMaterials];
|
||||
::memcpy(tempScene->mMaterials,&materials[0],sizeof(void*)*
|
||||
tempScene->mNumMaterials);
|
||||
}
|
||||
|
||||
/* Now merge all sub scenes and attach them to the correct
|
||||
* attachment points in the scenegraph.
|
||||
*/
|
||||
SceneCombiner::MergeScenes(pScene,tempScene,attach);
|
||||
SceneCombiner::MergeScenes(&pScene,tempScene,attach,
|
||||
AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES |
|
||||
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES);
|
||||
|
||||
|
||||
/* If we have no meshes | no materials now set the INCOMPLETE
|
||||
* scene flag. This is necessary if we failed to load all
|
||||
* models from external files
|
||||
*/
|
||||
if (!pScene->mNumMeshes || !pScene->mNumMaterials)
|
||||
{
|
||||
DefaultLogger::get()->warn("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE");
|
||||
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
|
||||
}
|
||||
|
||||
|
||||
// transformation matrix to convert from IRRMESH to ASSIMP coordinates
|
||||
pScene->mRootNode->mTransformation *= aiMatrix4x4(1.0f, 0.0f, 0.0f, 0.f, 0.0f, 0.0f, -1.0f,
|
||||
0.f, 0.0f, 1.0f, 0.0f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
|
||||
/* Finished ... everything destructs automatically and all
|
||||
* temporary scenes have already been deleted by MergeScenes()
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -238,35 +238,6 @@ private:
|
|||
aiVector3D position, normal, uv;
|
||||
};
|
||||
|
||||
/** Temporary data structure to describe an IRR animator
|
||||
*
|
||||
* Irrlicht animations always start at the beginning, so
|
||||
* we don't need "first" and "pre" for the moment.
|
||||
*/
|
||||
struct TemporaryAnim
|
||||
{
|
||||
TemporaryAnim()
|
||||
: last (0)
|
||||
, post (aiAnimBehaviour_DEFAULT)
|
||||
, matrices (NULL)
|
||||
{}
|
||||
|
||||
~TemporaryAnim()
|
||||
{
|
||||
delete[] matrices;
|
||||
}
|
||||
|
||||
void SetupMatrices(unsigned int num)
|
||||
{
|
||||
last = num;
|
||||
matrices = new aiMatrix4x4[num];
|
||||
}
|
||||
|
||||
unsigned int last;
|
||||
aiAnimBehaviour post;
|
||||
|
||||
aiMatrix4x4* matrices;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Fill the scenegraph recursively
|
||||
|
@ -276,7 +247,7 @@ private:
|
|||
std::vector<aiMesh*>& meshes,
|
||||
std::vector<aiNodeAnim*>& anims,
|
||||
std::vector<AttachmentInfo>& attach,
|
||||
std::vector<aiMaterial*> materials,
|
||||
std::vector<aiMaterial*>& materials,
|
||||
unsigned int& defaultMatIdx);
|
||||
|
||||
|
||||
|
@ -308,7 +279,7 @@ private:
|
|||
* @param defMatIdx Default material index - 0xffffffff if not there
|
||||
* @param mesh Mesh to work on
|
||||
*/
|
||||
void CopyMaterial(std::vector<aiMaterial*> materials,
|
||||
void CopyMaterial(std::vector<aiMaterial*>& materials,
|
||||
std::vector< std::pair<aiMaterial*, unsigned int> >& inmaterials,
|
||||
unsigned int& defMatIdx,
|
||||
aiMesh* mesh);
|
||||
|
@ -319,16 +290,14 @@ private:
|
|||
*
|
||||
* @param root Node to be processed
|
||||
* @param anims The list of output animations
|
||||
* @param transform Transformation matrix of the current node
|
||||
* (relative to the parent's coordinate space)
|
||||
*/
|
||||
void ComputeAnimations(Node* root, std::vector<aiNodeAnim*>& anims,
|
||||
const aiMatrix4x4& transform);
|
||||
void ComputeAnimations(Node* root, aiNode* real,
|
||||
std::vector<aiNodeAnim*>& anims);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
unsigned int fps;
|
||||
double fps;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -238,11 +238,18 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
|
|||
ColorFromARGBPacked(prop.value,clr);
|
||||
mat->AddProperty(&clr,1,AI_MATKEY_COLOR_SPECULAR);
|
||||
}
|
||||
|
||||
// NOTE: The 'emissive' property causes problems. It is
|
||||
// often != 0, even if there is obviously no light
|
||||
// emitted by the described surface. In fact I think
|
||||
// IRRLICHT ignores this property, too.
|
||||
#if 0
|
||||
else if (prop.name == "Emissive")
|
||||
{
|
||||
ColorFromARGBPacked(prop.value,clr);
|
||||
mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// Float properties
|
||||
else if (!ASSIMP_stricmp(reader->getNodeName(),"float"))
|
||||
|
@ -746,24 +753,22 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
|
|||
sz = fast_atof_move(sz,(float&)temp.x);
|
||||
SkipSpaces(&sz);
|
||||
|
||||
sz = fast_atof_move(sz,(float&)temp.z);
|
||||
SkipSpaces(&sz);
|
||||
|
||||
sz = fast_atof_move(sz,(float&)temp.y);
|
||||
SkipSpaces(&sz);
|
||||
temp.y *= -1.0f;
|
||||
|
||||
sz = fast_atof_move(sz,(float&)temp.z);
|
||||
SkipSpaces(&sz);
|
||||
curVertices.push_back(temp);
|
||||
|
||||
// Read the vertex normals
|
||||
sz = fast_atof_move(sz,(float&)temp.x);
|
||||
SkipSpaces(&sz);
|
||||
|
||||
sz = fast_atof_move(sz,(float&)temp.z);
|
||||
SkipSpaces(&sz);
|
||||
|
||||
sz = fast_atof_move(sz,(float&)temp.y);
|
||||
SkipSpaces(&sz);
|
||||
temp.y *= -1.0f;
|
||||
|
||||
sz = fast_atof_move(sz,(float&)temp.z);
|
||||
SkipSpaces(&sz);
|
||||
curNormals.push_back(temp);
|
||||
|
||||
// read the vertex colors
|
||||
|
@ -953,6 +958,10 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
|
|||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
pScene->mRootNode->mMeshes[i] = i;
|
||||
|
||||
// transformation matrix to convert from IRRMESH to ASSIMP coordinates
|
||||
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
||||
1.0f, 0.0f, 0.0f, 0.f, 0.0f, 0.0f, -1.0f, 0.f, 0.0f, 1.0f, 0.0f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
delete reader;
|
||||
AI_DEBUG_INVALIDATE_PTR(reader);
|
||||
}
|
|
@ -1,2 +1,97 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (ASSIMP)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
#include "AssimpPCH.h"
|
||||
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 LWS importer class */
|
||||
|
||||
#include "AssimpPCH.h"
|
||||
|
||||
#include "LWSLoader.h"
|
||||
#include "ParsingUtils.h"
|
||||
#include "fast_atof.h"
|
||||
|
||||
#include "SceneCombiner.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
LWSImporter::LWSImporter()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
LWSImporter::~LWSImporter()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool LWSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
|
||||
{
|
||||
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 i = extension.begin(); i != extension.end();++i)
|
||||
*i = ::tolower(*i);
|
||||
|
||||
return extension == ".lws";
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWSImporter::GetExtensionList(std::string& append)
|
||||
{
|
||||
append.append("*.lws");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
|
||||
namespace Assimp {
|
||||
namespace LWS {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents an element in a LWS file.
|
||||
*
|
||||
* This can either be a single data line - <name> <value> or it can
|
||||
* be a data group - { name <data_line0> ... n }
|
||||
*/
|
||||
class Element
|
||||
{
|
||||
std::string name, data;
|
||||
std::list<Element> children;
|
||||
|
||||
void Parse (const char* buffer);
|
||||
};
|
||||
|
||||
|
||||
} // end namespace LWS
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** LWS (LightWave Scene Format) importer class.
|
||||
|
@ -76,10 +94,7 @@ protected:
|
|||
/** Called by Importer::GetExtensionList() for each loaded importer.
|
||||
* See BaseImporter::GetExtensionList() for details
|
||||
*/
|
||||
void GetExtensionList(std::string& append)
|
||||
{
|
||||
append.append("*.lws");
|
||||
}
|
||||
void GetExtensionList(std::string& append);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
|
|
|
@ -102,6 +102,7 @@ void OptimizeGraphProcess::FindLockedNodes(aiNode* node)
|
|||
{
|
||||
ai_assert(NULL != node);
|
||||
|
||||
// process animations
|
||||
for (unsigned int i = 0; i < pScene->mNumAnimations;++i)
|
||||
{
|
||||
aiAnimation* pani = pScene->mAnimations[i];
|
||||
|
@ -110,11 +111,34 @@ void OptimizeGraphProcess::FindLockedNodes(aiNode* node)
|
|||
aiNodeAnim* pba = pani->mChannels[a];
|
||||
if (pba->mNodeName == node->mName)
|
||||
{
|
||||
// this node is locked
|
||||
// this node is locked, it is referenced by an animation channel
|
||||
node->mNumChildren |= AI_OG_UINT_MSB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// process cameras
|
||||
for (unsigned int i = 0; i < pScene->mNumCameras;++i)
|
||||
{
|
||||
aiCamera* p = pScene->mCameras[i];
|
||||
if (p->mName == node->mName)
|
||||
{
|
||||
// this node is locked, it is referenced by a camera
|
||||
node->mNumChildren |= AI_OG_UINT_MSB;
|
||||
}
|
||||
}
|
||||
|
||||
// process lights
|
||||
for (unsigned int i = 0; i < pScene->mNumLights;++i)
|
||||
{
|
||||
aiLight* p = pScene->mLights[i];
|
||||
if (p->mName == node->mName)
|
||||
{
|
||||
// this node is locked, it is referenced by a light
|
||||
node->mNumChildren |= AI_OG_UINT_MSB;
|
||||
}
|
||||
}
|
||||
|
||||
// call all children
|
||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
||||
FindLockedNodes(node->mChildren[i]);
|
||||
|
@ -250,233 +274,6 @@ inline unsigned int OptimizeGraphProcess::BinarySearch(NodeIndexList& sortedArra
|
|||
return (unsigned int)sortedArray.size();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void OptimizeGraphProcess::BuildUniqueBoneList(
|
||||
std::vector<aiMesh*>::const_iterator it,
|
||||
std::vector<aiMesh*>::const_iterator end,
|
||||
std::list<BoneWithHash>& asBones)
|
||||
{
|
||||
|
||||
unsigned int iOffset = 0;
|
||||
for (; it != end;++it)
|
||||
{
|
||||
for (unsigned int l = 0; l < (*it)->mNumBones;++l)
|
||||
{
|
||||
aiBone* p = (*it)->mBones[l];
|
||||
uint32_t itml = SuperFastHash(p->mName.data,(unsigned int)p->mName.length);
|
||||
|
||||
std::list<BoneWithHash>::iterator it2 = asBones.begin();
|
||||
std::list<BoneWithHash>::iterator end2 = asBones.end();
|
||||
|
||||
for (;it2 != end2;++it2)
|
||||
{
|
||||
if ((*it2).first == itml)
|
||||
{
|
||||
(*it2).pSrcBones.push_back(BoneSrcIndex(p,iOffset));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (end2 == it2)
|
||||
{
|
||||
// need to begin a new bone entry
|
||||
asBones.push_back(BoneWithHash());
|
||||
BoneWithHash& btz = asBones.back();
|
||||
|
||||
// setup members
|
||||
btz.first = itml;
|
||||
btz.second = &p->mName;
|
||||
btz.pSrcBones.push_back(BoneSrcIndex(p,iOffset));
|
||||
}
|
||||
}
|
||||
iOffset += (*it)->mNumVertices;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void OptimizeGraphProcess::JoinBones(
|
||||
std::vector<aiMesh*>::const_iterator it,
|
||||
std::vector<aiMesh*>::const_iterator end,
|
||||
aiMesh* out)
|
||||
{
|
||||
ai_assert(NULL != out);
|
||||
|
||||
// find we need to build an unique list of all bones.
|
||||
// we work with hashes to make the comparisons MUCH faster,
|
||||
// at least if we have many bones.
|
||||
std::list<BoneWithHash> asBones;
|
||||
BuildUniqueBoneList(it,end,asBones);
|
||||
|
||||
// now create the output bones
|
||||
out->mBones = new aiBone*[asBones.size()];
|
||||
|
||||
for (std::list<BoneWithHash>::const_iterator it = asBones.begin(),
|
||||
end = asBones.end(); it != end;++it)
|
||||
{
|
||||
aiBone* pc = out->mBones[out->mNumBones++] = new aiBone();
|
||||
pc->mName = aiString( *((*it).second ));
|
||||
|
||||
// get an itrator to the end of the list
|
||||
std::vector< BoneSrcIndex >::const_iterator wend = (*it).pSrcBones.end();
|
||||
|
||||
// loop through all bones to be joined for this bone
|
||||
for (std::vector< BoneSrcIndex >::const_iterator
|
||||
wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)
|
||||
{
|
||||
pc->mNumWeights += (*wmit).first->mNumWeights;
|
||||
|
||||
// NOTE: different offset matrices for bones with equal names
|
||||
// are - at the moment - not handled correctly.
|
||||
if (wmit != (*it).pSrcBones.begin() &&
|
||||
pc->mOffsetMatrix != (*wmit).first->mOffsetMatrix)
|
||||
{
|
||||
DefaultLogger::get()->warn("Bones with equal names but different "
|
||||
"offset matrices can't be joined at the moment. If this causes "
|
||||
"problems, deactivate the OptimizeGraph-Step");
|
||||
|
||||
continue;
|
||||
}
|
||||
pc->mOffsetMatrix = (*wmit).first->mOffsetMatrix;
|
||||
}
|
||||
// allocate the vertex weight array
|
||||
aiVertexWeight* avw = pc->mWeights = new aiVertexWeight[pc->mNumWeights];
|
||||
|
||||
// and copy the final weights - adjust the vertex IDs by the
|
||||
// face index offset of the coresponding mesh.
|
||||
for (std::vector< BoneSrcIndex >::const_iterator
|
||||
wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)
|
||||
{
|
||||
aiBone* pip = (*wmit).first;
|
||||
for (unsigned int mp = 0; mp < pip->mNumWeights;++mp,++avw)
|
||||
{
|
||||
const aiVertexWeight& vfi = pip->mWeights[mp];
|
||||
avw->mWeight = vfi.mWeight;
|
||||
avw->mVertexId = vfi.mVertexId + (*wmit).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void OptimizeGraphProcess::JoinMeshes(std::vector<aiMesh*>& meshList,
|
||||
aiMesh*& out, unsigned int max)
|
||||
{
|
||||
ai_assert(NULL != out && 0 != max);
|
||||
|
||||
out->mMaterialIndex = meshList[0]->mMaterialIndex;
|
||||
|
||||
// allocate the output mesh
|
||||
out = new aiMesh();
|
||||
std::vector<aiMesh*>::const_iterator end = meshList.begin()+max;
|
||||
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
|
||||
{
|
||||
out->mNumVertices += (*it)->mNumVertices;
|
||||
out->mNumFaces += (*it)->mNumFaces;
|
||||
out->mNumBones += AI_OG_UNMASK((*it)->mNumBones);
|
||||
|
||||
// combine primitive type flags
|
||||
out->mPrimitiveTypes |= (*it)->mPrimitiveTypes;
|
||||
}
|
||||
|
||||
if (out->mNumVertices) // just for safety
|
||||
{
|
||||
aiVector3D* pv2;
|
||||
|
||||
// copy vertex positions
|
||||
if (meshList[0]->HasPositions())
|
||||
{
|
||||
pv2 = out->mVertices = new aiVector3D[out->mNumVertices];
|
||||
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
|
||||
{
|
||||
::memcpy(pv2,(*it)->mVertices,(*it)->mNumVertices*sizeof(aiVector3D));
|
||||
pv2 += (*it)->mNumVertices;
|
||||
}
|
||||
}
|
||||
// copy normals
|
||||
if (meshList[0]->HasNormals())
|
||||
{
|
||||
pv2 = out->mNormals = new aiVector3D[out->mNumVertices];
|
||||
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
|
||||
{
|
||||
::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D));
|
||||
pv2 += (*it)->mNumVertices;
|
||||
}
|
||||
}
|
||||
// copy tangents and bitangents
|
||||
if (meshList[0]->HasTangentsAndBitangents())
|
||||
{
|
||||
pv2 = out->mTangents = new aiVector3D[out->mNumVertices];
|
||||
aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices];
|
||||
|
||||
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
|
||||
{
|
||||
::memcpy(pv2, (*it)->mTangents, (*it)->mNumVertices*sizeof(aiVector3D));
|
||||
::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D));
|
||||
pv2 += (*it)->mNumVertices;
|
||||
pv2b += (*it)->mNumVertices;
|
||||
}
|
||||
}
|
||||
// copy texture coordinates
|
||||
unsigned int n = 0;
|
||||
while (meshList[0]->HasTextureCoords(n))
|
||||
{
|
||||
out->mNumUVComponents[n] = meshList[0]->mNumUVComponents[n];
|
||||
|
||||
pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices];
|
||||
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
|
||||
{
|
||||
::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D));
|
||||
pv2 += (*it)->mNumVertices;
|
||||
}
|
||||
++n;
|
||||
}
|
||||
// copy vertex colors
|
||||
n = 0;
|
||||
while (meshList[0]->HasVertexColors(n))
|
||||
{
|
||||
aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
|
||||
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
|
||||
{
|
||||
::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
|
||||
pv2 += (*it)->mNumVertices;
|
||||
}
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
if (out->mNumFaces) // just for safety
|
||||
{
|
||||
// copy faces
|
||||
out->mFaces = new aiFace[out->mNumFaces];
|
||||
aiFace* pf2 = out->mFaces;
|
||||
|
||||
unsigned int ofs = 0;
|
||||
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
|
||||
{
|
||||
for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2)
|
||||
{
|
||||
aiFace& face = (*it)->mFaces[m];
|
||||
pf2->mNumIndices = face.mNumIndices;
|
||||
pf2->mIndices = face.mIndices;
|
||||
|
||||
if (ofs)
|
||||
{
|
||||
// add the offset to the vertex
|
||||
for (unsigned int q = 0; q < face.mNumIndices; ++q)
|
||||
face.mIndices[q] += ofs;
|
||||
}
|
||||
ofs += (*it)->mNumVertices;
|
||||
face.mIndices = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bones - as this is quite lengthy, I moved the code to a separate function
|
||||
if (out->mNumBones)JoinBones(meshList.begin(),end,out);
|
||||
|
||||
// delete all source meshes
|
||||
for (std::vector<aiMesh*>::const_iterator it = meshList.begin(); it != end;++it)
|
||||
delete *it;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void OptimizeGraphProcess::ApplyNodeMeshesOptimization(aiNode* pNode)
|
||||
|
@ -513,7 +310,7 @@ void OptimizeGraphProcess::ApplyNodeMeshesOptimization(aiNode* pNode)
|
|||
if (iNumMeshes > 0)
|
||||
{
|
||||
apcMeshes[iNumMeshes++] = pScene->mMeshes[nm];
|
||||
JoinMeshes(apcMeshes,out,iNumMeshes);
|
||||
// JoinMeshes(apcMeshes,out,iNumMeshes);
|
||||
}
|
||||
else out = pScene->mMeshes[nm];
|
||||
|
||||
|
@ -785,13 +582,13 @@ void OptimizeGraphProcess::Execute( aiScene* pScene)
|
|||
|
||||
a) the term "mesh node" stands for a node with numMeshes > 0
|
||||
b) the term "animation node" stands for a node with numMeshes == 0,
|
||||
regardless whether the node is referenced by animation channels.
|
||||
regardless whether the node is referenced by animation channels,
|
||||
lights or cameras
|
||||
|
||||
Algorithm:
|
||||
|
||||
1. Compute hashes for all meshes that we're able to check whether
|
||||
two meshes are compatible.
|
||||
2. Remove animation nodes if we have been configured to do so
|
||||
3. Find out which nodes may not be moved, so to speak are "locked" - a
|
||||
locked node will never be joined with neighbors.
|
||||
- A node lock is indicated by a set MSB in the aiNode::mNumChildren member
|
||||
|
|
|
@ -87,14 +87,6 @@ struct NodeIndexEntry : public std::pair<unsigned int, unsigned int>
|
|||
aiNode* pNode;
|
||||
};
|
||||
typedef std::vector<NodeIndexEntry> NodeIndexList;
|
||||
typedef std::pair<aiBone*,unsigned int> BoneSrcIndex;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
struct BoneWithHash : public std::pair<uint32_t,aiString*>
|
||||
{
|
||||
std::vector<BoneSrcIndex> pSrcBones;
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** This post processing step reformats the output node graph to be more
|
||||
|
@ -230,38 +222,6 @@ protected:
|
|||
void ApplyNodeMeshesOptimization(aiNode* pNode);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Join meshes.
|
||||
* The output meshes are deleted afterwards.
|
||||
* @param meshList List of meshes to be joined
|
||||
* @param out Receives a pointer to the output mesh.
|
||||
*/
|
||||
void JoinMeshes(std::vector<aiMesh*>& meshList,aiMesh*& out,
|
||||
unsigned int max);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Join bones from a collection of meshes.
|
||||
*
|
||||
* @param it First mesh to be processed
|
||||
* @param end Last mesh to be processed
|
||||
* @param out Valid output mesh to receive the output bone list.
|
||||
*/
|
||||
void JoinBones(std::vector<aiMesh*>::const_iterator it,
|
||||
std::vector<aiMesh*>::const_iterator end,
|
||||
aiMesh* out);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Build a list of unique bones from a collection of meshes.
|
||||
*
|
||||
* @param it First mesh to be processed
|
||||
* @param end Last mesh to be processed
|
||||
* @param asBones Receives a list of unique bones
|
||||
*/
|
||||
void BuildUniqueBoneList(std::vector<aiMesh*>::const_iterator it,
|
||||
std::vector<aiMesh*>::const_iterator end,
|
||||
std::list<BoneWithHash>& asBones);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Build the output mesh list.
|
||||
|
|
|
@ -48,14 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using namespace Assimp;
|
||||
|
||||
|
||||
// MSB for type unsigned int
|
||||
#define AI_RC_UINT_MSB (1u<<((sizeof(unsigned int)<<3u)-1u))
|
||||
#define AI_RC_UINT_MSB_2 (AI_RC_UINT_MSB>>1u)
|
||||
|
||||
// unmask the two upper bits of an unsigned int
|
||||
#define AI_RC_UNMASK(p) (p & (~(AI_RC_UINT_MSB|AI_RC_UINT_MSB_2)))
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
RemoveVCProcess::RemoveVCProcess()
|
||||
|
@ -79,89 +71,70 @@ bool RemoveVCProcess::IsActive( unsigned int pFlags) const
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Small helper function to delete all elements in a T** aray using delete
|
||||
template <typename T>
|
||||
inline void ArrayDelete(T**& in, unsigned int num)
|
||||
inline void ArrayDelete(T**& in, unsigned int& num)
|
||||
{
|
||||
for (unsigned int i = 0; i < num; ++i)
|
||||
delete in[i];
|
||||
|
||||
delete[] in;
|
||||
in = NULL;
|
||||
num = 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Small helper function to set a sepcific bit in the aiNode::mNumMeshes member of all nodes
|
||||
// that are referenced by the elements of an array (T::mName must be there)
|
||||
template <typename T>
|
||||
inline void MaskNodes(aiNode* node,T** in, unsigned int num, unsigned int bit)
|
||||
{
|
||||
if (node->mName.length)
|
||||
{
|
||||
for (unsigned int i = 0; i < num;++i)
|
||||
{
|
||||
T* cur = in[i];
|
||||
if (cur->mName == node->mName)
|
||||
{
|
||||
node->mNumMeshes |= bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
||||
MaskNodes(node->mChildren[i],in,num,bit);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Updates the node graph - removes all nodes which have the "remove" flag set and the
|
||||
// "don't remove" flag not set. Nodes with meshes are never deleted.
|
||||
bool UpdateNodeGraph(aiNode* node,std::list<aiNode*>& childsOfParent,bool root)
|
||||
{
|
||||
register bool b = false;
|
||||
|
||||
std::list<aiNode*> mine;
|
||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
||||
{
|
||||
if(UpdateNodeGraph(node->mChildren[i],mine,false))
|
||||
b = true;
|
||||
}
|
||||
|
||||
if (!root && !node->mNumMeshes && AI_RC_UINT_MSB == (node->mNumMeshes & (AI_RC_UINT_MSB | AI_RC_UINT_MSB_2)))
|
||||
{
|
||||
// this node needs to be removed
|
||||
if(node->mNumChildren)
|
||||
{
|
||||
childsOfParent.insert(childsOfParent.end(),mine.begin(),mine.end());
|
||||
|
||||
// set all children to NULL to make sure they are not deleted when we delete ourself
|
||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
||||
node->mChildren[i] = NULL;
|
||||
}
|
||||
b = true;
|
||||
delete node;
|
||||
}
|
||||
else
|
||||
{
|
||||
AI_RC_UNMASK(node->mNumMeshes);
|
||||
childsOfParent.push_back(node);
|
||||
|
||||
if (b)
|
||||
{
|
||||
// reallocate the array of our children here
|
||||
node->mNumChildren = (unsigned int)mine.size();
|
||||
aiNode** const children = new aiNode*[mine.size()];
|
||||
aiNode** ptr = children;
|
||||
|
||||
for (std::list<aiNode*>::iterator it = mine.begin(), end = mine.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
*ptr++ = *it;
|
||||
}
|
||||
delete[] node->mChildren;
|
||||
node->mChildren = children;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
//// ------------------------------------------------------------------------------------------------
|
||||
//// Updates the node graph - removes all nodes which have the "remove" flag set and the
|
||||
//// "don't remove" flag not set. Nodes with meshes are never deleted.
|
||||
//bool UpdateNodeGraph(aiNode* node,std::list<aiNode*>& childsOfParent,bool root)
|
||||
//{
|
||||
// register bool b = false;
|
||||
//
|
||||
// std::list<aiNode*> mine;
|
||||
// for (unsigned int i = 0; i < node->mNumChildren;++i)
|
||||
// {
|
||||
// if(UpdateNodeGraph(node->mChildren[i],mine,false))
|
||||
// b = true;
|
||||
// }
|
||||
//
|
||||
// // somewhat tricky ... mNumMeshes must be originally 0 and MSB2 may not be set,
|
||||
// // so we can do a simple comparison against MSB here
|
||||
// if (!root && AI_RC_UINT_MSB == node->mNumMeshes )
|
||||
// {
|
||||
// // this node needs to be removed
|
||||
// if(node->mNumChildren)
|
||||
// {
|
||||
// childsOfParent.insert(childsOfParent.end(),mine.begin(),mine.end());
|
||||
//
|
||||
// // set all children to NULL to make sure they are not deleted when we delete ourself
|
||||
// for (unsigned int i = 0; i < node->mNumChildren;++i)
|
||||
// node->mChildren[i] = NULL;
|
||||
// }
|
||||
// b = true;
|
||||
// delete node;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// AI_RC_UNMASK(node->mNumMeshes);
|
||||
// childsOfParent.push_back(node);
|
||||
//
|
||||
// if (b)
|
||||
// {
|
||||
// // reallocate the array of our children here
|
||||
// node->mNumChildren = (unsigned int)mine.size();
|
||||
// aiNode** const children = new aiNode*[mine.size()];
|
||||
// aiNode** ptr = children;
|
||||
//
|
||||
// for (std::list<aiNode*>::iterator it = mine.begin(), end = mine.end();
|
||||
// it != end; ++it)
|
||||
// {
|
||||
// *ptr++ = *it;
|
||||
// }
|
||||
// delete[] node->mChildren;
|
||||
// node->mChildren = children;
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// return b;
|
||||
//}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
|
@ -175,6 +148,7 @@ void RemoveVCProcess::Execute( aiScene* pScene)
|
|||
// handle animations
|
||||
if ( configDeleteFlags & aiComponent_ANIMATIONS)
|
||||
{
|
||||
|
||||
bHas = true;
|
||||
ArrayDelete(pScene->mAnimations,pScene->mNumAnimations);
|
||||
}
|
||||
|
@ -212,21 +186,13 @@ void RemoveVCProcess::Execute( aiScene* pScene)
|
|||
// handle light sources
|
||||
if ( configDeleteFlags & aiComponent_LIGHTS)
|
||||
{
|
||||
// mask nodes for removal
|
||||
MaskNodes(pScene->mRootNode,pScene->mLights,pScene->mNumLights,
|
||||
AI_RC_UINT_MSB);
|
||||
|
||||
bHas = bMasked = true;
|
||||
bHas = true;
|
||||
ArrayDelete(pScene->mLights,pScene->mNumLights);
|
||||
}
|
||||
|
||||
// handle camneras
|
||||
if ( configDeleteFlags & aiComponent_CAMERAS)
|
||||
{
|
||||
// mask nodes for removal
|
||||
MaskNodes(pScene->mRootNode,pScene->mLights,pScene->mNumLights,
|
||||
AI_RC_UINT_MSB);
|
||||
|
||||
bHas = true;
|
||||
ArrayDelete(pScene->mCameras,pScene->mNumCameras);
|
||||
}
|
||||
|
@ -241,46 +207,11 @@ void RemoveVCProcess::Execute( aiScene* pScene)
|
|||
{
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
||||
{
|
||||
if( this->ProcessMesh( pScene->mMeshes[a]))
|
||||
if( ProcessMesh( pScene->mMeshes[a]))
|
||||
bHas = true;
|
||||
}
|
||||
if (configDeleteFlags & aiComponent_BONEWEIGHTS && bHas)bMasked = true;
|
||||
}
|
||||
|
||||
// now check which scenegraph nodes are unnecessary now
|
||||
// we use the upper two bits of aiNode::mNumMeshes as
|
||||
// temporary storage.
|
||||
// MSB means: REMOVE ME!
|
||||
// MSB>>1 means: NO, DON'T REMOVE ME (Veto)
|
||||
if (bMasked)
|
||||
{
|
||||
if (pScene->mNumLights)
|
||||
{
|
||||
MaskNodes(pScene->mRootNode,pScene->mLights,pScene->mNumLights,
|
||||
AI_RC_UINT_MSB_2);
|
||||
}
|
||||
if (pScene->mNumCameras)
|
||||
{
|
||||
MaskNodes(pScene->mRootNode,pScene->mCameras,pScene->mNumCameras,
|
||||
AI_RC_UINT_MSB_2);
|
||||
}
|
||||
if (!(configDeleteFlags & aiComponent_BONEWEIGHTS))
|
||||
{
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
{
|
||||
aiMesh* mesh = pScene->mMeshes[i];
|
||||
if (mesh->mNumBones)
|
||||
{
|
||||
MaskNodes(pScene->mRootNode,mesh->mBones,mesh->mNumBones,
|
||||
AI_RC_UINT_MSB_2);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::list<aiNode*> dummy;
|
||||
UpdateNodeGraph(pScene->mRootNode,dummy, true);
|
||||
|
||||
// the root node will never be deleted
|
||||
}
|
||||
|
||||
// now check whether the result is still a full scene
|
||||
if (!pScene->mNumMeshes || !pScene->mNumMaterials)
|
||||
|
@ -385,13 +316,8 @@ bool RemoveVCProcess::ProcessMesh(aiMesh* pMesh)
|
|||
// handle bones
|
||||
if (configDeleteFlags & aiComponent_BONEWEIGHTS && pMesh->mBones)
|
||||
{
|
||||
// mask nodes for removal
|
||||
MaskNodes(mScene->mRootNode,pMesh->mBones,pMesh->mNumBones,
|
||||
AI_RC_UINT_MSB);
|
||||
|
||||
ArrayDelete(pMesh->mBones,pMesh->mNumBones);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -69,6 +69,43 @@ struct AttachmentInfo
|
|||
aiNode* attachToNode;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
struct NodeAttachmentInfo
|
||||
{
|
||||
NodeAttachmentInfo()
|
||||
: node (NULL)
|
||||
, attachToNode (NULL)
|
||||
{}
|
||||
|
||||
NodeAttachmentInfo(aiNode* _scene, aiNode* _attachToNode)
|
||||
: node (_scene)
|
||||
, attachToNode (_attachToNode)
|
||||
{}
|
||||
|
||||
aiNode* node;
|
||||
aiNode* attachToNode;
|
||||
};
|
||||
|
||||
// generate unique names for all named scene items
|
||||
#define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES 0x1
|
||||
// generate unique names for materials, too
|
||||
#define AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES 0x2
|
||||
// use deep copies of duplicate scenes
|
||||
#define AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY 0x4
|
||||
|
||||
|
||||
typedef std::pair<aiBone*,unsigned int> BoneSrcIndex;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** \brief Helper data structure for SceneCombiner::MergeBones.
|
||||
*
|
||||
*/
|
||||
struct BoneWithHash : public std::pair<uint32_t,aiString*>
|
||||
{
|
||||
std::vector<BoneSrcIndex> pSrcBones;
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** \brief Static helper class providing various utilities to merge two
|
||||
* scenes. It is intended as internal utility and NOT for use by
|
||||
|
@ -87,12 +124,14 @@ public:
|
|||
// -------------------------------------------------------------------
|
||||
/** Merges two or more scenes.
|
||||
*
|
||||
* @param dest Destination scene. Must be empty.
|
||||
* @param dest Receives a pointer to the destination scene. If the
|
||||
* pointer doesn't point to NULL when the function is called, the
|
||||
* existing scene is cleared and refilled.
|
||||
* @param src Non-empty list of scenes to be merged. The function
|
||||
* deletes the input scenes afterwards.
|
||||
* deletes the input scenes afterwards. There may be duplicate scenes.
|
||||
* @param flags Combination of the AI_INT_MERGE_SCENE flags defined above
|
||||
*/
|
||||
static void MergeScenes(aiScene* dest,std::vector<aiScene*>& src,
|
||||
static void MergeScenes(aiScene** dest,std::vector<aiScene*>& src,
|
||||
unsigned int flags = 0);
|
||||
|
||||
|
||||
|
@ -100,31 +139,63 @@ public:
|
|||
/** Merges two or more scenes and attaches all sceenes to a specific
|
||||
* position in the node graph of the masteer scene.
|
||||
*
|
||||
* @param dest Destination scene. Must be empty.
|
||||
* @param dest Receives a pointer to the destination scene. If the
|
||||
* pointer doesn't point to NULL when the function is called, the
|
||||
* existing scene is cleared and refilled.
|
||||
* @param master Master scene. It will be deleted afterwards. All
|
||||
* other scenes will be inserted in its node graph.
|
||||
* @param src Non-empty list of scenes to be merged along with their
|
||||
* corresponding attachment points in the master scene. The function
|
||||
* deletes the input scenes afterwards.
|
||||
* deletes the input scenes afterwards. There may be duplicate scenes.
|
||||
* @param flags Combination of the AI_INT_MERGE_SCENE flags defined above
|
||||
*/
|
||||
static void MergeScenes(aiScene* dest, const aiScene* master,
|
||||
static void MergeScenes(aiScene** dest, aiScene* master,
|
||||
std::vector<AttachmentInfo>& src,
|
||||
unsigned int flags = 0);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Merges two or more meshes
|
||||
*
|
||||
* The meshes should have equal vertex formats. Only components
|
||||
* that are provided by ALL meshes will be present in the output mesh.
|
||||
* An exception is made for VColors - they are set to black. The
|
||||
* meshes should have the same material indices, too. The output
|
||||
* material index is always the material index of the first mesh.
|
||||
*
|
||||
* @param dest Destination mesh. Must be empty.
|
||||
* @param src Non-empty list of meshes to be merged. The function
|
||||
* deletes the input meshes afterwards.
|
||||
* @param flags Currently no parameters
|
||||
* @param begin First mesh to be processed
|
||||
* @param end Points to the mesh after the last mesh to be processed
|
||||
*/
|
||||
static void MergeMeshes(aiMesh* dest,std::vector<aiMesh*>& src,
|
||||
unsigned int flags);
|
||||
static void MergeMeshes(aiMesh** dest,unsigned int flags,
|
||||
std::vector<aiMesh*>::const_iterator begin,
|
||||
std::vector<aiMesh*>::const_iterator end);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Merges two or more bones
|
||||
*
|
||||
* @param out Mesh to receive the output bone list
|
||||
* @param flags Currently no parameters
|
||||
* @param begin First mesh to be processed
|
||||
* @param end Points to the mesh after the last mesh to be processed
|
||||
*/
|
||||
static void MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator it,
|
||||
std::vector<aiMesh*>::const_iterator end);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Builds a list of uniquely named bones in a mesh list
|
||||
*
|
||||
* @param asBones Receives the output list
|
||||
* @param it First mesh to be processed
|
||||
* @param end Last mesh to be processed
|
||||
*/
|
||||
static void BuildUniqueBoneList(std::list<BoneWithHash>& asBones,
|
||||
std::vector<aiMesh*>::const_iterator it,
|
||||
std::vector<aiMesh*>::const_iterator end);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Add a name prefix to all nodes in a scene.
|
||||
*
|
||||
|
@ -134,6 +205,75 @@ public:
|
|||
*/
|
||||
static void AddNodePrefixes(aiNode* node, const char* prefix,
|
||||
unsigned int len);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Add an offset to all mesh indices in a node graph
|
||||
*
|
||||
* @param Current node. This function is called recursively.
|
||||
* @param offset Offset to be added to all mesh indices
|
||||
*/
|
||||
static void OffsetNodeMeshIndices (aiNode* node, unsigned int offset);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Attach a list of node graphs to well-defined nodes in a master
|
||||
* graph. This is a helper for MergeScenes()
|
||||
*
|
||||
* @param master Master scene
|
||||
* @param srcList List of source scenes along with their attachment
|
||||
* points. If an attachment point is NULL (or does not exist in
|
||||
* the master graph), a scene is attached to the root of the master
|
||||
* graph (as an additional child node)
|
||||
* @duplicates List of duplicates. If elem[n] == n the scene is not
|
||||
* a duplicate. Otherwise elem[n] links scene n to its first occurence.
|
||||
*/
|
||||
static void AttachToGraph ( aiScene* master,
|
||||
std::vector<NodeAttachmentInfo>& srcList);
|
||||
|
||||
static void AttachToGraph (aiNode* attach,
|
||||
std::vector<NodeAttachmentInfo>& srcList);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get a deep copy of a scene
|
||||
*
|
||||
* @param dest Receives a pointer to the destination scene
|
||||
* @param src Source scene - remains unmodified.
|
||||
*/
|
||||
static void CopyScene(aiScene** dest,aiScene* source);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get a flat copy of a scene
|
||||
*
|
||||
* Only the first hierarchy layer is copied. All pointer members of
|
||||
* aiScene are shared by source and destination scene. If the
|
||||
* pointer doesn't point to NULL when the function is called, the
|
||||
* existing scene is cleared and refilled.
|
||||
* @param dest Receives a pointer to the destination scene
|
||||
* @param src Source scene - remains unmodified.
|
||||
*/
|
||||
static void CopySceneFlat(aiScene** dest,aiScene* source);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get a deep copy of a mesh
|
||||
*
|
||||
* @param dest Receives a pointer to the destination mesh
|
||||
* @param src Source mesh - remains unmodified.
|
||||
*/
|
||||
static void Copy (aiMesh** dest, const aiMesh* src);
|
||||
|
||||
// similar to Copy():
|
||||
static void Copy (aiMaterial** dest, const aiMaterial* src);
|
||||
static void Copy (aiTexture** dest, const aiTexture* src);
|
||||
static void Copy (aiAnimation** dest, const aiAnimation* src);
|
||||
static void Copy (aiCamera** dest, const aiCamera* src);
|
||||
static void Copy (aiBone** dest, const aiBone* src);
|
||||
static void Copy (aiLight** dest, const aiLight* src);
|
||||
static void Copy (aiNodeAnim** dest, const aiNodeAnim* src);
|
||||
|
||||
// recursive, of course
|
||||
static void Copy (aiNode** dest, const aiNode* src);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -194,6 +194,6 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
|
|||
if (anim->mDuration == -1.)
|
||||
{
|
||||
DefaultLogger::get()->debug("Setting animation duration");
|
||||
anim->mDuration = last - first;
|
||||
anim->mDuration = last - std::min( first, 0. );
|
||||
}
|
||||
}
|
|
@ -44,7 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using namespace Assimp;
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
KeyIterator::KeyIterator(const std::vector<aiVectorKey>* _objPos,
|
||||
const std::vector<aiVectorKey>* _targetObjPos,
|
||||
const aiVector3D* defaultObjectPos /*= NULL*/,
|
||||
|
@ -80,7 +80,14 @@ KeyIterator::KeyIterator(const std::vector<aiVectorKey>* _objPos,
|
|||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
T Interpolate(const T& one, const T& two, float val)
|
||||
{
|
||||
return one + (two-one)*val;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void KeyIterator::operator ++()
|
||||
{
|
||||
// If we are already at the end of all keyframes, return
|
||||
|
@ -129,8 +136,8 @@ void KeyIterator::operator ++()
|
|||
const aiVectorKey& last = targetObjPos->at(nextTargetObjPos);
|
||||
const aiVectorKey& first = targetObjPos->at(nextTargetObjPos-1);
|
||||
|
||||
/* curTargetPosition = Interpolate(first.mValue, last.mValue,
|
||||
(curTime-first.mTime) / (last.mTime-first.mTime));*/
|
||||
curTargetPosition = Interpolate(first.mValue, last.mValue, (float) (
|
||||
(curTime-first.mTime) / (last.mTime-first.mTime) ));
|
||||
}
|
||||
|
||||
// increment counters
|
||||
|
@ -155,8 +162,8 @@ void KeyIterator::operator ++()
|
|||
const aiVectorKey& last = objPos->at(nextObjPos);
|
||||
const aiVectorKey& first = objPos->at(nextObjPos-1);
|
||||
|
||||
/*curPosition = Interpolate(first.mValue, last.mValue,
|
||||
(curTime-first.mTime) / (last.mTime-first.mTime));*/
|
||||
curPosition = Interpolate(first.mValue, last.mValue, (float) (
|
||||
(curTime-first.mTime) / (last.mTime-first.mTime)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,7 +174,7 @@ void KeyIterator::operator ++()
|
|||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TargetAnimationHelper::SetTargetAnimationChannel (
|
||||
const std::vector<aiVectorKey>* _targetPositions)
|
||||
{
|
||||
|
@ -175,7 +182,7 @@ void TargetAnimationHelper::SetTargetAnimationChannel (
|
|||
targetPositions = _targetPositions;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TargetAnimationHelper::SetMainAnimationChannel (
|
||||
const std::vector<aiVectorKey>* _objectPositions)
|
||||
{
|
||||
|
@ -183,7 +190,7 @@ void TargetAnimationHelper::SetMainAnimationChannel (
|
|||
objectPositions = _objectPositions;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TargetAnimationHelper::SetFixedMainAnimationChannel(
|
||||
const aiVector3D& fixed)
|
||||
{
|
||||
|
@ -191,23 +198,53 @@ void TargetAnimationHelper::SetFixedMainAnimationChannel(
|
|||
fixedMain = fixed;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TargetAnimationHelper::Process(std::vector<aiVectorKey>* distanceTrack)
|
||||
{
|
||||
ai_assert(NULL != targetPositions);
|
||||
|
||||
// TODO: in most cases we won't need the extra array
|
||||
std::vector<aiVectorKey>* fill = NULL;
|
||||
std::vector<aiVectorKey> real;
|
||||
if (distanceTrack)
|
||||
{
|
||||
fill = (distanceTrack == objectPositions ? &real : distanceTrack);
|
||||
}
|
||||
fill->reserve(std::max( objectPositions->size(), targetPositions->size() ));
|
||||
|
||||
// Iterate through all object keys and interpolate their values if necessary.
|
||||
// Then get the corresponding target position, compute the difference
|
||||
// vector between object and target position. Then compute a rotation matrix
|
||||
// that rotates the base vector of the object coordinate system at that time
|
||||
// to match the diff vector.
|
||||
|
||||
KeyIterator iter(objectPositions,targetPositions,&fixedMain);
|
||||
unsigned int curTarget;
|
||||
for (;!iter.Finished();++iter)
|
||||
{
|
||||
const aiVector3D& position = iter.GetCurPosition();
|
||||
const aiVector3D& tposition = iter.GetCurTargetPosition();
|
||||
|
||||
|
||||
// diff vector
|
||||
aiVector3D diff = tposition - position;
|
||||
float f = diff.SquareLength();
|
||||
if (!f)
|
||||
{
|
||||
DefaultLogger::get()->error("Target position equals object position");
|
||||
continue;
|
||||
}
|
||||
f = ::sqrt(f);
|
||||
|
||||
// output distance vector
|
||||
if (fill)
|
||||
{
|
||||
fill->push_back(aiVectorKey());
|
||||
aiVectorKey& v = fill->back();
|
||||
v.mTime = iter.GetCurTime();
|
||||
v.mValue = aiVector3D (0.f,0.f,f);
|
||||
}
|
||||
diff /= f;
|
||||
}
|
||||
|
||||
if (real.size())
|
||||
*distanceTrack = real;
|
||||
}
|
|
@ -98,6 +98,9 @@ public:
|
|||
inline const aiVector3D& GetCurTargetPosition() const
|
||||
{return curTargetPosition;}
|
||||
|
||||
inline double GetCurTime() const
|
||||
{return curTime;}
|
||||
|
||||
private:
|
||||
|
||||
//! Did we reach the end?
|
||||
|
|
|
@ -114,22 +114,20 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
|
|||
return;
|
||||
}
|
||||
|
||||
float absTranslationX = info.mScaling.x * info.mTranslation.x;
|
||||
float absTranslationY = info.mScaling.y * info.mTranslation.y;
|
||||
|
||||
/* Optimize UV translation in the U direction. To determine whether
|
||||
* or not we can optimize we need to look at the requested mapping
|
||||
* type (e.g. if mirroring is active there IS a difference between
|
||||
* offset 2 and 3)
|
||||
*/
|
||||
if ((rounded = (int)absTranslationX))
|
||||
if ((rounded = (int)info.mTranslation.x))
|
||||
{
|
||||
float out;
|
||||
szTemp[0] = 0;
|
||||
if (aiTextureMapMode_Wrap == info.mapU)
|
||||
{
|
||||
// Wrap - simple take the fraction of the field
|
||||
out = (absTranslationX-(float)rounded) / info.mScaling.x;
|
||||
out = info.mTranslation.x-(float)rounded;
|
||||
sprintf(szTemp,"[w] UV U offset %f can "
|
||||
"be simplified to %f",info.mTranslation.x,out);
|
||||
}
|
||||
|
@ -137,7 +135,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
|
|||
{
|
||||
// Mirror
|
||||
if (rounded % 2)rounded--;
|
||||
out = (absTranslationX-(float)rounded) / info.mScaling.x;
|
||||
out = info.mTranslation.x-(float)rounded;
|
||||
|
||||
sprintf(szTemp,"[m/d] UV U offset %f can "
|
||||
"be simplified to %f",info.mTranslation.x,out);
|
||||
|
@ -162,14 +160,14 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
|
|||
* type (e.g. if mirroring is active there IS a difference between
|
||||
* offset 2 and 3)
|
||||
*/
|
||||
if ((rounded = (int)absTranslationY))
|
||||
if ((rounded = (int)info.mTranslation.y))
|
||||
{
|
||||
float out;
|
||||
szTemp[0] = 0;
|
||||
if (aiTextureMapMode_Wrap == info.mapV)
|
||||
{
|
||||
// Wrap - simple take the fraction of the field
|
||||
out = (absTranslationY-(float)rounded) / info.mScaling.y;
|
||||
out = info.mTranslation.y-(float)rounded;
|
||||
sprintf(szTemp,"[w] UV V offset %f can "
|
||||
"be simplified to %f",info.mTranslation.y,out);
|
||||
}
|
||||
|
@ -177,7 +175,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
|
|||
{
|
||||
// Mirror
|
||||
if (rounded % 2)rounded--;
|
||||
out = (absTranslationY-(float)rounded) / info.mScaling.y;
|
||||
out = info.mTranslation.x-(float)rounded;
|
||||
|
||||
sprintf(szTemp,"[m/d] UV V offset %f can "
|
||||
"be simplified to %f",info.mTranslation.y,out);
|
||||
|
@ -272,7 +270,7 @@ void TextureTransformStep::Execute( aiScene* pScene)
|
|||
info.uvIndex = *((int*)prop2->mData);
|
||||
|
||||
// Store a direct pointer for later use
|
||||
update.directShortcut = (unsigned int*) &prop2->mData;
|
||||
update.directShortcut = (unsigned int*) prop2->mData;
|
||||
}
|
||||
|
||||
else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodeu"))
|
||||
|
@ -286,8 +284,7 @@ void TextureTransformStep::Execute( aiScene* pScene)
|
|||
// ValidateDS should check this
|
||||
ai_assert(prop2->mDataLength >= 20);
|
||||
|
||||
::memcpy(&info.mTranslation.x,prop2->mData,
|
||||
sizeof(float)*5);
|
||||
::memcpy(&info.mTranslation.x,prop2->mData,sizeof(float)*5);
|
||||
|
||||
delete[] prop2->mData;
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ struct STransformVecInfo : public aiUVTransform
|
|||
inline bool operator== (const STransformVecInfo& other) const
|
||||
{
|
||||
// We use a small epsilon here
|
||||
const float epsilon = 0.05f;
|
||||
const static float epsilon = 0.05f;
|
||||
|
||||
if (fabs( mTranslation.x - other.mTranslation.x ) > epsilon ||
|
||||
fabs( mTranslation.y - other.mTranslation.y ) > epsilon)
|
||||
|
|
|
@ -637,8 +637,6 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
|
|||
szType,iIndex,iNumIndices,szType);
|
||||
}
|
||||
if (!iNumIndices)return;
|
||||
|
||||
// TODO: check whether the mappings are correctly
|
||||
std::vector<aiTextureMapping> mappings(iNumIndices);
|
||||
|
||||
// Now check whether all UV indices are valid ...
|
||||
|
@ -711,7 +709,7 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
|
|||
for (unsigned int a = 0; a < mScene->mNumMeshes;++a)
|
||||
{
|
||||
aiMesh* mesh = mScene->mMeshes[a];
|
||||
if(mesh->mMaterialIndex == (unsigned int)iIndex)
|
||||
if(mesh->mMaterialIndex == (unsigned int)iIndex && mappings[0] == aiTextureMapping_UV)
|
||||
{
|
||||
if (!mesh->mTextureCoords[0])
|
||||
{
|
||||
|
|
|
@ -77,7 +77,7 @@ SOURCES = AssimpPCH.cpp \
|
|||
TargetAnimation.cpp \
|
||||
ComputeUVMappingProcess.cpp \
|
||||
ColladaLoader.cpp \
|
||||
ColladaParser.cpp
|
||||
ColladaParser.cpp
|
||||
|
||||
OBJECTS = $(SOURCES:.cpp=.o)
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ SOURCES = AssimpPCH.cpp \
|
|||
TargetAnimation.cpp \
|
||||
ComputeUVMappingProcess.cpp \
|
||||
ColladaLoader.cpp \
|
||||
ColladaParser.cpp
|
||||
ColladaParser.cpp
|
||||
|
||||
OBJECTS = $(SOURCES:.cpp=.o)
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
|
||||
#ifndef BOOST_MATH_COMMON_FACTOR_RT_HPP
|
||||
#define BOOST_MATH_COMMON_FACTOR_RT_HPP
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace math {
|
||||
|
||||
// TODO: use binary GCD for unsigned integers ....
|
||||
template < typename IntegerType >
|
||||
IntegerType gcd( IntegerType const &a, IntegerType const &b )
|
||||
{
|
||||
while ( true )
|
||||
{
|
||||
if ( a == zero )
|
||||
return b;
|
||||
b %= a;
|
||||
|
||||
if ( b == zero )
|
||||
return a;
|
||||
a %= b;
|
||||
}
|
||||
}
|
||||
|
||||
template < typename IntegerType >
|
||||
IntegerType lcm( IntegerType const &a, IntegerType const &b )
|
||||
{
|
||||
IntegerType t = gcd (a,b);
|
||||
if (!t)return t;
|
||||
return a / t * b;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
|
@ -51,8 +51,8 @@ public:
|
|||
virtual std::string getOsSeparator() const = 0;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Open a new file with a given path. When the access to the file is finished,
|
||||
* call Close() to release all associated resources.
|
||||
/** Open a new file with a given path. When the access to the file
|
||||
* is finished, call Close() to release all associated resources.
|
||||
*
|
||||
* @param pFile Path to the file
|
||||
* @param pMode Desired file I/O mode. Required are: "wb", "w", "wt",
|
||||
|
@ -60,8 +60,8 @@ public:
|
|||
*
|
||||
* @return New IOStream interface allowing the lib to access
|
||||
* the underlying file.
|
||||
* @note When implementing this class to provide custom IO handling, you propably
|
||||
* have to supply an own implementation of IOStream as well.
|
||||
* @note When implementing this class to provide custom IO handling,
|
||||
* you propably have to supply an own implementation of IOStream as well.
|
||||
*/
|
||||
virtual IOStream* Open(
|
||||
const std::string& pFile,
|
||||
|
@ -72,6 +72,20 @@ public:
|
|||
* @param pFile The file instance previously created by Open().
|
||||
*/
|
||||
virtual void Close( IOStream* pFile) = 0;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Compares two paths and check whether the point to identical files.
|
||||
*
|
||||
* The dummy implementation of this virtual performs a
|
||||
* case-insensitive comparison of the path strings.
|
||||
* @param one First file
|
||||
* @param second Second file
|
||||
* @return true if the paths point to the same file. The file needn't
|
||||
* be existing, however.
|
||||
*/
|
||||
virtual bool ComparePaths (const std::string& one,
|
||||
const std::string& second);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -87,6 +101,7 @@ inline IOSystem::~IOSystem()
|
|||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
} //!ns Assimp
|
||||
|
||||
#endif //AI_IOSYSTEM_H_INC
|
||||
|
|
|
@ -191,6 +191,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
// Use our own definition of PI here
|
||||
#define AI_MATH_PI (3.1415926538)
|
||||
#define AI_MATH_TWO_PI (AI_MATH_PI * 2.0)
|
||||
#define AI_MATH_HALF_PI (AI_MATH_PI * 0.5)
|
||||
|
||||
// macrod to convert from radians to degrees and the reverse
|
||||
#define AI_DEG_TO_RAD(x) (x*0.0174532925f)
|
||||
|
|
|
@ -119,6 +119,7 @@ struct aiMatrix4x4
|
|||
* \param z Rotation angle for the z-axis, in radians
|
||||
*/
|
||||
inline void FromEulerAngles(float x, float y, float z);
|
||||
inline void FromEulerAngles(const aiVector3D& blubb);
|
||||
|
||||
|
||||
/** \brief Returns a rotation matrix for a rotation around the x axis
|
||||
|
|
|
@ -87,15 +87,12 @@ inline aiMatrix4x4& aiMatrix4x4::Inverse()
|
|||
float det = Determinant();
|
||||
if(det == 0.0f)
|
||||
{
|
||||
const float nan = std::numeric_limits<float>::quiet_NaN();
|
||||
*this = aiMatrix4x4(
|
||||
std::numeric_limits<float>::quiet_NaN(),std::numeric_limits<float>::quiet_NaN(),
|
||||
std::numeric_limits<float>::quiet_NaN(),std::numeric_limits<float>::quiet_NaN(),
|
||||
std::numeric_limits<float>::quiet_NaN(),std::numeric_limits<float>::quiet_NaN(),
|
||||
std::numeric_limits<float>::quiet_NaN(),std::numeric_limits<float>::quiet_NaN(),
|
||||
std::numeric_limits<float>::quiet_NaN(),std::numeric_limits<float>::quiet_NaN(),
|
||||
std::numeric_limits<float>::quiet_NaN(),std::numeric_limits<float>::quiet_NaN(),
|
||||
std::numeric_limits<float>::quiet_NaN(),std::numeric_limits<float>::quiet_NaN(),
|
||||
std::numeric_limits<float>::quiet_NaN(),std::numeric_limits<float>::quiet_NaN());
|
||||
nan,nan,nan,nan,
|
||||
nan,nan,nan,nan,
|
||||
nan,nan,nan,nan,
|
||||
nan,nan,nan,nan);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -129,7 +126,6 @@ inline float* aiMatrix4x4::operator[](unsigned int p_iIndex)
|
|||
return &this->a1 + p_iIndex * 4;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
inline const float* aiMatrix4x4::operator[](unsigned int p_iIndex) const
|
||||
{
|
||||
|
@ -208,6 +204,11 @@ inline void aiMatrix4x4::DecomposeNoScaling (aiQuaternion& rotation,
|
|||
rotation = aiQuaternion((aiMatrix3x3)_this);
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
inline void aiMatrix4x4::FromEulerAngles(const aiVector3D& blubb)
|
||||
{
|
||||
FromEulerAngles(blubb.x,blubb.y,blubb.z);
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
inline void aiMatrix4x4::FromEulerAngles(float x, float y, float z)
|
||||
{
|
||||
aiMatrix4x4& _this = *this;
|
||||
|
|
|
@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
// include math helper classes
|
||||
#include "aiVector3D.h"
|
||||
#include "aiVector2D.h"
|
||||
#include "aiMatrix3x3.h"
|
||||
#include "aiMatrix4x4.h"
|
||||
|
||||
|
@ -66,22 +67,6 @@ const size_t MAXLEN = 1024;
|
|||
|
||||
#include "./Compiler/pushpack1.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a two-dimensional vector.
|
||||
*/
|
||||
struct aiVector2D
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
aiVector2D () : x(0.0f), y(0.0f) {}
|
||||
aiVector2D (float _x, float _y) : x(_x), y(_y) {}
|
||||
aiVector2D (const aiVector2D& o) : x(o.x), y(o.y) {}
|
||||
|
||||
#endif // !__cplusplus
|
||||
|
||||
//! X and y coordinates
|
||||
float x, y;
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a plane in a three-dimensional, euclidean space
|
||||
|
@ -94,13 +79,32 @@ struct aiPlane
|
|||
: a(_a), b(_b), c(_c), d(_d) {}
|
||||
|
||||
aiPlane (const aiPlane& o) : a(o.a), b(o.b), c(o.c), d(o.d) {}
|
||||
|
||||
|
||||
#endif // !__cplusplus
|
||||
|
||||
//! Plane equation
|
||||
float a,b,c,d;
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a ray
|
||||
*/
|
||||
struct aiRay
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
aiRay () {}
|
||||
aiRay (const aiVector3D& _pos, const aiVector3D& _dir)
|
||||
: pos(_pos), dir(_dir) {}
|
||||
|
||||
aiRay (const aiRay& o) : pos (o.pos), dir (o.dir) {}
|
||||
|
||||
#endif // !__cplusplus
|
||||
|
||||
//! Position and direction of the ray
|
||||
aiVector3D pos, dir;
|
||||
} PACK_STRUCT;
|
||||
|
||||
// aiVector3D type moved to separate header due to size of operators
|
||||
// aiQuaternion type moved to separate header due to size of operators
|
||||
// aiMatrix4x4 type moved to separate header due to size of operators
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
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 2D vector structure, including operators when compiling in C++ */
|
||||
#ifndef AI_VECTOR2D_H_INC
|
||||
#define AI_VECTOR2D_H_INC
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "./Compiler/pushpack1.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Represents a two-dimensional vector. */
|
||||
struct aiVector2D
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
aiVector2D () : x(0.0f), y(0.0f) {}
|
||||
aiVector2D (float _x, float _y) : x(_x), y(_y) {}
|
||||
aiVector2D (float _xyz) : x(_xyz), y(_xyz) {}
|
||||
aiVector2D (const aiVector2D& o) : x(o.x), y(o.y) {}
|
||||
|
||||
void Set( float pX, float pY) { x = pX; y = pY;}
|
||||
float SquareLength() const { return x*x + y*y; }
|
||||
float Length() const { return sqrt( SquareLength()); }
|
||||
aiVector2D& Normalize() { *this /= Length(); return *this; }
|
||||
const aiVector2D& operator += (const aiVector2D& o) { x += o.x; y += o.y; return *this; }
|
||||
const aiVector2D& operator -= (const aiVector2D& o) { x -= o.x; y -= o.y; return *this; }
|
||||
const aiVector2D& operator *= (float f) { x *= f; y *= f; return *this; }
|
||||
const aiVector2D& operator /= (float f) { x /= f; y /= f; return *this; }
|
||||
|
||||
inline float operator[](unsigned int i) const {return *(&x + i);}
|
||||
inline float& operator[](unsigned int i) {return *(&x + i);}
|
||||
|
||||
inline bool operator== (const aiVector2D& other) const
|
||||
{return x == other.x && y == other.y;}
|
||||
|
||||
inline bool operator!= (const aiVector2D& other) const
|
||||
{return x != other.x || y != other.y;}
|
||||
|
||||
inline aiVector2D& operator= (float f)
|
||||
{x = y = f;return *this;}
|
||||
|
||||
const aiVector2D SymMul(const aiVector2D& o)
|
||||
{return aiVector2D(x*o.x,y*o.y);}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
float x, y;
|
||||
} PACK_STRUCT;
|
||||
|
||||
#include "./Compiler/poppack1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // end extern "C"
|
||||
|
||||
// symmetric addition
|
||||
inline aiVector2D operator + (const aiVector2D& v1, const aiVector2D& v2)
|
||||
{
|
||||
return aiVector2D( v1.x + v2.x, v1.y + v2.y);
|
||||
}
|
||||
|
||||
// symmetric subtraction
|
||||
inline aiVector2D operator - (const aiVector2D& v1, const aiVector2D& v2)
|
||||
{
|
||||
return aiVector2D( v1.x - v2.x, v1.y - v2.y);
|
||||
}
|
||||
|
||||
// scalar product
|
||||
inline float operator * (const aiVector2D& v1, const aiVector2D& v2)
|
||||
{
|
||||
return v1.x*v2.x + v1.y*v2.y;
|
||||
}
|
||||
|
||||
// scalar multiplication
|
||||
inline aiVector2D operator * ( float f, const aiVector2D& v)
|
||||
{
|
||||
return aiVector2D( f*v.x, f*v.y);
|
||||
}
|
||||
|
||||
// and the other way around
|
||||
inline aiVector2D operator * ( const aiVector2D& v, float f)
|
||||
{
|
||||
return aiVector2D( f*v.x, f*v.y);
|
||||
}
|
||||
|
||||
// scalar division
|
||||
inline aiVector2D operator / ( const aiVector2D& v, float f)
|
||||
{
|
||||
|
||||
return v * (1/f);
|
||||
}
|
||||
|
||||
// vector division
|
||||
inline aiVector2D operator / ( const aiVector2D& v, const aiVector2D& v2)
|
||||
{
|
||||
return aiVector2D(v.x / v2.x,v.y / v2.y);
|
||||
}
|
||||
|
||||
// vector inversion
|
||||
inline aiVector2D operator - ( const aiVector2D& v)
|
||||
{
|
||||
return aiVector2D( -v.x, -v.y);
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // AI_VECTOR2D_H_INC
|
|
@ -9,7 +9,7 @@ kids 0
|
|||
OBJECT poly
|
||||
name "sphere"
|
||||
loc -0.0624103 -0.012381 0.0558408
|
||||
texture "./../LWOFiles/LWO2/MappingModes/concrete.jpg"
|
||||
texture "./../LWOFiles/LWO2/MappingModes/earthSpherical.jpg"
|
||||
crease 45.000000
|
||||
numvert 134
|
||||
-0.00202139 0.0563461 0
|
||||
|
|
|
@ -9,7 +9,7 @@ kids 0
|
|||
OBJECT poly
|
||||
name "sphere"
|
||||
loc -0.0624103 -0.012381 0.0558408
|
||||
texture "./../LWOFiles/LWO2/MappingModes/concrete.jpg"
|
||||
texture "./../LWOFiles/LWO2/MappingModes/earthSpherical.jpg"
|
||||
texrep 1.9 2.5
|
||||
texoff 0.019 0.5
|
||||
crease 45.000000
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -663,6 +663,10 @@
|
|||
RelativePath="..\..\include\aiTypes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\aiVector2D.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\aiVector3D.h"
|
||||
>
|
||||
|
@ -722,6 +726,10 @@
|
|||
<Filter
|
||||
Name="BoostWorkaround"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\include\BoostWorkaround\boost\common_factor_rt.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\BoostWorkaround\boost\format.hpp"
|
||||
>
|
||||
|
|
Loading…
Reference in New Issue