moved files around
This commit is contained in:
147
Extras/BulletOdeCollide/BVHTrimeshShape.cpp
Normal file
147
Extras/BulletOdeCollide/BVHTrimeshShape.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
|
||||
#include "BVHTrimeshShape.h"
|
||||
|
||||
#define TRIMESH_INTERNAL //requires OPCODE for the AABB tree
|
||||
#include <../ode/src/collision_trimesh_internal.h>
|
||||
|
||||
//Thanks AndrewONeil for the TrimeshBridge fix
|
||||
|
||||
BVHTrimeshShape::BVHTrimeshShape(dxTriMesh* trimesh)
|
||||
: TriangleMeshShape(new TrimeshBridge(trimesh))
|
||||
, m_triangleBridge( static_cast<TrimeshBridge*>(m_meshInterface))
|
||||
{
|
||||
}
|
||||
|
||||
BVHTrimeshShape::~BVHTrimeshShape ()
|
||||
{
|
||||
delete m_triangleBridge;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
TrimeshBridge::TrimeshBridge(dxTriMesh* trimesh)
|
||||
:m_trimesh(trimesh)
|
||||
{
|
||||
}
|
||||
|
||||
void TrimeshBridge::getLockedReadOnlyVertexIndexBase(const unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,const unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart) const
|
||||
{
|
||||
numverts = m_trimesh->Data->Mesh.GetNbVertices();
|
||||
(*vertexbase) = (unsigned char *)m_trimesh->Data->Mesh.GetVerts();
|
||||
type = PHY_FLOAT;
|
||||
stride = m_trimesh->Data->Mesh.GetVertexStride();
|
||||
|
||||
numfaces = m_trimesh->Data->Mesh.GetNbTriangles();
|
||||
(*indexbase) = (unsigned char *)m_trimesh->Data->Mesh.GetTris();
|
||||
indexstride = m_trimesh->Data->Mesh.GetTriStride();
|
||||
indicestype = PHY_INTEGER;
|
||||
}
|
||||
|
||||
void TrimeshBridge::getLockedVertexIndexBase(unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart)
|
||||
{
|
||||
|
||||
numverts = m_trimesh->Data->Mesh.GetNbVertices();
|
||||
(*vertexbase) = (unsigned char *)m_trimesh->Data->Mesh.GetVerts();
|
||||
type = PHY_FLOAT;
|
||||
stride = m_trimesh->Data->Mesh.GetVertexStride();
|
||||
|
||||
numfaces = m_trimesh->Data->Mesh.GetNbTriangles();
|
||||
(*indexbase) = (unsigned char *)m_trimesh->Data->Mesh.GetTris();
|
||||
indexstride = m_trimesh->Data->Mesh.GetTriStride();
|
||||
indicestype = PHY_INTEGER;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_AABB_TREE
|
||||
|
||||
//ProcessAllTriangles first gets the overlapping triangles using BVH culling
|
||||
//and passes them on to the TriangleCallback
|
||||
void BVHTrimeshShape::ProcessAllTriangles(TriangleCallback* callback,const SimdVector3& aabbMin,const SimdVector3& aabbMax) const
|
||||
{
|
||||
dxTriMesh* TriMesh = m_triangleBridge->m_trimesh;
|
||||
|
||||
// Init
|
||||
const dVector3& TLPosition = *(const dVector3*)dGeomGetPosition(TriMesh);
|
||||
const dMatrix3& TLRotation = *(const dMatrix3*)dGeomGetRotation(TriMesh);
|
||||
|
||||
SphereCollider& Collider = TriMesh->_SphereCollider;
|
||||
|
||||
|
||||
SimdVector3 he = (aabbMax-aabbMin)*0.5f;
|
||||
SimdVector3 cen = (aabbMax+aabbMin)*0.5f;
|
||||
|
||||
|
||||
dVector3 aabbHalfExtents;
|
||||
aabbHalfExtents[0] = he.x();
|
||||
aabbHalfExtents[1] = he.y();
|
||||
aabbHalfExtents[2] = he.z();
|
||||
|
||||
dVector3 Position;
|
||||
Position[0]=cen.x();
|
||||
Position[1]=cen.y();
|
||||
Position[2]=cen.z();
|
||||
|
||||
dReal Radius = he.length();
|
||||
|
||||
// Bounding Sphere (from aabb)
|
||||
Sphere Sphere;
|
||||
Sphere.mCenter.x = Position[0];
|
||||
Sphere.mCenter.y = Position[1];
|
||||
Sphere.mCenter.z = Position[2];
|
||||
Sphere.mRadius = Radius;
|
||||
|
||||
Matrix4x4 trimeshTransform;
|
||||
MakeMatrix(TLPosition, TLRotation, trimeshTransform);
|
||||
|
||||
// bvhTraversal.getOverlappingPrimitiveIndices(
|
||||
// indicesCache,
|
||||
// Sphere,
|
||||
// TriMesh->Data->BVTree,
|
||||
// &trimeshTransform);
|
||||
|
||||
Collider.SetTemporalCoherence(false);
|
||||
Collider.SetPrimitiveTests(false);
|
||||
Collider.Collide(dxTriMesh::defaultSphereCache, Sphere, TriMesh->Data->BVTree, null,
|
||||
&trimeshTransform);
|
||||
|
||||
// get results
|
||||
int TriCount = Collider.GetNbTouchedPrimitives();
|
||||
const int* Triangles = (const int*)Collider.GetTouchedPrimitives();
|
||||
|
||||
if (TriCount != 0){
|
||||
|
||||
int OutTriCount = 0;
|
||||
for (int i = 0; i < TriCount; i++){
|
||||
//what was this
|
||||
//if (OutTriCount == (Flags & 0xffff)){
|
||||
// break;
|
||||
//}
|
||||
|
||||
const int& TriIndex = Triangles[i];
|
||||
|
||||
dVector3 dv[3];
|
||||
FetchTriangle(TriMesh, TriIndex, TLPosition, TLRotation, dv);
|
||||
|
||||
SimdVector3 vts[3] =
|
||||
{ SimdVector3(dv[0][0],dv[0][1],dv[0][2]),
|
||||
SimdVector3 (dv[1][0],dv[1][1],dv[1][2]),
|
||||
SimdVector3 (dv[2][0],dv[2][1],dv[2][2])
|
||||
};
|
||||
|
||||
callback->ProcessTriangle(&vts[0]);
|
||||
|
||||
OutTriCount++;
|
||||
}
|
||||
if (OutTriCount)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif //USE_AABB_TREE
|
||||
|
||||
68
Extras/BulletOdeCollide/BVHTrimeshShape.h
Normal file
68
Extras/BulletOdeCollide/BVHTrimeshShape.h
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
#ifndef BVH_TRIMESH_SHAPE_H
|
||||
#define BVH_TRIMESH_SHAPE_H
|
||||
|
||||
#include <ode/collision.h>
|
||||
#include <ode/matrix.h>
|
||||
#include <ode/rotation.h>
|
||||
#include <ode/odemath.h>
|
||||
#include <../ode/src/collision_util.h>
|
||||
#include <../ode/src/collision_kernel.h>
|
||||
#include <../ode/src/collision_kernel.h>
|
||||
#include "CollisionShapes/TriangleMeshShape.h"
|
||||
struct dxTriMesh;
|
||||
|
||||
///if this USE_AABB_TREE is not defined, it will brute force go through all triangles
|
||||
#define USE_AABB_TREE
|
||||
|
||||
|
||||
class TrimeshBridge : public StridingMeshInterface
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
dxTriMesh* m_trimesh;
|
||||
|
||||
TrimeshBridge(dxTriMesh* trimesh);
|
||||
|
||||
virtual void getLockedVertexIndexBase(unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0);
|
||||
|
||||
virtual void getLockedReadOnlyVertexIndexBase(const unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,const unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0) const;
|
||||
|
||||
/// unLockVertexBase finishes the access to a subpart of the triangle mesh
|
||||
/// make a call to unLockVertexBase when the read and write access (using getLockedVertexIndexBase) is finished
|
||||
virtual void unLockVertexBase(int subpart) {}
|
||||
|
||||
virtual void unLockReadOnlyVertexBase(int subpart) const {}
|
||||
|
||||
/// getNumSubParts returns the number of seperate subparts
|
||||
/// each subpart has a continuous array of vertices and indices
|
||||
virtual int getNumSubParts() const { return 1;}
|
||||
|
||||
virtual void preallocateVertices(int numverts){}
|
||||
virtual void preallocateIndices(int numindices){}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// BVHTrimeshShape bridges the Opcode to provide backwards compatibility with dxTriMesh.
|
||||
/// You can also avoid using Opcode and use Bullet trimesh support See: BvhTriangleMeshShape
|
||||
class BVHTrimeshShape : public TriangleMeshShape
|
||||
{
|
||||
TrimeshBridge * m_triangleBridge;
|
||||
|
||||
public:
|
||||
BVHTrimeshShape(dxTriMesh* trimesh);
|
||||
virtual ~BVHTrimeshShape ();
|
||||
|
||||
|
||||
#ifdef USE_AABB_TREE
|
||||
//ProcessAllTriangles first gets the overlapping triangles using BVH culling
|
||||
//and passes them on to the TriangleCallback
|
||||
void ProcessAllTriangles(TriangleCallback* callback,const SimdVector3& aabbMin,const SimdVector3& aabbMax) const;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //BVH_TRIMESH_SHAPE_H
|
||||
139
Extras/BulletOdeCollide/BulletOdeCollide.cpp
Normal file
139
Extras/BulletOdeCollide/BulletOdeCollide.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
#include "BulletOdeCollide.h"
|
||||
|
||||
//quick hack, we need internals, not just the public ode api
|
||||
#include <../ode/src/collision_kernel.h>
|
||||
|
||||
#include "NarrowPhaseCollision/PersistentManifold.h"
|
||||
#include "NarrowPhaseCollision/ManifoldPoint.h"
|
||||
|
||||
#include "BroadphaseCollision/CollisionAlgorithm.h"
|
||||
#include "BulletOdeCollisionPair.h"
|
||||
#include "../ode/src/collision_convex_internal.h"
|
||||
|
||||
#define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip)))
|
||||
|
||||
|
||||
//Persistent collision pairs. Best is to store this in the broadphase/collision-pairs if the collision detection framework provides this
|
||||
#define MAX_COLLISION_PAIRS 10000
|
||||
static BulletOdeCollisionPair* sCollisionPair[MAX_COLLISION_PAIRS];
|
||||
static int numActiveCollisionPairs = 0;
|
||||
|
||||
void InitBulletOdeCollide()
|
||||
{
|
||||
numActiveCollisionPairs = 0;
|
||||
}
|
||||
|
||||
void ExitBulletOdeCollide()
|
||||
{
|
||||
//todo: cleanup memory
|
||||
numActiveCollisionPairs = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CollisionShape* GetCollisionShapeFromConvex(dGeomID geom)
|
||||
{
|
||||
dUASSERT (geom && geom->type == dConvexClass,"argument not a convex");
|
||||
dxConvex* cnvx = (dxConvex*) geom;
|
||||
return cnvx->m_bulletCollisionShape;
|
||||
}
|
||||
|
||||
|
||||
BulletOdeCollisionPair* FindCollisionPair(dGeomID o1,dGeomID o2)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<numActiveCollisionPairs;i++)
|
||||
{
|
||||
if ( (sCollisionPair[i]->m_o1 == o1) &&
|
||||
(sCollisionPair[i]->m_o2 == o2))
|
||||
{
|
||||
return sCollisionPair[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void RemoveOdeGeomFromCollisionCache(dGeomID geom)
|
||||
{
|
||||
int i;
|
||||
for (i=numActiveCollisionPairs-1;i>=0;i--)
|
||||
{
|
||||
if ( (sCollisionPair[i]->m_o1 == geom) ||
|
||||
(sCollisionPair[i]->m_o2 == geom))
|
||||
{
|
||||
delete sCollisionPair[i];
|
||||
sCollisionPair[i] = sCollisionPair[numActiveCollisionPairs-1];
|
||||
numActiveCollisionPairs--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int BulletOdeCollide(dGeomID o1,dGeomID o2,dContactGeom *contact,int maxContact,int skip)
|
||||
{
|
||||
|
||||
//In order to have more then 1 point we use persistent manifold per overlapping pair
|
||||
BulletOdeCollisionPair* collisionPair = FindCollisionPair(o1,o2);
|
||||
if (!collisionPair)
|
||||
{
|
||||
if (numActiveCollisionPairs < MAX_COLLISION_PAIRS)
|
||||
{
|
||||
collisionPair = new BulletOdeCollisionPair(o1,o2);
|
||||
sCollisionPair[numActiveCollisionPairs++] = collisionPair ;
|
||||
} else
|
||||
{
|
||||
printf("overflow in collisionpair cache\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//perform collision detection and recalculate the contact manifold
|
||||
collisionPair->CalculateContacts();
|
||||
|
||||
//transfer contacts from PersistentManifold to gContactGeom
|
||||
int validContacts = 0;
|
||||
float maxDepth = -1e30f;
|
||||
|
||||
for (int i=0; i<collisionPair->m_manifold->GetNumContacts(); i++)
|
||||
{
|
||||
const ManifoldPoint& pt = collisionPair->m_manifold->GetContactPoint(i);
|
||||
|
||||
if (pt.GetDistance() < 0.f)
|
||||
{
|
||||
float depth = -pt.GetDistance();
|
||||
|
||||
//add contacts, and make sure to add the deepest contact in any case
|
||||
if ((validContacts < maxContact) || (depth > maxDepth))
|
||||
{
|
||||
maxDepth = depth;
|
||||
int contactIndex = validContacts;
|
||||
|
||||
if (contactIndex >= maxContact)
|
||||
contactIndex = 0;
|
||||
|
||||
if (contactIndex < maxContact)
|
||||
{
|
||||
SimdVector3 pos = (pt.m_positionWorldOnB + pt.m_positionWorldOnA)*0.5f;
|
||||
|
||||
CONTACT(contact,contactIndex*skip)->depth = depth;
|
||||
CONTACT(contact,contactIndex*skip)->pos[0] = pos.getX();
|
||||
CONTACT(contact,contactIndex*skip)->pos[1] = pos.getY();
|
||||
CONTACT(contact,contactIndex*skip)->pos[2] = pos.getZ();
|
||||
CONTACT(contact,contactIndex*skip)->normal[0] = pt.m_normalWorldOnB.getX();
|
||||
CONTACT(contact,contactIndex*skip)->normal[1] = pt.m_normalWorldOnB.getY();
|
||||
CONTACT(contact,contactIndex*skip)->normal[2] = pt.m_normalWorldOnB.getZ();
|
||||
CONTACT(contact,contactIndex*skip)->g1 = o1;
|
||||
CONTACT(contact,contactIndex*skip)->g2 = o2;
|
||||
}
|
||||
if (validContacts < maxContact)
|
||||
validContacts++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//printf("numcontacts: %d",validContacts);
|
||||
|
||||
return validContacts;
|
||||
}
|
||||
13
Extras/BulletOdeCollide/BulletOdeCollide.h
Normal file
13
Extras/BulletOdeCollide/BulletOdeCollide.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef _BULLET_ODE_COLLIDE_H
|
||||
#define _BULLET_ODE_COLLIDE_H
|
||||
|
||||
#include <ode/common.h>
|
||||
#include <ode/contact.h>
|
||||
|
||||
int BulletOdeCollide(dGeomID o1,dGeomID o2,dContactGeom *contact,int maxContacts,int skip);
|
||||
void RemoveOdeGeomFromCollisionCache(dGeomID geom);
|
||||
class CollisionShape* GetCollisionShapeFromConvex(dGeomID convex);
|
||||
dGeomID dCreateConvex (dSpaceID space, class CollisionShape* shape);
|
||||
void dGeomConvexGetLengths(dGeomID convex, dVector3 result);
|
||||
|
||||
#endif //_BULLET_ODE_COLLIDE_H
|
||||
161
Extras/BulletOdeCollide/BulletOdeCollide_vc7.vcproj
Normal file
161
Extras/BulletOdeCollide/BulletOdeCollide_vc7.vcproj
Normal file
@@ -0,0 +1,161 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="BulletOdeCollide"
|
||||
ProjectGUID="{44672927-0084-4B70-8CDA-8697BF848C7F}"
|
||||
RootNamespace="BulletOdeCollide"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../ode/include;../../Bullet;../../LinearMath;."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB,BULLET_CONVEX_SUPPORT"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
AdditionalIncludeDirectories="../ode/include;../../Bullet;../../LinearMath;."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB,BULLET_CONVEX_SUPPORT"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath=".\BulletOdeCollide.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\BulletOdeCollisionPair.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\BulletOdeManifoldResult.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\BulletOdeTransformConvert.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ode\ode\src\collision_convex.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GeomToShape.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath=".\BulletOdeCollide.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\BulletOdeCollisionPair.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\BulletOdeManifoldResult.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\BulletOdeTransformConvert.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\BVHTraversal.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\BVHTrimeshShape.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GeomToShape.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\VTune\BulletOdeCollide.vpj">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ReadMe.txt">
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
184
Extras/BulletOdeCollide/BulletOdeCollisionPair.cpp
Normal file
184
Extras/BulletOdeCollide/BulletOdeCollisionPair.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
#include "BulletOdeCollisionPair.h"
|
||||
|
||||
#include "NarrowPhaseCollision/PersistentManifold.h"
|
||||
//quick hack, we need internals, not just the public ode api
|
||||
#include <../ode/src/collision_kernel.h>
|
||||
#include "CollisionShapes/BoxShape.h"
|
||||
#include "BulletOdeCollide.h"
|
||||
|
||||
#include "CollisionShapes/SphereShape.h"
|
||||
#include "CollisionShapes/CylinderShape.h"
|
||||
#include "CollisionShapes/MultiSphereShape.h"//capped cylinder is convex hull of two spheres
|
||||
#include "CollisionShapes/ConvexTriangleCallback.h"
|
||||
|
||||
#include "BVHTrimeshShape.h"
|
||||
|
||||
#include "NarrowPhaseCollision/GjkPairDetector.h"
|
||||
#include "NarrowPhaseCollision/VoronoiSimplexSolver.h"
|
||||
#include "NarrowPhaseCollision/MinkowskiPenetrationDepthSolver.h"
|
||||
///for comparison/unit testing
|
||||
#ifdef UNIT_TEST_COMPARE_PENETRATION_DEPTH
|
||||
#include "../ExtraSolid35/Solid3EpaPenetrationDepth.h"
|
||||
#endif //UNIT_TEST_COMPARE_PENETRATION_DEPTH
|
||||
|
||||
#include "BulletOdeManifoldResult.h"
|
||||
#include "BulletOdeTransformConvert.h"
|
||||
|
||||
BulletOdeCollisionPair::BulletOdeCollisionPair(dGeomID o1,dGeomID o2)
|
||||
{
|
||||
m_manifold = new PersistentManifold();
|
||||
|
||||
m_o1 = o1;
|
||||
m_o2 = o2;
|
||||
|
||||
m_shape1 = CreateShapeFromGeom(o1);
|
||||
|
||||
m_shape2 = CreateShapeFromGeom(o2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
BulletOdeCollisionPair::~BulletOdeCollisionPair()
|
||||
{
|
||||
}
|
||||
|
||||
void BulletOdeCollisionPair::CalculateContacts()
|
||||
{
|
||||
//perform gjk, passing the points to the persistent manifold and convert to ode contacts
|
||||
|
||||
if ((!m_shape1) || (!m_shape2))
|
||||
return;
|
||||
|
||||
if (m_shape1->IsConcave() && m_shape2->IsConvex())
|
||||
{
|
||||
TriangleMeshShape* triangleMesh = (TriangleMeshShape*)m_shape1;
|
||||
ConvexShape* convexShape2 = (ConvexShape*)m_shape2;
|
||||
|
||||
float collisionMarginTriangle = 0.02f;//triangleMesh->GetMargin();
|
||||
SimdTransform triangleMeshTrans = GetTransformFromGeom(m_o1);
|
||||
SimdTransform convexTrans = GetTransformFromGeom(m_o2);
|
||||
|
||||
ConvexTriangleCallback convexTriangleCallback(m_manifold,convexShape2,convexTrans,triangleMeshTrans);
|
||||
convexTriangleCallback.Update(collisionMarginTriangle);
|
||||
|
||||
triangleMesh->ProcessAllTriangles( &convexTriangleCallback,convexTriangleCallback.GetAabbMin(),convexTriangleCallback.GetAabbMax());
|
||||
|
||||
m_manifold->RefreshContactPoints(triangleMeshTrans,convexTrans);
|
||||
|
||||
}
|
||||
|
||||
if (m_shape1->IsConvex() && m_shape2->IsConvex())
|
||||
{
|
||||
ConvexShape* convexShape1 = (ConvexShape*)m_shape1;
|
||||
ConvexShape* convexShape2 = (ConvexShape*)m_shape2;
|
||||
|
||||
|
||||
|
||||
BulletOdeManifoldResult output(m_o1,m_o2,m_manifold);
|
||||
|
||||
GjkPairDetector::ClosestPointInput input;
|
||||
|
||||
VoronoiSimplexSolver simplexSolver;
|
||||
|
||||
#ifdef UNIT_TEST_COMPARE_PENETRATION_DEPTH
|
||||
Solid3EpaPenetrationDepth penetrationDepthSolver;
|
||||
#else
|
||||
MinkowskiPenetrationDepthSolver penetrationDepthSolver;
|
||||
#endif// UNIT_TEST_COMPARE_PENETRATION_DEPTH
|
||||
|
||||
GjkPairDetector gjkDetector(convexShape1,convexShape2,&simplexSolver,&penetrationDepthSolver);
|
||||
|
||||
|
||||
gjkDetector.SetMinkowskiA(convexShape1);
|
||||
gjkDetector.SetMinkowskiB(convexShape2);
|
||||
input.m_maximumDistanceSquared = m_shape1->GetMargin()+ m_shape2->GetMargin() + m_manifold->GetManifoldMargin();
|
||||
input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared;
|
||||
|
||||
input.m_maximumDistanceSquared = 1e30;//?
|
||||
|
||||
input.m_transformA = GetTransformFromGeom(m_o1);
|
||||
input.m_transformB = GetTransformFromGeom(m_o2);
|
||||
|
||||
gjkDetector.GetClosestPoints(input,output,0);
|
||||
|
||||
m_manifold->RefreshContactPoints(input.m_transformA,input.m_transformB);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void BulletOdeCollisionPair::ProcessCollision (BroadphaseProxy* proxy0,BroadphaseProxy* proxy1,const struct DispatcherInfo& dispatchInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
float BulletOdeCollisionPair::CalculateTimeOfImpact(BroadphaseProxy* proxy0,BroadphaseProxy* proxy1,const struct DispatcherInfo& dispatchInfo)
|
||||
{
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
|
||||
CollisionShape* BulletOdeCollisionPair::CreateShapeFromGeom(dGeomID geom)
|
||||
{
|
||||
CollisionShape* shape = 0;
|
||||
|
||||
if (geom->type == dConvexClass)
|
||||
{
|
||||
shape = GetCollisionShapeFromConvex(geom);
|
||||
} else
|
||||
{
|
||||
//bullet shape versus ode geom, create a compatible shape from the ode types
|
||||
switch (geom->type)
|
||||
{
|
||||
case dPlaneClass:
|
||||
break;
|
||||
case dBoxClass:
|
||||
{
|
||||
dVector3 size;
|
||||
dGeomBoxGetLengths (geom,size);
|
||||
SimdVector3 halfExtents(0.5f*size[0],0.5f*size[1],0.5f*size[2]);
|
||||
shape = new BoxShape(halfExtents);
|
||||
break;
|
||||
}
|
||||
case dSphereClass:
|
||||
{
|
||||
dVector3 size;
|
||||
shape = new SphereShape(dGeomSphereGetRadius(geom));
|
||||
break;
|
||||
}
|
||||
case dCylinderClass:
|
||||
{
|
||||
dVector3 size;
|
||||
dGeomBoxGetLengths (geom,size);
|
||||
SimdVector3 boxHalfExtents(size[0],size[0],size[1]);
|
||||
shape = new CylinderShapeZ(boxHalfExtents);
|
||||
break;
|
||||
}
|
||||
case dCCylinderClass:
|
||||
{
|
||||
dReal radius,length;
|
||||
dGeomCCylinderGetParams (geom, &radius, &length);
|
||||
SimdVector3 boxHalfExtents(radius,radius,0.5f*length);
|
||||
int numspheres = 2;
|
||||
SimdVector3 centers[2]={ SimdVector3(0,0,0.5f*length),SimdVector3(0,0,-0.5f*length)};
|
||||
SimdScalar radi[2]={radius,radius};
|
||||
shape = new MultiSphereShape(boxHalfExtents,centers,radi,numspheres);
|
||||
break;
|
||||
}
|
||||
case dTriMeshClass:
|
||||
{
|
||||
dxTriMesh* trimesh = (dxTriMesh*) geom;
|
||||
shape = 0;//new BVHTrimeshShape(trimesh);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
return shape;
|
||||
|
||||
}
|
||||
35
Extras/BulletOdeCollide/BulletOdeCollisionPair.h
Normal file
35
Extras/BulletOdeCollide/BulletOdeCollisionPair.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef BULLET_ODE_COLLISION_PAIR_H
|
||||
#define BULLET_ODE_COLLISION_PAIR_H
|
||||
|
||||
#include <BroadphaseCollision/CollisionAlgorithm.h>
|
||||
#include <ode/common.h>
|
||||
class PersistentManifold;
|
||||
|
||||
/// BulletOdeCollisionPair provides Bullet convex collision detection for Open Dynamics Engine
|
||||
class BulletOdeCollisionPair : public CollisionAlgorithm
|
||||
{
|
||||
public:
|
||||
BulletOdeCollisionPair(dGeomID o1,dGeomID o2);
|
||||
virtual ~BulletOdeCollisionPair();
|
||||
|
||||
PersistentManifold* m_manifold;
|
||||
dGeomID m_o1;
|
||||
dGeomID m_o2;
|
||||
|
||||
class CollisionShape* m_shape1;
|
||||
|
||||
class CollisionShape* m_shape2;
|
||||
|
||||
|
||||
void CalculateContacts();
|
||||
|
||||
CollisionShape* CreateShapeFromGeom(dGeomID);
|
||||
|
||||
///future support for Bullet broadphase + framework?
|
||||
virtual void ProcessCollision (BroadphaseProxy* proxy0,BroadphaseProxy* proxy1,const struct DispatcherInfo& dispatchInfo);
|
||||
|
||||
///future support for Bullet broadphase + framework?
|
||||
virtual float CalculateTimeOfImpact(BroadphaseProxy* proxy0,BroadphaseProxy* proxy1,const struct DispatcherInfo& dispatchInfo);
|
||||
};
|
||||
|
||||
#endif //BULLET_ODE_COLLISION_PAIR_H
|
||||
33
Extras/BulletOdeCollide/BulletOdeManifoldResult.cpp
Normal file
33
Extras/BulletOdeCollide/BulletOdeManifoldResult.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "BulletOdeManifoldResult.h"
|
||||
#include "NarrowPhaseCollision/PersistentManifold.h"
|
||||
#include "BulletOdeTransformConvert.h"
|
||||
|
||||
BulletOdeManifoldResult::BulletOdeManifoldResult(dGeomID geom1,dGeomID geom2,PersistentManifold* manifoldPtr)
|
||||
:m_manifoldPtr(manifoldPtr),
|
||||
m_geom1(geom1),
|
||||
m_geom2(geom2)
|
||||
{
|
||||
}
|
||||
|
||||
void BulletOdeManifoldResult::AddContactPoint(const SimdVector3& normalOnBInWorld,const SimdVector3& pointInWorld,float depth)
|
||||
{
|
||||
if (depth > m_manifoldPtr->GetManifoldMargin())
|
||||
return;
|
||||
|
||||
SimdTransform transAInv = GetTransformFromGeom(m_geom1).inverse();
|
||||
SimdTransform transBInv = GetTransformFromGeom(m_geom2).inverse();
|
||||
|
||||
SimdVector3 pointA = pointInWorld + normalOnBInWorld * depth;
|
||||
SimdVector3 localA = transAInv(pointA );
|
||||
SimdVector3 localB = transBInv(pointInWorld);
|
||||
ManifoldPoint newPt(localA,localB,normalOnBInWorld,depth);
|
||||
|
||||
int insertIndex = m_manifoldPtr->GetCacheEntry(newPt);
|
||||
if (insertIndex >= 0)
|
||||
{
|
||||
m_manifoldPtr->ReplaceContactPoint(newPt,insertIndex);
|
||||
} else
|
||||
{
|
||||
m_manifoldPtr->AddManifoldPoint(newPt);
|
||||
}
|
||||
}
|
||||
38
Extras/BulletOdeCollide/BulletOdeManifoldResult.h
Normal file
38
Extras/BulletOdeCollide/BulletOdeManifoldResult.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BULLET_ODE_MANIFOLD_RESULT_H
|
||||
#define BULLET_ODE_MANIFOLD_RESULT_H
|
||||
|
||||
#include "NarrowPhaseCollision/DiscreteCollisionDetectorInterface.h"
|
||||
class PersistentManifold;
|
||||
#include <ode/common.h>
|
||||
|
||||
class BulletOdeManifoldResult : public DiscreteCollisionDetectorInterface::Result
|
||||
{
|
||||
PersistentManifold* m_manifoldPtr;
|
||||
dGeomID m_geom1;
|
||||
dGeomID m_geom2;
|
||||
|
||||
public:
|
||||
|
||||
BulletOdeManifoldResult(dGeomID geom1,dGeomID geom2,PersistentManifold* manifoldPtr);
|
||||
|
||||
virtual void AddContactPoint(const SimdVector3& normalOnBInWorld,const SimdVector3& pointInWorld,float depth);
|
||||
|
||||
};
|
||||
|
||||
#endif //BULLET_ODE_MANIFOLD_RESULT_H
|
||||
39
Extras/BulletOdeCollide/BulletOdeTransformConvert.cpp
Normal file
39
Extras/BulletOdeCollide/BulletOdeTransformConvert.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "BulletOdeTransformConvert.h"
|
||||
#include "../ode/src/collision_kernel.h"
|
||||
|
||||
SimdTransform GetTransformFromGeom(dGeomID geom)
|
||||
{
|
||||
SimdTransform trans;
|
||||
trans.setIdentity();
|
||||
|
||||
|
||||
const dReal* pos = dGeomGetPosition (geom);// pointer to object's position vector
|
||||
const dReal* rot = dGeomGetRotation (geom);; // pointer to object's rotation matrix, 4*3 format!
|
||||
|
||||
SimdMatrix3x3 orn(rot[0],rot[1],rot[2],
|
||||
rot[4],rot[5],rot[6],
|
||||
rot[8],rot[9],rot[10]);
|
||||
|
||||
trans.setOrigin(SimdVector3(pos[0],pos[1],pos[2]));
|
||||
trans.setBasis(orn);
|
||||
|
||||
return trans;
|
||||
}
|
||||
|
||||
SimdTransform GetTransformFromBody(dBodyID body)
|
||||
{
|
||||
SimdTransform trans;
|
||||
|
||||
const dReal* pos = body->pos;
|
||||
const dReal* rot = body->R;
|
||||
|
||||
SimdMatrix3x3 orn(rot[0],rot[1],rot[2],
|
||||
rot[4],rot[5],rot[6],
|
||||
rot[8],rot[9],rot[10]);
|
||||
|
||||
trans.setOrigin(SimdVector3(pos[0],pos[1],pos[2]));
|
||||
trans.setBasis(orn);
|
||||
|
||||
return trans;
|
||||
|
||||
}
|
||||
10
Extras/BulletOdeCollide/BulletOdeTransformConvert.h
Normal file
10
Extras/BulletOdeCollide/BulletOdeTransformConvert.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef BULLET_ODE_TRANSFORM_CONVERT_H
|
||||
#define BULLET_ODE_TRANSFORM_CONVERT_H
|
||||
|
||||
#include "SimdTransform.h"
|
||||
#include <ode/common.h>
|
||||
|
||||
SimdTransform GetTransformFromGeom(dGeomID geom);
|
||||
SimdTransform GetTransformFromBody(dBodyID body);
|
||||
|
||||
#endif //BULLET_ODE_TRANSFORM_CONVERT_H
|
||||
70
Extras/BulletOdeCollide/GeomToShape.cpp
Normal file
70
Extras/BulletOdeCollide/GeomToShape.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
#include "CollisionShapes/SphereShape.h"
|
||||
#include "CollisionShapes/CylinderShape.h"
|
||||
#include "CollisionShapes/MultiSphereShape.h"//capped cylinder is convex hull of two spheres
|
||||
#include "CollisionShapes/ConvexTriangleCallback.h"
|
||||
#include "CollisionShapes/BoxShape.h"
|
||||
|
||||
//need access to internals to convert...
|
||||
#include <../ode/src/collision_kernel.h>
|
||||
|
||||
|
||||
CollisionShape* CreateShapeFromGeom(dGeomID geom)
|
||||
{
|
||||
CollisionShape* shape = 0;
|
||||
|
||||
switch (geom->type)
|
||||
{
|
||||
case dPlaneClass:
|
||||
break;
|
||||
case dBoxClass:
|
||||
{
|
||||
dVector3 size;
|
||||
dGeomBoxGetLengths (geom,size);
|
||||
SimdVector3 halfExtents(0.5f*size[0],0.5f*size[1],0.5f*size[2]);
|
||||
shape = new BoxShape(halfExtents);
|
||||
break;
|
||||
}
|
||||
case dSphereClass:
|
||||
{
|
||||
dVector3 size;
|
||||
shape = new SphereShape(dGeomSphereGetRadius(geom));
|
||||
break;
|
||||
}
|
||||
case dCylinderClass:
|
||||
{
|
||||
dVector3 size;
|
||||
dGeomBoxGetLengths (geom,size);
|
||||
SimdVector3 boxHalfExtents(size[0],size[0],size[1]);
|
||||
shape = new CylinderShapeZ(boxHalfExtents);
|
||||
break;
|
||||
}
|
||||
case dCCylinderClass:
|
||||
{
|
||||
dReal radius,length;
|
||||
dGeomCCylinderGetParams (geom, &radius, &length);
|
||||
SimdVector3 boxHalfExtents(radius,radius,0.5f*length);
|
||||
int numspheres = 2;
|
||||
SimdVector3 centers[2]={ SimdVector3(0,0,0.5f*length),SimdVector3(0,0,-0.5f*length)};
|
||||
SimdScalar radi[2]={radius,radius};
|
||||
shape = new MultiSphereShape(boxHalfExtents,centers,radi,numspheres);
|
||||
break;
|
||||
}
|
||||
/*case dTriMeshClass:
|
||||
{
|
||||
dxTriMesh* trimesh = (dxTriMesh*) geom;
|
||||
shape = 0;//new BVHTrimeshShape(trimesh);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
default:
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return shape;
|
||||
|
||||
}
|
||||
11
Extras/BulletOdeCollide/GeomToShape.h
Normal file
11
Extras/BulletOdeCollide/GeomToShape.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef GEOM_TO_SHAPE_H
|
||||
#define GEOM_TO_SHAPE_H
|
||||
|
||||
class CollisionShape;
|
||||
|
||||
//need internals to handle dGeomID
|
||||
#include <../ode/src/collision_kernel.h>
|
||||
|
||||
CollisionShape* CreateShapeFromGeom(dGeomID geom);
|
||||
|
||||
#endif //
|
||||
119
Extras/BulletOdeCollide/ode_bullet2005nov5.patch
Normal file
119
Extras/BulletOdeCollide/ode_bullet2005nov5.patch
Normal file
@@ -0,0 +1,119 @@
|
||||
? OPCODE/Debug
|
||||
? OPCODE/Opcode.vcproj
|
||||
? OPCODE/Release
|
||||
? VC6/Debug
|
||||
? VC6/Release
|
||||
? VC6/msvcdefs.def
|
||||
? VC6/ode.ncb
|
||||
? VC6/ode.vcproj
|
||||
? VC6/Samples/BuildLog.htm
|
||||
? VC6/Samples/DrawStuff.vcproj
|
||||
? VC6/Samples/DrawStuff_Debug
|
||||
? VC6/Samples/DrawStuff_Release
|
||||
? VC6/Samples/MakeAllTests.ncb
|
||||
? VC6/Samples/MakeAllTests.sln
|
||||
? VC6/Samples/MakeAllTests.suo
|
||||
? VC6/Samples/MakeAllTests.vcproj
|
||||
? VC6/Samples/Test_BoxStack.vcproj
|
||||
? VC6/Samples/Test_BoxStack_Debug
|
||||
? VC6/Samples/Test_BoxStack_Release
|
||||
? VC6/Samples/Test_Buggy.vcproj
|
||||
? VC6/Samples/Test_Chain1.vcproj
|
||||
? VC6/Samples/Test_Chain2.vcproj
|
||||
? VC6/Samples/Test_Collision.vcproj
|
||||
? VC6/Samples/Test_Friction.vcproj
|
||||
? VC6/Samples/Test_Hinge.vcproj
|
||||
? VC6/Samples/Test_I.vcproj
|
||||
? VC6/Samples/Test_Joints.vcproj
|
||||
? VC6/Samples/Test_MovingTrimesh.vcproj
|
||||
? VC6/Samples/Test_Ode.vcproj
|
||||
? VC6/Samples/Test_Slider.vcproj
|
||||
? VC6/Samples/Test_Space.vcproj
|
||||
? VC6/Samples/Test_Step.vcproj
|
||||
? VC6/Samples/Test_Trimesh.vcproj
|
||||
? VC6/Samples/Test_Trimesh_Debug
|
||||
? VC6/Samples/Test_Trimesh_Release
|
||||
? VC6/Samples/state.dif
|
||||
? include/ode/config.h
|
||||
? ode/test/test_trimesh_convex.cpp
|
||||
? ode/test/text_convex.cpp
|
||||
Index: include/ode/collision.h
|
||||
===================================================================
|
||||
RCS file: /cvsroot/opende/ode/include/ode/collision.h,v
|
||||
retrieving revision 1.9
|
||||
diff -u -r1.9 collision.h
|
||||
--- include/ode/collision.h 19 Jun 2004 15:44:22 -0000 1.9
|
||||
+++ include/ode/collision.h 6 Nov 2005 23:06:52 -0000
|
||||
@@ -84,6 +84,7 @@
|
||||
dRayClass,
|
||||
dGeomTransformClass,
|
||||
dTriMeshClass,
|
||||
+ dConvexClass,
|
||||
|
||||
dFirstSpaceClass,
|
||||
dSimpleSpaceClass = dFirstSpaceClass,
|
||||
Index: ode/src/collision_kernel.cpp
|
||||
===================================================================
|
||||
RCS file: /cvsroot/opende/ode/ode/src/collision_kernel.cpp,v
|
||||
retrieving revision 1.18
|
||||
diff -u -r1.18 collision_kernel.cpp
|
||||
--- ode/src/collision_kernel.cpp 19 Apr 2004 18:27:56 -0000 1.18
|
||||
+++ ode/src/collision_kernel.cpp 6 Nov 2005 23:10:02 -0000
|
||||
@@ -146,6 +146,17 @@
|
||||
setCollider (dTriMeshClass,dTriMeshClass,&dCollideTTL);
|
||||
setCollider (dTriMeshClass,dCCylinderClass,&dCollideCCTL);
|
||||
#endif
|
||||
+
|
||||
+#ifdef BULLET_CONVEX_SUPPORT
|
||||
+ ///see collision_convex.cpp
|
||||
+ setCollider (dConvexClass,dConvexClass,&dCollideConvexConvex);
|
||||
+ setCollider (dConvexClass,dPlaneClass,&dCollideConvexConvex);
|
||||
+ setCollider (dConvexClass,dBoxClass,&dCollideConvexConvex);
|
||||
+ setCollider (dConvexClass,dSphereClass,&dCollideConvexConvex);
|
||||
+ setCollider (dConvexClass,dCCylinderClass,&dCollideConvexConvex);
|
||||
+ setCollider( dTriMeshClass,dConvexClass, dCollideConvexConvex);
|
||||
+#endif //BULLET_CONVEX_SUPPORT
|
||||
+
|
||||
setAllColliders (dGeomTransformClass,&dCollideTransform);
|
||||
}
|
||||
|
||||
Index: ode/src/collision_std.h
|
||||
===================================================================
|
||||
RCS file: /cvsroot/opende/ode/ode/src/collision_std.h,v
|
||||
retrieving revision 1.2
|
||||
diff -u -r1.2 collision_std.h
|
||||
--- ode/src/collision_std.h 1 Dec 2002 06:13:42 -0000 1.2
|
||||
+++ ode/src/collision_std.h 6 Nov 2005 23:03:52 -0000
|
||||
@@ -37,6 +37,7 @@
|
||||
// the same interface as dCollide(). the first and second geom arguments must
|
||||
// have the specified types.
|
||||
|
||||
+
|
||||
int dCollideSphereSphere (dxGeom *o1, dxGeom *o2, int flags,
|
||||
dContactGeom *contact, int skip);
|
||||
int dCollideSphereBox (dxGeom *o1, dxGeom *o2, int flags,
|
||||
@@ -63,6 +64,9 @@
|
||||
int flags, dContactGeom *contact, int skip);
|
||||
int dCollideRayPlane (dxGeom *o1, dxGeom *o2, int flags,
|
||||
dContactGeom *contact, int skip);
|
||||
+///dCollideConvexConvex: see collision_convex.cpp for details
|
||||
+int dCollideConvexConvex(dxGeom *o1, dxGeom *o2, int flags,
|
||||
+ dContactGeom *contact, int skip);
|
||||
|
||||
|
||||
#endif
|
||||
Index: ode/src/collision_trimesh_internal.h
|
||||
===================================================================
|
||||
RCS file: /cvsroot/opende/ode/ode/src/collision_trimesh_internal.h,v
|
||||
retrieving revision 1.10
|
||||
diff -u -r1.10 collision_trimesh_internal.h
|
||||
--- ode/src/collision_trimesh_internal.h 21 Sep 2004 20:54:21 -0000 1.10
|
||||
+++ ode/src/collision_trimesh_internal.h 6 Nov 2005 23:04:52 -0000
|
||||
@@ -25,6 +25,7 @@
|
||||
#ifndef _ODE_COLLISION_TRIMESH_INTERNAL_H_
|
||||
#define _ODE_COLLISION_TRIMESH_INTERNAL_H_
|
||||
|
||||
+int dCollideTrimeshConvex(dxGeom* g1, dxGeom* cnvx, int Flags, dContactGeom* Contacts, int Stride);
|
||||
int dCollideSTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip);
|
||||
int dCollideBTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip);
|
||||
int dCollideRTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip);
|
||||
773
Extras/ConvexDecomposition/ConvexDecomposition.cpp
Normal file
773
Extras/ConvexDecomposition/ConvexDecomposition.cpp
Normal file
@@ -0,0 +1,773 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
#include "ConvexDecomposition.h"
|
||||
#include "cd_vector.h"
|
||||
#include "cd_hull.h"
|
||||
#include "bestfit.h"
|
||||
#include "PlaneTri.h"
|
||||
#include "vlookup.h"
|
||||
#include "splitplane.h"
|
||||
#include "meshvolume.h"
|
||||
#include "concavity.h"
|
||||
#include "bestfitobb.h"
|
||||
#include "float_math.h"
|
||||
#include "fitsphere.h"
|
||||
|
||||
#define SHOW_MESH 0
|
||||
#define MAKE_MESH 1
|
||||
|
||||
static unsigned int MAXDEPTH=8;
|
||||
static float CONCAVE_PERCENT=1.0f;
|
||||
static float MERGE_PERCENT=2.0f;
|
||||
|
||||
|
||||
using namespace ConvexDecomposition;
|
||||
|
||||
typedef std::vector< unsigned int > UintVector;
|
||||
|
||||
namespace ConvexDecomposition
|
||||
{
|
||||
|
||||
class FaceTri
|
||||
{
|
||||
public:
|
||||
FaceTri(void) { };
|
||||
FaceTri(const float *vertices,unsigned int i1,unsigned int i2,unsigned int i3)
|
||||
{
|
||||
mP1.Set( &vertices[i1*3] );
|
||||
mP2.Set( &vertices[i2*3] );
|
||||
mP3.Set( &vertices[i3*3] );
|
||||
}
|
||||
|
||||
Vector3d<float> mP1;
|
||||
Vector3d<float> mP2;
|
||||
Vector3d<float> mP3;
|
||||
Vector3d<float> mNormal;
|
||||
|
||||
};
|
||||
|
||||
|
||||
void addTri(VertexLookup vl,UintVector &list,const Vector3d<float> &p1,const Vector3d<float> &p2,const Vector3d<float> &p3)
|
||||
{
|
||||
unsigned int i1 = Vl_getIndex(vl, p1.Ptr() );
|
||||
unsigned int i2 = Vl_getIndex(vl, p2.Ptr() );
|
||||
unsigned int i3 = Vl_getIndex(vl, p3.Ptr() );
|
||||
|
||||
// do *not* process degenerate triangles!
|
||||
|
||||
if ( i1 != i2 && i1 != i3 && i2 != i3 )
|
||||
{
|
||||
list.push_back(i1);
|
||||
list.push_back(i2);
|
||||
list.push_back(i3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void doConvexDecomposition(unsigned int vcount,
|
||||
const float *vertices,
|
||||
unsigned int tcount,
|
||||
const unsigned int *indices,
|
||||
ConvexDecompInterface *callback,
|
||||
float masterVolume,
|
||||
unsigned int depth)
|
||||
|
||||
{
|
||||
|
||||
float plane[4];
|
||||
|
||||
bool split = false;
|
||||
|
||||
|
||||
if ( depth < MAXDEPTH )
|
||||
{
|
||||
|
||||
float volume;
|
||||
float c = computeConcavity( vcount, vertices, tcount, indices, callback, plane, volume );
|
||||
|
||||
if ( depth == 0 )
|
||||
{
|
||||
masterVolume = volume;
|
||||
}
|
||||
|
||||
float percent = (c*100.0f)/masterVolume;
|
||||
|
||||
if ( percent > CONCAVE_PERCENT ) // if great than 5% of the total volume is concave, go ahead and keep splitting.
|
||||
{
|
||||
split = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( depth >= MAXDEPTH || !split )
|
||||
{
|
||||
|
||||
#if 1
|
||||
|
||||
HullResult result;
|
||||
HullLibrary hl;
|
||||
HullDesc desc;
|
||||
|
||||
desc.SetHullFlag(QF_TRIANGLES);
|
||||
|
||||
desc.mVcount = vcount;
|
||||
desc.mVertices = vertices;
|
||||
desc.mVertexStride = sizeof(float)*3;
|
||||
|
||||
HullError ret = hl.CreateConvexHull(desc,result);
|
||||
|
||||
if ( ret == QE_OK )
|
||||
{
|
||||
|
||||
ConvexResult r(result.mNumOutputVertices, result.mOutputVertices, result.mNumFaces, result.mIndices);
|
||||
|
||||
|
||||
callback->ConvexDecompResult(r);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
static unsigned int colors[8] =
|
||||
{
|
||||
0xFF0000,
|
||||
0x00FF00,
|
||||
0x0000FF,
|
||||
0xFFFF00,
|
||||
0x00FFFF,
|
||||
0xFF00FF,
|
||||
0xFFFFFF,
|
||||
0xFF8040
|
||||
};
|
||||
|
||||
static int count = 0;
|
||||
|
||||
count++;
|
||||
|
||||
if ( count == 8 ) count = 0;
|
||||
|
||||
assert( count >= 0 && count < 8 );
|
||||
|
||||
unsigned int color = colors[count];
|
||||
|
||||
const unsigned int *source = indices;
|
||||
|
||||
for (unsigned int i=0; i<tcount; i++)
|
||||
{
|
||||
|
||||
unsigned int i1 = *source++;
|
||||
unsigned int i2 = *source++;
|
||||
unsigned int i3 = *source++;
|
||||
|
||||
FaceTri t(vertices, i1, i2, i3 );
|
||||
|
||||
callback->ConvexDebugTri( t.mP1.Ptr(), t.mP2.Ptr(), t.mP3.Ptr(), color );
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
UintVector ifront;
|
||||
UintVector iback;
|
||||
|
||||
VertexLookup vfront = Vl_createVertexLookup();
|
||||
VertexLookup vback = Vl_createVertexLookup();
|
||||
|
||||
|
||||
bool showmesh = false;
|
||||
#if SHOW_MESH
|
||||
showmesh = true;
|
||||
#endif
|
||||
|
||||
if ( 0 )
|
||||
{
|
||||
showmesh = true;
|
||||
for (float x=-1; x<1; x+=0.10f)
|
||||
{
|
||||
for (float y=0; y<1; y+=0.10f)
|
||||
{
|
||||
for (float z=-1; z<1; z+=0.04f)
|
||||
{
|
||||
float d = x*plane[0] + y*plane[1] + z*plane[2] + plane[3];
|
||||
Vector3d<float> p(x,y,z);
|
||||
if ( d >= 0 )
|
||||
callback->ConvexDebugPoint(p.Ptr(), 0.02f, 0x00FF00);
|
||||
else
|
||||
callback->ConvexDebugPoint(p.Ptr(), 0.02f, 0xFF0000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( 1 )
|
||||
{
|
||||
// ok..now we are going to 'split' all of the input triangles against this plane!
|
||||
const unsigned int *source = indices;
|
||||
for (unsigned int i=0; i<tcount; i++)
|
||||
{
|
||||
unsigned int i1 = *source++;
|
||||
unsigned int i2 = *source++;
|
||||
unsigned int i3 = *source++;
|
||||
|
||||
FaceTri t(vertices, i1, i2, i3 );
|
||||
|
||||
Vector3d<float> front[4];
|
||||
Vector3d<float> back[4];
|
||||
|
||||
unsigned int fcount=0;
|
||||
unsigned int bcount=0;
|
||||
|
||||
PlaneTriResult result;
|
||||
|
||||
result = planeTriIntersection(plane,t.mP1.Ptr(),sizeof(Vector3d<float>),0.00001f,front[0].Ptr(),fcount,back[0].Ptr(),bcount );
|
||||
|
||||
if( fcount > 4 || bcount > 4 )
|
||||
{
|
||||
result = planeTriIntersection(plane,t.mP1.Ptr(),sizeof(Vector3d<float>),0.00001f,front[0].Ptr(),fcount,back[0].Ptr(),bcount );
|
||||
}
|
||||
|
||||
switch ( result )
|
||||
{
|
||||
case PTR_FRONT:
|
||||
|
||||
assert( fcount == 3 );
|
||||
|
||||
if ( showmesh )
|
||||
callback->ConvexDebugTri( front[0].Ptr(), front[1].Ptr(), front[2].Ptr(), 0x00FF00 );
|
||||
|
||||
#if MAKE_MESH
|
||||
|
||||
addTri( vfront, ifront, front[0], front[1], front[2] );
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
break;
|
||||
case PTR_BACK:
|
||||
assert( bcount == 3 );
|
||||
|
||||
if ( showmesh )
|
||||
callback->ConvexDebugTri( back[0].Ptr(), back[1].Ptr(), back[2].Ptr(), 0xFFFF00 );
|
||||
|
||||
#if MAKE_MESH
|
||||
|
||||
addTri( vback, iback, back[0], back[1], back[2] );
|
||||
|
||||
#endif
|
||||
|
||||
break;
|
||||
case PTR_SPLIT:
|
||||
|
||||
assert( fcount >= 3 && fcount <= 4);
|
||||
assert( bcount >= 3 && bcount <= 4);
|
||||
|
||||
#if MAKE_MESH
|
||||
|
||||
addTri( vfront, ifront, front[0], front[1], front[2] );
|
||||
addTri( vback, iback, back[0], back[1], back[2] );
|
||||
|
||||
|
||||
if ( fcount == 4 )
|
||||
{
|
||||
addTri( vfront, ifront, front[0], front[2], front[3] );
|
||||
}
|
||||
|
||||
if ( bcount == 4 )
|
||||
{
|
||||
addTri( vback, iback, back[0], back[2], back[3] );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ( showmesh )
|
||||
{
|
||||
callback->ConvexDebugTri( front[0].Ptr(), front[1].Ptr(), front[2].Ptr(), 0x00D000 );
|
||||
callback->ConvexDebugTri( back[0].Ptr(), back[1].Ptr(), back[2].Ptr(), 0xD0D000 );
|
||||
|
||||
if ( fcount == 4 )
|
||||
{
|
||||
callback->ConvexDebugTri( front[0].Ptr(), front[2].Ptr(), front[3].Ptr(), 0x00D000 );
|
||||
}
|
||||
if ( bcount == 4 )
|
||||
{
|
||||
callback->ConvexDebugTri( back[0].Ptr(), back[2].Ptr(), back[3].Ptr(), 0xD0D000 );
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int fsize = ifront.size()/3;
|
||||
unsigned int bsize = iback.size()/3;
|
||||
|
||||
// ok... here we recursively call
|
||||
if ( ifront.size() )
|
||||
{
|
||||
unsigned int vcount = Vl_getVcount(vfront);
|
||||
const float *vertices = Vl_getVertices(vfront);
|
||||
unsigned int tcount = ifront.size()/3;
|
||||
|
||||
doConvexDecomposition(vcount, vertices, tcount, &ifront[0], callback, masterVolume, depth+1);
|
||||
|
||||
}
|
||||
|
||||
ifront.clear();
|
||||
|
||||
Vl_releaseVertexLookup(vfront);
|
||||
|
||||
if ( iback.size() )
|
||||
{
|
||||
unsigned int vcount = Vl_getVcount(vback);
|
||||
const float *vertices = Vl_getVertices(vback);
|
||||
unsigned int tcount = iback.size()/3;
|
||||
|
||||
doConvexDecomposition(vcount, vertices, tcount, &iback[0], callback, masterVolume, depth+1);
|
||||
|
||||
}
|
||||
|
||||
iback.clear();
|
||||
Vl_releaseVertexLookup(vback);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class CHull
|
||||
{
|
||||
public:
|
||||
CHull(const ConvexResult &result)
|
||||
{
|
||||
mResult = new ConvexResult(result);
|
||||
mVolume = computeMeshVolume( result.mHullVertices, result.mHullTcount, result.mHullIndices );
|
||||
|
||||
mDiagonal = getBoundingRegion( result.mHullVcount, result.mHullVertices, sizeof(float)*3, mMin, mMax );
|
||||
|
||||
float dx = mMax[0] - mMin[0];
|
||||
float dy = mMax[1] - mMin[1];
|
||||
float dz = mMax[2] - mMin[2];
|
||||
|
||||
dx*=0.1f; // inflate 1/10th on each edge
|
||||
dy*=0.1f; // inflate 1/10th on each edge
|
||||
dz*=0.1f; // inflate 1/10th on each edge
|
||||
|
||||
mMin[0]-=dx;
|
||||
mMin[1]-=dy;
|
||||
mMin[2]-=dz;
|
||||
|
||||
mMax[0]+=dx;
|
||||
mMax[1]+=dy;
|
||||
mMax[2]+=dz;
|
||||
|
||||
|
||||
}
|
||||
|
||||
~CHull(void)
|
||||
{
|
||||
delete mResult;
|
||||
}
|
||||
|
||||
bool overlap(const CHull &h) const
|
||||
{
|
||||
return overlapAABB(mMin,mMax, h.mMin, h.mMax );
|
||||
}
|
||||
|
||||
float mMin[3];
|
||||
float mMax[3];
|
||||
float mVolume;
|
||||
float mDiagonal; // long edge..
|
||||
ConvexResult *mResult;
|
||||
};
|
||||
|
||||
// Usage: std::sort( list.begin(), list.end(), StringSortRef() );
|
||||
class CHullSort
|
||||
{
|
||||
public:
|
||||
|
||||
bool operator()(const CHull *a,const CHull *b) const
|
||||
{
|
||||
return a->mVolume < b->mVolume;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector< CHull * > CHullVector;
|
||||
|
||||
|
||||
class ConvexBuilder : public ConvexDecompInterface
|
||||
{
|
||||
public:
|
||||
ConvexBuilder(ConvexDecompInterface *callback)
|
||||
{
|
||||
mCallback = callback;
|
||||
};
|
||||
|
||||
~ConvexBuilder(void)
|
||||
{
|
||||
CHullVector::iterator i;
|
||||
for (i=mChulls.begin(); i!=mChulls.end(); ++i)
|
||||
{
|
||||
CHull *cr = (*i);
|
||||
delete cr;
|
||||
}
|
||||
}
|
||||
|
||||
bool isDuplicate(unsigned int i1,unsigned int i2,unsigned int i3,
|
||||
unsigned int ci1,unsigned int ci2,unsigned int ci3)
|
||||
{
|
||||
unsigned int dcount = 0;
|
||||
|
||||
assert( i1 != i2 && i1 != i3 && i2 != i3 );
|
||||
assert( ci1 != ci2 && ci1 != ci3 && ci2 != ci3 );
|
||||
|
||||
if ( i1 == ci1 || i1 == ci2 || i1 == ci3 ) dcount++;
|
||||
if ( i2 == ci1 || i2 == ci2 || i2 == ci3 ) dcount++;
|
||||
if ( i3 == ci1 || i3 == ci2 || i3 == ci3 ) dcount++;
|
||||
|
||||
return dcount == 3;
|
||||
}
|
||||
|
||||
void getMesh(const ConvexResult &cr,VertexLookup vc,UintVector &indices)
|
||||
{
|
||||
unsigned int *src = cr.mHullIndices;
|
||||
|
||||
for (unsigned int i=0; i<cr.mHullTcount; i++)
|
||||
{
|
||||
unsigned int i1 = *src++;
|
||||
unsigned int i2 = *src++;
|
||||
unsigned int i3 = *src++;
|
||||
|
||||
const float *p1 = &cr.mHullVertices[i1*3];
|
||||
const float *p2 = &cr.mHullVertices[i2*3];
|
||||
const float *p3 = &cr.mHullVertices[i3*3];
|
||||
|
||||
i1 = Vl_getIndex(vc,p1);
|
||||
i2 = Vl_getIndex(vc,p2);
|
||||
i3 = Vl_getIndex(vc,p3);
|
||||
|
||||
#if 0
|
||||
bool duplicate = false;
|
||||
|
||||
unsigned int tcount = indices.size()/3;
|
||||
for (unsigned int j=0; j<tcount; j++)
|
||||
{
|
||||
unsigned int ci1 = indices[j*3+0];
|
||||
unsigned int ci2 = indices[j*3+1];
|
||||
unsigned int ci3 = indices[j*3+2];
|
||||
if ( isDuplicate(i1,i2,i3, ci1, ci2, ci3 ) )
|
||||
{
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !duplicate )
|
||||
{
|
||||
indices.push_back(i1);
|
||||
indices.push_back(i2);
|
||||
indices.push_back(i3);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
CHull * canMerge(CHull *a,CHull *b)
|
||||
{
|
||||
|
||||
if ( !a->overlap(*b) ) return 0; // if their AABB's (with a little slop) don't overlap, then return.
|
||||
|
||||
CHull *ret = 0;
|
||||
|
||||
// ok..we are going to combine both meshes into a single mesh
|
||||
// and then we are going to compute the concavity...
|
||||
|
||||
VertexLookup vc = Vl_createVertexLookup();
|
||||
|
||||
UintVector indices;
|
||||
|
||||
getMesh( *a->mResult, vc, indices );
|
||||
getMesh( *b->mResult, vc, indices );
|
||||
|
||||
unsigned int vcount = Vl_getVcount(vc);
|
||||
const float *vertices = Vl_getVertices(vc);
|
||||
unsigned int tcount = indices.size()/3;
|
||||
unsigned int *idx = &indices[0];
|
||||
|
||||
HullResult hresult;
|
||||
HullLibrary hl;
|
||||
HullDesc desc;
|
||||
|
||||
desc.SetHullFlag(QF_TRIANGLES);
|
||||
|
||||
desc.mVcount = vcount;
|
||||
desc.mVertices = vertices;
|
||||
desc.mVertexStride = sizeof(float)*3;
|
||||
|
||||
HullError hret = hl.CreateConvexHull(desc,hresult);
|
||||
|
||||
if ( hret == QE_OK )
|
||||
{
|
||||
|
||||
float combineVolume = computeMeshVolume( hresult.mOutputVertices, hresult.mNumFaces, hresult.mIndices );
|
||||
float sumVolume = a->mVolume + b->mVolume;
|
||||
|
||||
float percent = (sumVolume*100) / combineVolume;
|
||||
if ( percent >= (100.0f-MERGE_PERCENT) )
|
||||
{
|
||||
ConvexResult cr(hresult.mNumOutputVertices, hresult.mOutputVertices, hresult.mNumFaces, hresult.mIndices);
|
||||
ret = new CHull(cr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vl_releaseVertexLookup(vc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool combineHulls(void)
|
||||
{
|
||||
|
||||
bool combine = false;
|
||||
|
||||
sortChulls(mChulls); // sort the convex hulls, largest volume to least...
|
||||
|
||||
CHullVector output; // the output hulls...
|
||||
|
||||
|
||||
CHullVector::iterator i;
|
||||
|
||||
for (i=mChulls.begin(); i!=mChulls.end() && !combine; ++i)
|
||||
{
|
||||
CHull *cr = (*i);
|
||||
|
||||
CHullVector::iterator j;
|
||||
for (j=mChulls.begin(); j!=mChulls.end(); ++j)
|
||||
{
|
||||
CHull *match = (*j);
|
||||
|
||||
if ( cr != match ) // don't try to merge a hull with itself, that be stoopid
|
||||
{
|
||||
|
||||
CHull *merge = canMerge(cr,match); // if we can merge these two....
|
||||
|
||||
if ( merge )
|
||||
{
|
||||
|
||||
output.push_back(merge);
|
||||
|
||||
|
||||
++i;
|
||||
while ( i != mChulls.end() )
|
||||
{
|
||||
CHull *cr = (*i);
|
||||
if ( cr != match )
|
||||
{
|
||||
output.push_back(cr);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
delete cr;
|
||||
delete match;
|
||||
combine = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( combine )
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
output.push_back(cr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( combine )
|
||||
{
|
||||
mChulls.clear();
|
||||
mChulls = output;
|
||||
output.clear();
|
||||
}
|
||||
|
||||
|
||||
return combine;
|
||||
}
|
||||
|
||||
unsigned int process(const DecompDesc &desc)
|
||||
{
|
||||
|
||||
unsigned int ret = 0;
|
||||
|
||||
MAXDEPTH = desc.mDepth;
|
||||
CONCAVE_PERCENT = desc.mCpercent;
|
||||
MERGE_PERCENT = desc.mPpercent;
|
||||
|
||||
|
||||
doConvexDecomposition(desc.mVcount, desc.mVertices, desc.mTcount, desc.mIndices,this,0,0);
|
||||
|
||||
|
||||
while ( combineHulls() ); // keep combinging hulls until I can't combine any more...
|
||||
|
||||
CHullVector::iterator i;
|
||||
for (i=mChulls.begin(); i!=mChulls.end(); ++i)
|
||||
{
|
||||
CHull *cr = (*i);
|
||||
|
||||
// before we hand it back to the application, we need to regenerate the hull based on the
|
||||
// limits given by the user.
|
||||
|
||||
const ConvexResult &c = *cr->mResult; // the high resolution hull...
|
||||
|
||||
HullResult result;
|
||||
HullLibrary hl;
|
||||
HullDesc hdesc;
|
||||
|
||||
hdesc.SetHullFlag(QF_TRIANGLES);
|
||||
|
||||
hdesc.mVcount = c.mHullVcount;
|
||||
hdesc.mVertices = c.mHullVertices;
|
||||
hdesc.mVertexStride = sizeof(float)*3;
|
||||
hdesc.mMaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output
|
||||
|
||||
if ( desc.mSkinWidth > 0 )
|
||||
{
|
||||
hdesc.mSkinWidth = desc.mSkinWidth;
|
||||
hdesc.SetHullFlag(QF_SKIN_WIDTH); // do skin width computation.
|
||||
}
|
||||
|
||||
HullError ret = hl.CreateConvexHull(hdesc,result);
|
||||
|
||||
if ( ret == QE_OK )
|
||||
{
|
||||
ConvexResult r(result.mNumOutputVertices, result.mOutputVertices, result.mNumFaces, result.mIndices);
|
||||
|
||||
r.mHullVolume = computeMeshVolume( result.mOutputVertices, result.mNumFaces, result.mIndices ); // the volume of the hull.
|
||||
|
||||
// compute the best fit OBB
|
||||
computeBestFitOBB( result.mNumOutputVertices, result.mOutputVertices, sizeof(float)*3, r.mOBBSides, r.mOBBTransform );
|
||||
|
||||
r.mOBBVolume = r.mOBBSides[0] * r.mOBBSides[1] *r.mOBBSides[2]; // compute the OBB volume.
|
||||
|
||||
fm_getTranslation( r.mOBBTransform, r.mOBBCenter ); // get the translation component of the 4x4 matrix.
|
||||
|
||||
fm_matrixToQuat( r.mOBBTransform, r.mOBBOrientation ); // extract the orientation as a quaternion.
|
||||
|
||||
r.mSphereRadius = computeBoundingSphere( result.mNumOutputVertices, result.mOutputVertices, r.mSphereCenter );
|
||||
r.mSphereVolume = fm_sphereVolume( r.mSphereRadius );
|
||||
|
||||
|
||||
mCallback->ConvexDecompResult(r);
|
||||
}
|
||||
|
||||
|
||||
delete cr;
|
||||
}
|
||||
|
||||
ret = mChulls.size();
|
||||
|
||||
mChulls.clear();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
virtual void ConvexDebugTri(const float *p1,const float *p2,const float *p3,unsigned int color)
|
||||
{
|
||||
mCallback->ConvexDebugTri(p1,p2,p3,color);
|
||||
}
|
||||
|
||||
virtual void ConvexDebugOBB(const float *sides, const float *matrix,unsigned int color)
|
||||
{
|
||||
mCallback->ConvexDebugOBB(sides,matrix,color);
|
||||
}
|
||||
virtual void ConvexDebugPoint(const float *p,float dist,unsigned int color)
|
||||
{
|
||||
mCallback->ConvexDebugPoint(p,dist,color);
|
||||
}
|
||||
|
||||
virtual void ConvexDebugBound(const float *bmin,const float *bmax,unsigned int color)
|
||||
{
|
||||
mCallback->ConvexDebugBound(bmin,bmax,color);
|
||||
}
|
||||
|
||||
virtual void ConvexDecompResult(ConvexResult &result)
|
||||
{
|
||||
CHull *ch = new CHull(result);
|
||||
mChulls.push_back(ch);
|
||||
}
|
||||
|
||||
void sortChulls(CHullVector &hulls)
|
||||
{
|
||||
std::sort( hulls.begin(), hulls.end(), CHullSort() );
|
||||
}
|
||||
|
||||
CHullVector mChulls;
|
||||
ConvexDecompInterface *mCallback;
|
||||
|
||||
};
|
||||
|
||||
unsigned int performConvexDecomposition(const DecompDesc &desc)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
if ( desc.mCallback )
|
||||
{
|
||||
ConvexBuilder cb(desc.mCallback);
|
||||
|
||||
ret = cb.process(desc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
192
Extras/ConvexDecomposition/ConvexDecomposition.h
Normal file
192
Extras/ConvexDecomposition/ConvexDecomposition.h
Normal file
@@ -0,0 +1,192 @@
|
||||
#ifndef CONVEX_DECOMPOSITION_H
|
||||
|
||||
#define CONVEX_DECOMPOSITION_H
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
|
||||
namespace ConvexDecomposition
|
||||
{
|
||||
|
||||
class ConvexResult
|
||||
{
|
||||
public:
|
||||
ConvexResult(void)
|
||||
{
|
||||
mHullVcount = 0;
|
||||
mHullVertices = 0;
|
||||
mHullTcount = 0;
|
||||
mHullIndices = 0;
|
||||
}
|
||||
|
||||
ConvexResult(unsigned int hvcount,const float *hvertices,unsigned int htcount,const unsigned int *hindices)
|
||||
{
|
||||
mHullVcount = hvcount;
|
||||
if ( mHullVcount )
|
||||
{
|
||||
mHullVertices = new float[mHullVcount*sizeof(float)*3];
|
||||
memcpy(mHullVertices, hvertices, sizeof(float)*3*mHullVcount );
|
||||
}
|
||||
else
|
||||
{
|
||||
mHullVertices = 0;
|
||||
}
|
||||
|
||||
mHullTcount = htcount;
|
||||
|
||||
if ( mHullTcount )
|
||||
{
|
||||
mHullIndices = new unsigned int[sizeof(unsigned int)*mHullTcount*3];
|
||||
memcpy(mHullIndices,hindices, sizeof(unsigned int)*mHullTcount*3 );
|
||||
}
|
||||
else
|
||||
{
|
||||
mHullIndices = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ConvexResult(const ConvexResult &r)
|
||||
{
|
||||
mHullVcount = r.mHullVcount;
|
||||
if ( mHullVcount )
|
||||
{
|
||||
mHullVertices = new float[mHullVcount*sizeof(float)*3];
|
||||
memcpy(mHullVertices, r.mHullVertices, sizeof(float)*3*mHullVcount );
|
||||
}
|
||||
else
|
||||
{
|
||||
mHullVertices = 0;
|
||||
}
|
||||
mHullTcount = r.mHullTcount;
|
||||
if ( mHullTcount )
|
||||
{
|
||||
mHullIndices = new unsigned int[sizeof(unsigned int)*mHullTcount*3];
|
||||
memcpy(mHullIndices, r.mHullIndices, sizeof(unsigned int)*mHullTcount*3 );
|
||||
}
|
||||
else
|
||||
{
|
||||
mHullIndices = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~ConvexResult(void)
|
||||
{
|
||||
delete mHullVertices;
|
||||
delete mHullIndices;
|
||||
}
|
||||
|
||||
// the convex hull.
|
||||
unsigned int mHullVcount;
|
||||
float * mHullVertices;
|
||||
unsigned int mHullTcount;
|
||||
unsigned int *mHullIndices;
|
||||
|
||||
float mHullVolume; // the volume of the convex hull.
|
||||
|
||||
float mOBBSides[3]; // the width, height and breadth of the best fit OBB
|
||||
float mOBBCenter[3]; // the center of the OBB
|
||||
float mOBBOrientation[4]; // the quaternion rotation of the OBB.
|
||||
float mOBBTransform[16]; // the 4x4 transform of the OBB.
|
||||
float mOBBVolume; // the volume of the OBB
|
||||
|
||||
float mSphereRadius; // radius and center of best fit sphere
|
||||
float mSphereCenter[3];
|
||||
float mSphereVolume; // volume of the best fit sphere
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
class ConvexDecompInterface
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void ConvexDebugTri(const float *p1,const float *p2,const float *p3,unsigned int color) { };
|
||||
virtual void ConvexDebugPoint(const float *p,float dist,unsigned int color) { };
|
||||
virtual void ConvexDebugBound(const float *bmin,const float *bmax,unsigned int color) { };
|
||||
virtual void ConvexDebugOBB(const float *sides, const float *matrix,unsigned int color) { };
|
||||
|
||||
virtual void ConvexDecompResult(ConvexResult &result) = 0;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
// just to avoid passing a zillion parameters to the method the
|
||||
// options are packed into this descriptor.
|
||||
class DecompDesc
|
||||
{
|
||||
public:
|
||||
DecompDesc(void)
|
||||
{
|
||||
mVcount = 0;
|
||||
mVertices = 0;
|
||||
mTcount = 0;
|
||||
mIndices = 0;
|
||||
mDepth = 5;
|
||||
mCpercent = 5;
|
||||
mPpercent = 5;
|
||||
mMaxVertices = 32;
|
||||
mSkinWidth = 0;
|
||||
mCallback = 0;
|
||||
}
|
||||
|
||||
// describes the input triangle.
|
||||
unsigned int mVcount; // the number of vertices in the source mesh.
|
||||
const float *mVertices; // start of the vertex position array. Assumes a stride of 3 floats.
|
||||
unsigned int mTcount; // the number of triangles in the source mesh.
|
||||
unsigned int *mIndices; // the indexed triangle list array (zero index based)
|
||||
|
||||
// options
|
||||
unsigned int mDepth; // depth to split, a maximum of 10, generally not over 7.
|
||||
float mCpercent; // the concavity threshold percentage. 0=20 is reasonable.
|
||||
float mPpercent; // the percentage volume conservation threshold to collapse hulls. 0-30 is reasonable.
|
||||
|
||||
// hull output limits.
|
||||
unsigned int mMaxVertices; // maximum number of vertices in the output hull. Recommended 32 or less.
|
||||
float mSkinWidth; // a skin width to apply to the output hulls.
|
||||
|
||||
ConvexDecompInterface *mCallback; // the interface to receive back the results.
|
||||
|
||||
};
|
||||
|
||||
// perform approximate convex decomposition on a mesh.
|
||||
unsigned int performConvexDecomposition(const DecompDesc &desc); // returns the number of hulls produced.
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
465
Extras/ConvexDecomposition/bestfit.cpp
Normal file
465
Extras/ConvexDecomposition/bestfit.cpp
Normal file
@@ -0,0 +1,465 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
// Geometric Tools, Inc.
|
||||
// http://www.geometrictools.com
|
||||
// Copyright (c) 1998-2006. All Rights Reserved
|
||||
//
|
||||
// The Wild Magic Library (WM3) source code is supplied under the terms of
|
||||
// the license agreement
|
||||
// http://www.geometrictools.com/License/WildMagic3License.pdf
|
||||
// and may not be copied or disclosed except in accordance with the terms
|
||||
// of that agreement.
|
||||
|
||||
#include "bestfit.h"
|
||||
|
||||
namespace BestFit
|
||||
{
|
||||
|
||||
class Vec3
|
||||
{
|
||||
public:
|
||||
Vec3(void) { };
|
||||
Vec3(float _x,float _y,float _z) { x = _x; y = _y; z = _z; };
|
||||
|
||||
|
||||
float dot(const Vec3 &v)
|
||||
{
|
||||
return x*v.x + y*v.y + z*v.z; // the dot product
|
||||
}
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
|
||||
|
||||
class Eigen
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
void DecrSortEigenStuff(void)
|
||||
{
|
||||
Tridiagonal(); //diagonalize the matrix.
|
||||
QLAlgorithm(); //
|
||||
DecreasingSort();
|
||||
GuaranteeRotation();
|
||||
}
|
||||
|
||||
void Tridiagonal(void)
|
||||
{
|
||||
float fM00 = mElement[0][0];
|
||||
float fM01 = mElement[0][1];
|
||||
float fM02 = mElement[0][2];
|
||||
float fM11 = mElement[1][1];
|
||||
float fM12 = mElement[1][2];
|
||||
float fM22 = mElement[2][2];
|
||||
|
||||
m_afDiag[0] = fM00;
|
||||
m_afSubd[2] = 0;
|
||||
if (fM02 != (float)0.0)
|
||||
{
|
||||
float fLength = sqrtf(fM01*fM01+fM02*fM02);
|
||||
float fInvLength = ((float)1.0)/fLength;
|
||||
fM01 *= fInvLength;
|
||||
fM02 *= fInvLength;
|
||||
float fQ = ((float)2.0)*fM01*fM12+fM02*(fM22-fM11);
|
||||
m_afDiag[1] = fM11+fM02*fQ;
|
||||
m_afDiag[2] = fM22-fM02*fQ;
|
||||
m_afSubd[0] = fLength;
|
||||
m_afSubd[1] = fM12-fM01*fQ;
|
||||
mElement[0][0] = (float)1.0;
|
||||
mElement[0][1] = (float)0.0;
|
||||
mElement[0][2] = (float)0.0;
|
||||
mElement[1][0] = (float)0.0;
|
||||
mElement[1][1] = fM01;
|
||||
mElement[1][2] = fM02;
|
||||
mElement[2][0] = (float)0.0;
|
||||
mElement[2][1] = fM02;
|
||||
mElement[2][2] = -fM01;
|
||||
m_bIsRotation = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_afDiag[1] = fM11;
|
||||
m_afDiag[2] = fM22;
|
||||
m_afSubd[0] = fM01;
|
||||
m_afSubd[1] = fM12;
|
||||
mElement[0][0] = (float)1.0;
|
||||
mElement[0][1] = (float)0.0;
|
||||
mElement[0][2] = (float)0.0;
|
||||
mElement[1][0] = (float)0.0;
|
||||
mElement[1][1] = (float)1.0;
|
||||
mElement[1][2] = (float)0.0;
|
||||
mElement[2][0] = (float)0.0;
|
||||
mElement[2][1] = (float)0.0;
|
||||
mElement[2][2] = (float)1.0;
|
||||
m_bIsRotation = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool QLAlgorithm(void)
|
||||
{
|
||||
const int iMaxIter = 32;
|
||||
|
||||
for (int i0 = 0; i0 <3; i0++)
|
||||
{
|
||||
int i1;
|
||||
for (i1 = 0; i1 < iMaxIter; i1++)
|
||||
{
|
||||
int i2;
|
||||
for (i2 = i0; i2 <= (3-2); i2++)
|
||||
{
|
||||
float fTmp = fabsf(m_afDiag[i2]) + fabsf(m_afDiag[i2+1]);
|
||||
if ( fabsf(m_afSubd[i2]) + fTmp == fTmp )
|
||||
break;
|
||||
}
|
||||
if (i2 == i0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
float fG = (m_afDiag[i0+1] - m_afDiag[i0])/(((float)2.0) * m_afSubd[i0]);
|
||||
float fR = sqrtf(fG*fG+(float)1.0);
|
||||
if (fG < (float)0.0)
|
||||
{
|
||||
fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG-fR);
|
||||
}
|
||||
else
|
||||
{
|
||||
fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG+fR);
|
||||
}
|
||||
float fSin = (float)1.0, fCos = (float)1.0, fP = (float)0.0;
|
||||
for (int i3 = i2-1; i3 >= i0; i3--)
|
||||
{
|
||||
float fF = fSin*m_afSubd[i3];
|
||||
float fB = fCos*m_afSubd[i3];
|
||||
if (fabsf(fF) >= fabsf(fG))
|
||||
{
|
||||
fCos = fG/fF;
|
||||
fR = sqrtf(fCos*fCos+(float)1.0);
|
||||
m_afSubd[i3+1] = fF*fR;
|
||||
fSin = ((float)1.0)/fR;
|
||||
fCos *= fSin;
|
||||
}
|
||||
else
|
||||
{
|
||||
fSin = fF/fG;
|
||||
fR = sqrtf(fSin*fSin+(float)1.0);
|
||||
m_afSubd[i3+1] = fG*fR;
|
||||
fCos = ((float)1.0)/fR;
|
||||
fSin *= fCos;
|
||||
}
|
||||
fG = m_afDiag[i3+1]-fP;
|
||||
fR = (m_afDiag[i3]-fG)*fSin+((float)2.0)*fB*fCos;
|
||||
fP = fSin*fR;
|
||||
m_afDiag[i3+1] = fG+fP;
|
||||
fG = fCos*fR-fB;
|
||||
for (int i4 = 0; i4 < 3; i4++)
|
||||
{
|
||||
fF = mElement[i4][i3+1];
|
||||
mElement[i4][i3+1] = fSin*mElement[i4][i3]+fCos*fF;
|
||||
mElement[i4][i3] = fCos*mElement[i4][i3]-fSin*fF;
|
||||
}
|
||||
}
|
||||
m_afDiag[i0] -= fP;
|
||||
m_afSubd[i0] = fG;
|
||||
m_afSubd[i2] = (float)0.0;
|
||||
}
|
||||
if (i1 == iMaxIter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DecreasingSort(void)
|
||||
{
|
||||
//sort eigenvalues in decreasing order, e[0] >= ... >= e[iSize-1]
|
||||
for (int i0 = 0, i1; i0 <= 3-2; i0++)
|
||||
{
|
||||
// locate maximum eigenvalue
|
||||
i1 = i0;
|
||||
float fMax = m_afDiag[i1];
|
||||
int i2;
|
||||
for (i2 = i0+1; i2 < 3; i2++)
|
||||
{
|
||||
if (m_afDiag[i2] > fMax)
|
||||
{
|
||||
i1 = i2;
|
||||
fMax = m_afDiag[i1];
|
||||
}
|
||||
}
|
||||
|
||||
if (i1 != i0)
|
||||
{
|
||||
// swap eigenvalues
|
||||
m_afDiag[i1] = m_afDiag[i0];
|
||||
m_afDiag[i0] = fMax;
|
||||
// swap eigenvectors
|
||||
for (i2 = 0; i2 < 3; i2++)
|
||||
{
|
||||
float fTmp = mElement[i2][i0];
|
||||
mElement[i2][i0] = mElement[i2][i1];
|
||||
mElement[i2][i1] = fTmp;
|
||||
m_bIsRotation = !m_bIsRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GuaranteeRotation(void)
|
||||
{
|
||||
if (!m_bIsRotation)
|
||||
{
|
||||
// change sign on the first column
|
||||
for (int iRow = 0; iRow <3; iRow++)
|
||||
{
|
||||
mElement[iRow][0] = -mElement[iRow][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float mElement[3][3];
|
||||
float m_afDiag[3];
|
||||
float m_afSubd[3];
|
||||
bool m_bIsRotation;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
using namespace BestFit;
|
||||
|
||||
|
||||
bool getBestFitPlane(unsigned int vcount,
|
||||
const float *points,
|
||||
unsigned int vstride,
|
||||
const float *weights,
|
||||
unsigned int wstride,
|
||||
float *plane)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
Vec3 kOrigin(0,0,0);
|
||||
|
||||
float wtotal = 0;
|
||||
|
||||
if ( 1 )
|
||||
{
|
||||
const char *source = (const char *) points;
|
||||
const char *wsource = (const char *) weights;
|
||||
|
||||
for (unsigned int i=0; i<vcount; i++)
|
||||
{
|
||||
|
||||
const float *p = (const float *) source;
|
||||
|
||||
float w = 1;
|
||||
|
||||
if ( wsource )
|
||||
{
|
||||
const float *ws = (const float *) wsource;
|
||||
w = *ws; //
|
||||
wsource+=wstride;
|
||||
}
|
||||
|
||||
kOrigin.x+=p[0]*w;
|
||||
kOrigin.y+=p[1]*w;
|
||||
kOrigin.z+=p[2]*w;
|
||||
|
||||
wtotal+=w;
|
||||
|
||||
source+=vstride;
|
||||
}
|
||||
}
|
||||
|
||||
float recip = 1.0f / wtotal; // reciprocol of total weighting
|
||||
|
||||
kOrigin.x*=recip;
|
||||
kOrigin.y*=recip;
|
||||
kOrigin.z*=recip;
|
||||
|
||||
|
||||
float fSumXX=0;
|
||||
float fSumXY=0;
|
||||
float fSumXZ=0;
|
||||
|
||||
float fSumYY=0;
|
||||
float fSumYZ=0;
|
||||
float fSumZZ=0;
|
||||
|
||||
|
||||
if ( 1 )
|
||||
{
|
||||
const char *source = (const char *) points;
|
||||
const char *wsource = (const char *) weights;
|
||||
|
||||
for (unsigned int i=0; i<vcount; i++)
|
||||
{
|
||||
|
||||
const float *p = (const float *) source;
|
||||
|
||||
float w = 1;
|
||||
|
||||
if ( wsource )
|
||||
{
|
||||
const float *ws = (const float *) wsource;
|
||||
w = *ws; //
|
||||
wsource+=wstride;
|
||||
}
|
||||
|
||||
Vec3 kDiff;
|
||||
|
||||
kDiff.x = w*(p[0] - kOrigin.x); // apply vertex weighting!
|
||||
kDiff.y = w*(p[1] - kOrigin.y);
|
||||
kDiff.z = w*(p[2] - kOrigin.z);
|
||||
|
||||
fSumXX+= kDiff.x * kDiff.x; // sume of the squares of the differences.
|
||||
fSumXY+= kDiff.x * kDiff.y; // sume of the squares of the differences.
|
||||
fSumXZ+= kDiff.x * kDiff.z; // sume of the squares of the differences.
|
||||
|
||||
fSumYY+= kDiff.y * kDiff.y;
|
||||
fSumYZ+= kDiff.y * kDiff.z;
|
||||
fSumZZ+= kDiff.z * kDiff.z;
|
||||
|
||||
|
||||
source+=vstride;
|
||||
}
|
||||
}
|
||||
|
||||
fSumXX *= recip;
|
||||
fSumXY *= recip;
|
||||
fSumXZ *= recip;
|
||||
fSumYY *= recip;
|
||||
fSumYZ *= recip;
|
||||
fSumZZ *= recip;
|
||||
|
||||
// setup the eigensolver
|
||||
Eigen kES;
|
||||
|
||||
kES.mElement[0][0] = fSumXX;
|
||||
kES.mElement[0][1] = fSumXY;
|
||||
kES.mElement[0][2] = fSumXZ;
|
||||
|
||||
kES.mElement[1][0] = fSumXY;
|
||||
kES.mElement[1][1] = fSumYY;
|
||||
kES.mElement[1][2] = fSumYZ;
|
||||
|
||||
kES.mElement[2][0] = fSumXZ;
|
||||
kES.mElement[2][1] = fSumYZ;
|
||||
kES.mElement[2][2] = fSumZZ;
|
||||
|
||||
// compute eigenstuff, smallest eigenvalue is in last position
|
||||
kES.DecrSortEigenStuff();
|
||||
|
||||
Vec3 kNormal;
|
||||
|
||||
kNormal.x = kES.mElement[0][2];
|
||||
kNormal.y = kES.mElement[1][2];
|
||||
kNormal.z = kES.mElement[2][2];
|
||||
|
||||
// the minimum energy
|
||||
plane[0] = kNormal.x;
|
||||
plane[1] = kNormal.y;
|
||||
plane[2] = kNormal.z;
|
||||
|
||||
plane[3] = 0 - kNormal.dot(kOrigin);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
float getBoundingRegion(unsigned int vcount,const float *points,unsigned int pstride,float *bmin,float *bmax) // returns the diagonal distance
|
||||
{
|
||||
|
||||
const unsigned char *source = (const unsigned char *) points;
|
||||
|
||||
bmin[0] = points[0];
|
||||
bmin[1] = points[1];
|
||||
bmin[2] = points[2];
|
||||
|
||||
bmax[0] = points[0];
|
||||
bmax[1] = points[1];
|
||||
bmax[2] = points[2];
|
||||
|
||||
|
||||
for (unsigned int i=1; i<vcount; i++)
|
||||
{
|
||||
source+=pstride;
|
||||
const float *p = (const float *) source;
|
||||
|
||||
if ( p[0] < bmin[0] ) bmin[0] = p[0];
|
||||
if ( p[1] < bmin[1] ) bmin[1] = p[1];
|
||||
if ( p[2] < bmin[2] ) bmin[2] = p[2];
|
||||
|
||||
if ( p[0] > bmax[0] ) bmax[0] = p[0];
|
||||
if ( p[1] > bmax[1] ) bmax[1] = p[1];
|
||||
if ( p[2] > bmax[2] ) bmax[2] = p[2];
|
||||
|
||||
}
|
||||
|
||||
float dx = bmax[0] - bmin[0];
|
||||
float dy = bmax[1] - bmin[1];
|
||||
float dz = bmax[2] - bmin[2];
|
||||
|
||||
return sqrtf( dx*dx + dy*dy + dz*dz );
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool overlapAABB(const float *bmin1,const float *bmax1,const float *bmin2,const float *bmax2) // return true if the two AABB's overlap.
|
||||
{
|
||||
if ( bmax2[0] < bmin1[0] ) return false; // if the maximum is less than our minimum on any axis
|
||||
if ( bmax2[1] < bmin1[1] ) return false;
|
||||
if ( bmax2[2] < bmin1[2] ) return false;
|
||||
|
||||
if ( bmin2[0] > bmax1[0] ) return false; // if the minimum is greater than our maximum on any axis
|
||||
if ( bmin2[1] > bmax1[1] ) return false; // if the minimum is greater than our maximum on any axis
|
||||
if ( bmin2[2] > bmax1[2] ) return false; // if the minimum is greater than our maximum on any axis
|
||||
|
||||
|
||||
return true; // the extents overlap
|
||||
}
|
||||
|
||||
|
||||
65
Extras/ConvexDecomposition/bestfit.h
Normal file
65
Extras/ConvexDecomposition/bestfit.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef BEST_FIT_H
|
||||
|
||||
#define BEST_FIT_H
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
// This routine was released in 'snippet' form
|
||||
// by John W. Ratcliff mailto:jratcliff@infiniplex.net
|
||||
// on March 22, 2006.
|
||||
//
|
||||
// This routine computes the 'best fit' plane equation to
|
||||
// a set of input data points with an optional per vertex
|
||||
// weighting component.
|
||||
//
|
||||
// The implementation for this was lifted directly from
|
||||
// David Eberly's Magic Software implementation.
|
||||
|
||||
// computes the best fit plane to a collection of data points.
|
||||
// returns the plane equation as A,B,C,D format. (Ax+By+Cz+D)
|
||||
|
||||
bool getBestFitPlane(unsigned int vcount, // number of input data points
|
||||
const float *points, // starting address of points array.
|
||||
unsigned int vstride, // stride between input points.
|
||||
const float *weights, // *optional point weighting values.
|
||||
unsigned int wstride, // weight stride for each vertex.
|
||||
float *plane);
|
||||
|
||||
|
||||
float getBoundingRegion(unsigned int vcount,const float *points,unsigned int pstride,float *bmin,float *bmax); // returns the diagonal distance
|
||||
bool overlapAABB(const float *bmin1,const float *bmax1,const float *bmin2,const float *bmax2); // return true if the two AABB's overlap.
|
||||
|
||||
#endif
|
||||
171
Extras/ConvexDecomposition/bestfitobb.cpp
Normal file
171
Extras/ConvexDecomposition/bestfitobb.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
#include "bestfitobb.h"
|
||||
#include "float_math.h"
|
||||
|
||||
// computes the OBB for this set of points relative to this transform matrix.
|
||||
void computeOBB(unsigned int vcount,const float *points,unsigned int pstride,float *sides,const float *matrix)
|
||||
{
|
||||
const char *src = (const char *) points;
|
||||
|
||||
float bmin[3] = { 1e9, 1e9, 1e9 };
|
||||
float bmax[3] = { -1e9, -1e9, -1e9 };
|
||||
|
||||
for (unsigned int i=0; i<vcount; i++)
|
||||
{
|
||||
const float *p = (const float *) src;
|
||||
float t[3];
|
||||
|
||||
fm_inverseRT(matrix, p, t ); // inverse rotate translate
|
||||
|
||||
if ( t[0] < bmin[0] ) bmin[0] = t[0];
|
||||
if ( t[1] < bmin[1] ) bmin[1] = t[1];
|
||||
if ( t[2] < bmin[2] ) bmin[2] = t[2];
|
||||
|
||||
if ( t[0] > bmax[0] ) bmax[0] = t[0];
|
||||
if ( t[1] > bmax[1] ) bmax[1] = t[1];
|
||||
if ( t[2] > bmax[2] ) bmax[2] = t[2];
|
||||
|
||||
src+=pstride;
|
||||
}
|
||||
|
||||
|
||||
sides[0] = bmax[0];
|
||||
sides[1] = bmax[1];
|
||||
sides[2] = bmax[2];
|
||||
|
||||
if ( fabsf(bmin[0]) > sides[0] ) sides[0] = fabsf(bmin[0]);
|
||||
if ( fabsf(bmin[1]) > sides[1] ) sides[1] = fabsf(bmin[1]);
|
||||
if ( fabsf(bmin[2]) > sides[2] ) sides[2] = fabsf(bmin[2]);
|
||||
|
||||
sides[0]*=2.0f;
|
||||
sides[1]*=2.0f;
|
||||
sides[2]*=2.0f;
|
||||
|
||||
}
|
||||
|
||||
void computeBestFitOBB(unsigned int vcount,const float *points,unsigned int pstride,float *sides,float *matrix)
|
||||
{
|
||||
|
||||
float bmin[3];
|
||||
float bmax[3];
|
||||
|
||||
fm_getAABB(vcount,points,pstride,bmin,bmax);
|
||||
|
||||
float center[3];
|
||||
|
||||
center[0] = (bmax[0]-bmin[0])*0.5f + bmin[0];
|
||||
center[1] = (bmax[1]-bmin[1])*0.5f + bmin[1];
|
||||
center[2] = (bmax[2]-bmin[2])*0.5f + bmin[2];
|
||||
|
||||
float ax = 0;
|
||||
float ay = 0;
|
||||
float az = 0;
|
||||
|
||||
float sweep = 45.0f; // 180 degree sweep on all three axes.
|
||||
float steps = 8.0f; // 16 steps on each axis.
|
||||
|
||||
float bestVolume = 1e9;
|
||||
float angle[3];
|
||||
|
||||
while ( sweep >= 1 )
|
||||
{
|
||||
|
||||
bool found = false;
|
||||
|
||||
float stepsize = sweep / steps;
|
||||
|
||||
for (float x=ax-sweep; x<=ax+sweep; x+=stepsize)
|
||||
{
|
||||
for (float y=ay-sweep; y<=ay+sweep; y+=stepsize)
|
||||
{
|
||||
for (float z=az-sweep; z<=az+sweep; z+=stepsize)
|
||||
{
|
||||
float pmatrix[16];
|
||||
|
||||
fm_eulerMatrix( x*FM_DEG_TO_RAD, y*FM_DEG_TO_RAD, z*FM_DEG_TO_RAD, pmatrix );
|
||||
|
||||
pmatrix[3*4+0] = center[0];
|
||||
pmatrix[3*4+1] = center[1];
|
||||
pmatrix[3*4+2] = center[2];
|
||||
|
||||
float psides[3];
|
||||
|
||||
computeOBB( vcount, points, pstride, psides, pmatrix );
|
||||
|
||||
float volume = psides[0]*psides[1]*psides[2]; // the volume of the cube
|
||||
|
||||
if ( volume <= bestVolume )
|
||||
{
|
||||
bestVolume = volume;
|
||||
|
||||
sides[0] = psides[0];
|
||||
sides[1] = psides[1];
|
||||
sides[2] = psides[2];
|
||||
|
||||
angle[0] = ax;
|
||||
angle[1] = ay;
|
||||
angle[2] = az;
|
||||
|
||||
memcpy(matrix,pmatrix,sizeof(float)*16);
|
||||
found = true; // yes, we found an improvement.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( found )
|
||||
{
|
||||
|
||||
ax = angle[0];
|
||||
ay = angle[1];
|
||||
az = angle[2];
|
||||
|
||||
sweep*=0.5f; // sweep 1/2 the distance as the last time.
|
||||
}
|
||||
else
|
||||
{
|
||||
break; // no improvement, so just
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
43
Extras/ConvexDecomposition/bestfitobb.h
Normal file
43
Extras/ConvexDecomposition/bestfitobb.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef BEST_FIT_OBB_H
|
||||
|
||||
#define BEST_FIT_OBB_H
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
|
||||
void computeBestFitOBB(unsigned int vcount,const float *points,unsigned int pstride,float *sides,float *matrix);
|
||||
|
||||
#endif
|
||||
3243
Extras/ConvexDecomposition/cd_hull.cpp
Normal file
3243
Extras/ConvexDecomposition/cd_hull.cpp
Normal file
File diff suppressed because it is too large
Load Diff
153
Extras/ConvexDecomposition/cd_hull.h
Normal file
153
Extras/ConvexDecomposition/cd_hull.h
Normal file
@@ -0,0 +1,153 @@
|
||||
#ifndef CD_HULL_H
|
||||
|
||||
#define CD_HULL_H
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
namespace ConvexDecomposition
|
||||
{
|
||||
|
||||
class HullResult
|
||||
{
|
||||
public:
|
||||
HullResult(void)
|
||||
{
|
||||
mPolygons = true;
|
||||
mNumOutputVertices = 0;
|
||||
mOutputVertices = 0;
|
||||
mNumFaces = 0;
|
||||
mNumIndices = 0;
|
||||
mIndices = 0;
|
||||
}
|
||||
bool mPolygons; // true if indices represents polygons, false indices are triangles
|
||||
unsigned int mNumOutputVertices; // number of vertices in the output hull
|
||||
float *mOutputVertices; // array of vertices, 3 floats each x,y,z
|
||||
unsigned int mNumFaces; // the number of faces produced
|
||||
unsigned int mNumIndices; // the total number of indices
|
||||
unsigned int *mIndices; // pointer to indices.
|
||||
|
||||
// If triangles, then indices are array indexes into the vertex list.
|
||||
// If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc..
|
||||
};
|
||||
|
||||
enum HullFlag
|
||||
{
|
||||
QF_TRIANGLES = (1<<0), // report results as triangles, not polygons.
|
||||
QF_REVERSE_ORDER = (1<<1), // reverse order of the triangle indices.
|
||||
QF_SKIN_WIDTH = (1<<2), // extrude hull based on this skin width
|
||||
QF_DEFAULT = 0
|
||||
};
|
||||
|
||||
|
||||
class HullDesc
|
||||
{
|
||||
public:
|
||||
HullDesc(void)
|
||||
{
|
||||
mFlags = QF_DEFAULT;
|
||||
mVcount = 0;
|
||||
mVertices = 0;
|
||||
mVertexStride = sizeof(float)*3;
|
||||
mNormalEpsilon = 0.001f;
|
||||
mMaxVertices = 4096; // maximum number of points to be considered for a convex hull.
|
||||
mMaxFaces = 4096;
|
||||
mSkinWidth = 0.01f; // default is one centimeter
|
||||
};
|
||||
|
||||
HullDesc(HullFlag flag,
|
||||
unsigned int vcount,
|
||||
const float *vertices,
|
||||
unsigned int stride)
|
||||
{
|
||||
mFlags = flag;
|
||||
mVcount = vcount;
|
||||
mVertices = vertices;
|
||||
mVertexStride = stride;
|
||||
mNormalEpsilon = 0.001f;
|
||||
mMaxVertices = 4096;
|
||||
mSkinWidth = 0.01f; // default is one centimeter
|
||||
}
|
||||
|
||||
bool HasHullFlag(HullFlag flag) const
|
||||
{
|
||||
if ( mFlags & flag ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetHullFlag(HullFlag flag)
|
||||
{
|
||||
mFlags|=flag;
|
||||
}
|
||||
|
||||
void ClearHullFlag(HullFlag flag)
|
||||
{
|
||||
mFlags&=~flag;
|
||||
}
|
||||
|
||||
unsigned int mFlags; // flags to use when generating the convex hull.
|
||||
unsigned int mVcount; // number of vertices in the input point cloud
|
||||
const float *mVertices; // the array of vertices.
|
||||
unsigned int mVertexStride; // the stride of each vertex, in bytes.
|
||||
float mNormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on.
|
||||
float mSkinWidth;
|
||||
unsigned int mMaxVertices; // maximum number of vertices to be considered for the hull!
|
||||
unsigned int mMaxFaces;
|
||||
};
|
||||
|
||||
enum HullError
|
||||
{
|
||||
QE_OK, // success!
|
||||
QE_FAIL // failed.
|
||||
};
|
||||
|
||||
class HullLibrary
|
||||
{
|
||||
public:
|
||||
|
||||
HullError CreateConvexHull(const HullDesc &desc, // describes the input request
|
||||
HullResult &result); // contains the resulst
|
||||
|
||||
HullError ReleaseResult(HullResult &result); // release memory allocated for this result, we are done with it.
|
||||
|
||||
private:
|
||||
|
||||
void BringOutYourDead(const float *verts,unsigned int vcount, float *overts,unsigned int &ocount,unsigned int *indices,unsigned indexcount);
|
||||
|
||||
bool CleanupVertices(unsigned int svcount,
|
||||
const float *svertices,
|
||||
unsigned int stride,
|
||||
unsigned int &vcount, // output number of vertices
|
||||
float *vertices, // location to store the results.
|
||||
float normalepsilon,
|
||||
float *scale);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
1179
Extras/ConvexDecomposition/cd_vector.h
Normal file
1179
Extras/ConvexDecomposition/cd_vector.h
Normal file
File diff suppressed because it is too large
Load Diff
850
Extras/ConvexDecomposition/cd_wavefront.cpp
Normal file
850
Extras/ConvexDecomposition/cd_wavefront.cpp
Normal file
@@ -0,0 +1,850 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
#include "cd_wavefront.h"
|
||||
|
||||
|
||||
using namespace ConvexDecomposition;
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ConvexDecomposition
|
||||
{
|
||||
|
||||
typedef std::vector< int > IntVector;
|
||||
typedef std::vector< float > FloatVector;
|
||||
|
||||
#if defined(__APPLE__) || defined(__CELLOS_LV2__)
|
||||
#define stricmp(a, b) strcasecmp((a), (b))
|
||||
#endif
|
||||
|
||||
/*******************************************************************/
|
||||
/******************** InParser.h ********************************/
|
||||
/*******************************************************************/
|
||||
class InPlaceParserInterface
|
||||
{
|
||||
public:
|
||||
virtual int ParseLine(int lineno,int argc,const char **argv) =0; // return TRUE to continue parsing, return FALSE to abort parsing process
|
||||
};
|
||||
|
||||
enum SeparatorType
|
||||
{
|
||||
ST_DATA, // is data
|
||||
ST_HARD, // is a hard separator
|
||||
ST_SOFT, // is a soft separator
|
||||
ST_EOS // is a comment symbol, and everything past this character should be ignored
|
||||
};
|
||||
|
||||
class InPlaceParser
|
||||
{
|
||||
public:
|
||||
InPlaceParser(void)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
InPlaceParser(char *data,int len)
|
||||
{
|
||||
Init();
|
||||
SetSourceData(data,len);
|
||||
}
|
||||
|
||||
InPlaceParser(const char *fname)
|
||||
{
|
||||
Init();
|
||||
SetFile(fname);
|
||||
}
|
||||
|
||||
~InPlaceParser(void);
|
||||
|
||||
void Init(void)
|
||||
{
|
||||
mQuoteChar = 34;
|
||||
mData = 0;
|
||||
mLen = 0;
|
||||
mMyAlloc = false;
|
||||
for (int i=0; i<256; i++)
|
||||
{
|
||||
mHard[i] = ST_DATA;
|
||||
mHardString[i*2] = i;
|
||||
mHardString[i*2+1] = 0;
|
||||
}
|
||||
mHard[0] = ST_EOS;
|
||||
mHard[32] = ST_SOFT;
|
||||
mHard[9] = ST_SOFT;
|
||||
mHard[13] = ST_SOFT;
|
||||
mHard[10] = ST_SOFT;
|
||||
}
|
||||
|
||||
void SetFile(const char *fname); // use this file as source data to parse.
|
||||
|
||||
void SetSourceData(char *data,int len)
|
||||
{
|
||||
mData = data;
|
||||
mLen = len;
|
||||
mMyAlloc = false;
|
||||
};
|
||||
|
||||
int Parse(InPlaceParserInterface *callback); // returns true if entire file was parsed, false if it aborted for some reason
|
||||
|
||||
int ProcessLine(int lineno,char *line,InPlaceParserInterface *callback);
|
||||
|
||||
const char ** GetArglist(char *source,int &count); // convert source string into an arg list, this is a destructive parse.
|
||||
|
||||
void SetHardSeparator(char c) // add a hard separator
|
||||
{
|
||||
mHard[c] = ST_HARD;
|
||||
}
|
||||
|
||||
void SetHard(char c) // add a hard separator
|
||||
{
|
||||
mHard[c] = ST_HARD;
|
||||
}
|
||||
|
||||
|
||||
void SetCommentSymbol(char c) // comment character, treated as 'end of string'
|
||||
{
|
||||
mHard[c] = ST_EOS;
|
||||
}
|
||||
|
||||
void ClearHardSeparator(char c)
|
||||
{
|
||||
mHard[c] = ST_DATA;
|
||||
}
|
||||
|
||||
|
||||
void DefaultSymbols(void); // set up default symbols for hard seperator and comment symbol of the '#' character.
|
||||
|
||||
bool EOS(char c)
|
||||
{
|
||||
if ( mHard[c] == ST_EOS )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetQuoteChar(char c)
|
||||
{
|
||||
mQuoteChar = c;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
inline char * AddHard(int &argc,const char **argv,char *foo);
|
||||
inline bool IsHard(char c);
|
||||
inline char * SkipSpaces(char *foo);
|
||||
inline bool IsWhiteSpace(char c);
|
||||
inline bool IsNonSeparator(char c); // non seperator,neither hard nor soft
|
||||
|
||||
bool mMyAlloc; // whether or not *I* allocated the buffer and am responsible for deleting it.
|
||||
char *mData; // ascii data to parse.
|
||||
int mLen; // length of data
|
||||
SeparatorType mHard[256];
|
||||
char mHardString[256*2];
|
||||
char mQuoteChar;
|
||||
};
|
||||
|
||||
/*******************************************************************/
|
||||
/******************** InParser.cpp ********************************/
|
||||
/*******************************************************************/
|
||||
void InPlaceParser::SetFile(const char *fname)
|
||||
{
|
||||
if ( mMyAlloc )
|
||||
{
|
||||
free(mData);
|
||||
}
|
||||
mData = 0;
|
||||
mLen = 0;
|
||||
mMyAlloc = false;
|
||||
|
||||
|
||||
FILE *fph = fopen(fname,"rb");
|
||||
if ( fph )
|
||||
{
|
||||
fseek(fph,0L,SEEK_END);
|
||||
mLen = ftell(fph);
|
||||
fseek(fph,0L,SEEK_SET);
|
||||
if ( mLen )
|
||||
{
|
||||
mData = (char *) malloc(sizeof(char)*(mLen+1));
|
||||
int ok = fread(mData, mLen, 1, fph);
|
||||
if ( !ok )
|
||||
{
|
||||
free(mData);
|
||||
mData = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mData[mLen] = 0; // zero byte terminate end of file marker.
|
||||
mMyAlloc = true;
|
||||
}
|
||||
}
|
||||
fclose(fph);
|
||||
}
|
||||
}
|
||||
|
||||
InPlaceParser::~InPlaceParser(void)
|
||||
{
|
||||
if ( mMyAlloc )
|
||||
{
|
||||
free(mData);
|
||||
}
|
||||
}
|
||||
|
||||
#define MAXARGS 512
|
||||
|
||||
bool InPlaceParser::IsHard(char c)
|
||||
{
|
||||
return mHard[c] == ST_HARD;
|
||||
}
|
||||
|
||||
char * InPlaceParser::AddHard(int &argc,const char **argv,char *foo)
|
||||
{
|
||||
while ( IsHard(*foo) )
|
||||
{
|
||||
const char *hard = &mHardString[*foo*2];
|
||||
if ( argc < MAXARGS )
|
||||
{
|
||||
argv[argc++] = hard;
|
||||
}
|
||||
foo++;
|
||||
}
|
||||
return foo;
|
||||
}
|
||||
|
||||
bool InPlaceParser::IsWhiteSpace(char c)
|
||||
{
|
||||
return mHard[c] == ST_SOFT;
|
||||
}
|
||||
|
||||
char * InPlaceParser::SkipSpaces(char *foo)
|
||||
{
|
||||
while ( !EOS(*foo) && IsWhiteSpace(*foo) ) foo++;
|
||||
return foo;
|
||||
}
|
||||
|
||||
bool InPlaceParser::IsNonSeparator(char c)
|
||||
{
|
||||
if ( !IsHard(c) && !IsWhiteSpace(c) && c != 0 ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int InPlaceParser::ProcessLine(int lineno,char *line,InPlaceParserInterface *callback)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
const char *argv[MAXARGS];
|
||||
int argc = 0;
|
||||
|
||||
char *foo = line;
|
||||
|
||||
while ( !EOS(*foo) && argc < MAXARGS )
|
||||
{
|
||||
|
||||
foo = SkipSpaces(foo); // skip any leading spaces
|
||||
|
||||
if ( EOS(*foo) ) break;
|
||||
|
||||
if ( *foo == mQuoteChar ) // if it is an open quote
|
||||
{
|
||||
foo++;
|
||||
if ( argc < MAXARGS )
|
||||
{
|
||||
argv[argc++] = foo;
|
||||
}
|
||||
while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
|
||||
if ( !EOS(*foo) )
|
||||
{
|
||||
*foo = 0; // replace close quote with zero byte EOS
|
||||
foo++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
|
||||
|
||||
if ( IsNonSeparator(*foo) ) // add non-hard argument.
|
||||
{
|
||||
bool quote = false;
|
||||
if ( *foo == mQuoteChar )
|
||||
{
|
||||
foo++;
|
||||
quote = true;
|
||||
}
|
||||
|
||||
if ( argc < MAXARGS )
|
||||
{
|
||||
argv[argc++] = foo;
|
||||
}
|
||||
|
||||
if ( quote )
|
||||
{
|
||||
while (*foo && *foo != mQuoteChar ) foo++;
|
||||
if ( *foo ) *foo = 32;
|
||||
}
|
||||
|
||||
// continue..until we hit an eos ..
|
||||
while ( !EOS(*foo) ) // until we hit EOS
|
||||
{
|
||||
if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
|
||||
{
|
||||
*foo = 0;
|
||||
foo++;
|
||||
break;
|
||||
}
|
||||
else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
|
||||
{
|
||||
const char *hard = &mHardString[*foo*2];
|
||||
*foo = 0;
|
||||
if ( argc < MAXARGS )
|
||||
{
|
||||
argv[argc++] = hard;
|
||||
}
|
||||
foo++;
|
||||
break;
|
||||
}
|
||||
foo++;
|
||||
} // end of while loop...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( argc )
|
||||
{
|
||||
ret = callback->ParseLine(lineno, argc, argv );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int InPlaceParser::Parse(InPlaceParserInterface *callback) // returns true if entire file was parsed, false if it aborted for some reason
|
||||
{
|
||||
assert( callback );
|
||||
if ( !mData ) return 0;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
int lineno = 0;
|
||||
|
||||
char *foo = mData;
|
||||
char *begin = foo;
|
||||
|
||||
|
||||
while ( *foo )
|
||||
{
|
||||
if ( *foo == 10 || *foo == 13 )
|
||||
{
|
||||
lineno++;
|
||||
*foo = 0;
|
||||
|
||||
if ( *begin ) // if there is any data to parse at all...
|
||||
{
|
||||
int v = ProcessLine(lineno,begin,callback);
|
||||
if ( v ) ret = v;
|
||||
}
|
||||
|
||||
foo++;
|
||||
if ( *foo == 10 ) foo++; // skip line feed, if it is in the carraige-return line-feed format...
|
||||
begin = foo;
|
||||
}
|
||||
else
|
||||
{
|
||||
foo++;
|
||||
}
|
||||
}
|
||||
|
||||
lineno++; // lasst line.
|
||||
|
||||
int v = ProcessLine(lineno,begin,callback);
|
||||
if ( v ) ret = v;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void InPlaceParser::DefaultSymbols(void)
|
||||
{
|
||||
SetHardSeparator(',');
|
||||
SetHardSeparator('(');
|
||||
SetHardSeparator(')');
|
||||
SetHardSeparator('=');
|
||||
SetHardSeparator('[');
|
||||
SetHardSeparator(']');
|
||||
SetHardSeparator('{');
|
||||
SetHardSeparator('}');
|
||||
SetCommentSymbol('#');
|
||||
}
|
||||
|
||||
|
||||
const char ** InPlaceParser::GetArglist(char *line,int &count) // convert source string into an arg list, this is a destructive parse.
|
||||
{
|
||||
const char **ret = 0;
|
||||
|
||||
static const char *argv[MAXARGS];
|
||||
int argc = 0;
|
||||
|
||||
char *foo = line;
|
||||
|
||||
while ( !EOS(*foo) && argc < MAXARGS )
|
||||
{
|
||||
|
||||
foo = SkipSpaces(foo); // skip any leading spaces
|
||||
|
||||
if ( EOS(*foo) ) break;
|
||||
|
||||
if ( *foo == mQuoteChar ) // if it is an open quote
|
||||
{
|
||||
foo++;
|
||||
if ( argc < MAXARGS )
|
||||
{
|
||||
argv[argc++] = foo;
|
||||
}
|
||||
while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
|
||||
if ( !EOS(*foo) )
|
||||
{
|
||||
*foo = 0; // replace close quote with zero byte EOS
|
||||
foo++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
|
||||
|
||||
if ( IsNonSeparator(*foo) ) // add non-hard argument.
|
||||
{
|
||||
bool quote = false;
|
||||
if ( *foo == mQuoteChar )
|
||||
{
|
||||
foo++;
|
||||
quote = true;
|
||||
}
|
||||
|
||||
if ( argc < MAXARGS )
|
||||
{
|
||||
argv[argc++] = foo;
|
||||
}
|
||||
|
||||
if ( quote )
|
||||
{
|
||||
while (*foo && *foo != mQuoteChar ) foo++;
|
||||
if ( *foo ) *foo = 32;
|
||||
}
|
||||
|
||||
// continue..until we hit an eos ..
|
||||
while ( !EOS(*foo) ) // until we hit EOS
|
||||
{
|
||||
if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
|
||||
{
|
||||
*foo = 0;
|
||||
foo++;
|
||||
break;
|
||||
}
|
||||
else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
|
||||
{
|
||||
const char *hard = &mHardString[*foo*2];
|
||||
*foo = 0;
|
||||
if ( argc < MAXARGS )
|
||||
{
|
||||
argv[argc++] = hard;
|
||||
}
|
||||
foo++;
|
||||
break;
|
||||
}
|
||||
foo++;
|
||||
} // end of while loop...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count = argc;
|
||||
if ( argc )
|
||||
{
|
||||
ret = argv;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
/******************** Geometry.h ********************************/
|
||||
/*******************************************************************/
|
||||
|
||||
class GeometryVertex
|
||||
{
|
||||
public:
|
||||
float mPos[3];
|
||||
float mNormal[3];
|
||||
float mTexel[2];
|
||||
};
|
||||
|
||||
|
||||
class GeometryInterface
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/******************** Obj.h ********************************/
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
class OBJ : public InPlaceParserInterface
|
||||
{
|
||||
public:
|
||||
int LoadMesh(const char *fname,GeometryInterface *callback);
|
||||
int ParseLine(int lineno,int argc,const char **argv); // return TRUE to continue parsing, return FALSE to abort parsing process
|
||||
private:
|
||||
|
||||
void GetVertex(GeometryVertex &v,const char *face) const;
|
||||
|
||||
FloatVector mVerts;
|
||||
FloatVector mTexels;
|
||||
FloatVector mNormals;
|
||||
|
||||
GeometryInterface *mCallback;
|
||||
};
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/******************** Obj.cpp ********************************/
|
||||
/*******************************************************************/
|
||||
|
||||
int OBJ::LoadMesh(const char *fname,GeometryInterface *iface)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mVerts.clear();
|
||||
mTexels.clear();
|
||||
mNormals.clear();
|
||||
|
||||
mCallback = iface;
|
||||
|
||||
InPlaceParser ipp(fname);
|
||||
|
||||
ipp.Parse(this);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char * GetArg(const char **argv,int i,int argc)
|
||||
{
|
||||
const char * ret = 0;
|
||||
if ( i < argc ) ret = argv[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
void OBJ::GetVertex(GeometryVertex &v,const char *face) const
|
||||
{
|
||||
v.mPos[0] = 0;
|
||||
v.mPos[1] = 0;
|
||||
v.mPos[2] = 0;
|
||||
|
||||
v.mTexel[0] = 0;
|
||||
v.mTexel[1] = 0;
|
||||
|
||||
v.mNormal[0] = 0;
|
||||
v.mNormal[1] = 1;
|
||||
v.mNormal[2] = 0;
|
||||
|
||||
int index = atoi( face )-1;
|
||||
|
||||
const char *texel = strstr(face,"/");
|
||||
|
||||
if ( texel )
|
||||
{
|
||||
int tindex = atoi( texel+1) - 1;
|
||||
|
||||
if ( tindex >=0 && tindex < (int)(mTexels.size()/2) )
|
||||
{
|
||||
const float *t = &mTexels[tindex*2];
|
||||
|
||||
v.mTexel[0] = t[0];
|
||||
v.mTexel[1] = t[1];
|
||||
|
||||
}
|
||||
|
||||
const char *normal = strstr(texel+1,"/");
|
||||
if ( normal )
|
||||
{
|
||||
int nindex = atoi( normal+1 ) - 1;
|
||||
|
||||
if (nindex >= 0 && nindex < (int)(mNormals.size()/3) )
|
||||
{
|
||||
const float *n = &mNormals[nindex*3];
|
||||
|
||||
v.mNormal[0] = n[0];
|
||||
v.mNormal[1] = n[1];
|
||||
v.mNormal[2] = n[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( index >= 0 && index < (int)(mVerts.size()/3) )
|
||||
{
|
||||
|
||||
const float *p = &mVerts[index*3];
|
||||
|
||||
v.mPos[0] = p[0];
|
||||
v.mPos[1] = p[1];
|
||||
v.mPos[2] = p[2];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int OBJ::ParseLine(int lineno,int argc,const char **argv) // return TRUE to continue parsing, return FALSE to abort parsing process
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if ( argc >= 1 )
|
||||
{
|
||||
const char *foo = argv[0];
|
||||
if ( *foo != '#' )
|
||||
{
|
||||
if ( stricmp(argv[0],"v") == 0 && argc == 4 )
|
||||
{
|
||||
float vx = (float) atof( argv[1] );
|
||||
float vy = (float) atof( argv[2] );
|
||||
float vz = (float) atof( argv[3] );
|
||||
mVerts.push_back(vx);
|
||||
mVerts.push_back(vy);
|
||||
mVerts.push_back(vz);
|
||||
}
|
||||
else if ( stricmp(argv[0],"vt") == 0 && argc == 3 )
|
||||
{
|
||||
float tx = (float) atof( argv[1] );
|
||||
float ty = (float) atof( argv[2] );
|
||||
mTexels.push_back(tx);
|
||||
mTexels.push_back(ty);
|
||||
}
|
||||
else if ( stricmp(argv[0],"vn") == 0 && argc == 4 )
|
||||
{
|
||||
float normalx = (float) atof(argv[1]);
|
||||
float normaly = (float) atof(argv[2]);
|
||||
float normalz = (float) atof(argv[3]);
|
||||
mNormals.push_back(normalx);
|
||||
mNormals.push_back(normaly);
|
||||
mNormals.push_back(normalz);
|
||||
}
|
||||
else if ( stricmp(argv[0],"f") == 0 && argc >= 4 )
|
||||
{
|
||||
GeometryVertex v[32];
|
||||
|
||||
int vcount = argc-1;
|
||||
|
||||
for (int i=1; i<argc; i++)
|
||||
{
|
||||
GetVertex(v[i-1],argv[i] );
|
||||
}
|
||||
|
||||
// need to generate a normal!
|
||||
#if 0 // not currently implemented
|
||||
if ( mNormals.empty() )
|
||||
{
|
||||
Vector3d<float> p1( v[0].mPos );
|
||||
Vector3d<float> p2( v[1].mPos );
|
||||
Vector3d<float> p3( v[2].mPos );
|
||||
|
||||
Vector3d<float> n;
|
||||
n.ComputeNormal(p3,p2,p1);
|
||||
|
||||
for (int i=0; i<vcount; i++)
|
||||
{
|
||||
v[i].mNormal[0] = n.x;
|
||||
v[i].mNormal[1] = n.y;
|
||||
v[i].mNormal[2] = n.z;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
mCallback->NodeTriangle(&v[0],&v[1],&v[2]);
|
||||
|
||||
if ( vcount >=3 ) // do the fan
|
||||
{
|
||||
for (int i=2; i<(vcount-1); i++)
|
||||
{
|
||||
mCallback->NodeTriangle(&v[0],&v[i],&v[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class BuildMesh : public GeometryInterface
|
||||
{
|
||||
public:
|
||||
|
||||
int GetIndex(const float *p)
|
||||
{
|
||||
|
||||
int vcount = mVertices.size()/3;
|
||||
|
||||
if(vcount>0)
|
||||
{
|
||||
//New MS STL library checks indices in debug build, so zero causes an assert if it is empty.
|
||||
const float *v = &mVertices[0];
|
||||
|
||||
for (int i=0; i<vcount; i++)
|
||||
{
|
||||
if ( v[0] == p[0] && v[1] == p[1] && v[2] == p[2] ) return i;
|
||||
v+=3;
|
||||
}
|
||||
}
|
||||
|
||||
mVertices.push_back( p[0] );
|
||||
mVertices.push_back( p[1] );
|
||||
mVertices.push_back( p[2] );
|
||||
|
||||
return vcount;
|
||||
}
|
||||
|
||||
virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3)
|
||||
{
|
||||
mIndices.push_back( GetIndex(v1->mPos) );
|
||||
mIndices.push_back( GetIndex(v2->mPos) );
|
||||
mIndices.push_back( GetIndex(v3->mPos) );
|
||||
}
|
||||
|
||||
const FloatVector& GetVertices(void) const { return mVertices; };
|
||||
const IntVector& GetIndices(void) const { return mIndices; };
|
||||
|
||||
private:
|
||||
FloatVector mVertices;
|
||||
IntVector mIndices;
|
||||
};
|
||||
|
||||
|
||||
WavefrontObj::WavefrontObj(void)
|
||||
{
|
||||
mVertexCount = 0;
|
||||
mTriCount = 0;
|
||||
mIndices = 0;
|
||||
mVertices = 0;
|
||||
}
|
||||
|
||||
WavefrontObj::~WavefrontObj(void)
|
||||
{
|
||||
delete mIndices;
|
||||
delete mVertices;
|
||||
}
|
||||
|
||||
unsigned int WavefrontObj::loadObj(const char *fname) // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed.
|
||||
{
|
||||
|
||||
unsigned int ret = 0;
|
||||
|
||||
delete mVertices;
|
||||
mVertices = 0;
|
||||
delete mIndices;
|
||||
mIndices = 0;
|
||||
mVertexCount = 0;
|
||||
mTriCount = 0;
|
||||
|
||||
|
||||
BuildMesh bm;
|
||||
|
||||
OBJ obj;
|
||||
|
||||
obj.LoadMesh(fname,&bm);
|
||||
|
||||
|
||||
const FloatVector &vlist = bm.GetVertices();
|
||||
const IntVector &indices = bm.GetIndices();
|
||||
if ( vlist.size() )
|
||||
{
|
||||
mVertexCount = vlist.size()/3;
|
||||
mVertices = new float[mVertexCount*3];
|
||||
memcpy( mVertices, &vlist[0], sizeof(float)*mVertexCount*3 );
|
||||
mTriCount = indices.size()/3;
|
||||
mIndices = new int[mTriCount*3*sizeof(int)];
|
||||
memcpy(mIndices, &indices[0], sizeof(int)*mTriCount*3);
|
||||
ret = mTriCount;
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
};
|
||||
62
Extras/ConvexDecomposition/cd_wavefront.h
Normal file
62
Extras/ConvexDecomposition/cd_wavefront.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef CD_WAVEFRONT_OBJ_H
|
||||
|
||||
|
||||
#define CD_WAVEFRONT_OBJ_H
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
namespace ConvexDecomposition
|
||||
{
|
||||
|
||||
class WavefrontObj
|
||||
{
|
||||
public:
|
||||
|
||||
WavefrontObj(void);
|
||||
~WavefrontObj(void);
|
||||
|
||||
unsigned int loadObj(const char *fname); // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed.
|
||||
|
||||
int mVertexCount;
|
||||
int mTriCount;
|
||||
int *mIndices;
|
||||
float *mVertices;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
799
Extras/ConvexDecomposition/concavity.cpp
Normal file
799
Extras/ConvexDecomposition/concavity.cpp
Normal file
@@ -0,0 +1,799 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
#include "concavity.h"
|
||||
#include "raytri.h"
|
||||
#include "bestfit.h"
|
||||
#include "cd_hull.h"
|
||||
#include "meshvolume.h"
|
||||
#include "cd_vector.h"
|
||||
#include "splitplane.h"
|
||||
#include "ConvexDecomposition.h"
|
||||
|
||||
|
||||
#define WSCALE 4
|
||||
#define CONCAVE_THRESH 0.05f
|
||||
|
||||
namespace ConvexDecomposition
|
||||
{
|
||||
|
||||
unsigned int getDebugColor(void)
|
||||
{
|
||||
static unsigned int colors[8] =
|
||||
{
|
||||
0xFF0000,
|
||||
0x00FF00,
|
||||
0x0000FF,
|
||||
0xFFFF00,
|
||||
0x00FFFF,
|
||||
0xFF00FF,
|
||||
0xFFFFFF,
|
||||
0xFF8040
|
||||
};
|
||||
|
||||
static int count = 0;
|
||||
|
||||
count++;
|
||||
|
||||
if ( count == 8 ) count = 0;
|
||||
|
||||
assert( count >= 0 && count < 8 );
|
||||
|
||||
unsigned int color = colors[count];
|
||||
|
||||
return color;
|
||||
|
||||
}
|
||||
|
||||
class Wpoint
|
||||
{
|
||||
public:
|
||||
Wpoint(const Vector3d<float> &p,float w)
|
||||
{
|
||||
mPoint = p;
|
||||
mWeight = w;
|
||||
}
|
||||
|
||||
Vector3d<float> mPoint;
|
||||
float mWeight;
|
||||
};
|
||||
|
||||
typedef std::vector< Wpoint > WpointVector;
|
||||
|
||||
|
||||
static inline float DistToPt(const float *p,const float *plane)
|
||||
{
|
||||
float x = p[0];
|
||||
float y = p[1];
|
||||
float z = p[2];
|
||||
float d = x*plane[0] + y*plane[1] + z*plane[2] + plane[3];
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
static void intersect(const float *p1,const float *p2,float *split,const float *plane)
|
||||
{
|
||||
|
||||
float dp1 = DistToPt(p1,plane);
|
||||
float dp2 = DistToPt(p2,plane);
|
||||
|
||||
float dir[3];
|
||||
|
||||
dir[0] = p2[0] - p1[0];
|
||||
dir[1] = p2[1] - p1[1];
|
||||
dir[2] = p2[2] - p1[2];
|
||||
|
||||
float dot1 = dir[0]*plane[0] + dir[1]*plane[1] + dir[2]*plane[2];
|
||||
float dot2 = dp1 - plane[3];
|
||||
|
||||
float t = -(plane[3] + dot2 ) / dot1;
|
||||
|
||||
split[0] = (dir[0]*t)+p1[0];
|
||||
split[1] = (dir[1]*t)+p1[1];
|
||||
split[2] = (dir[2]*t)+p1[2];
|
||||
|
||||
}
|
||||
|
||||
|
||||
class CTri
|
||||
{
|
||||
public:
|
||||
CTri(void) { };
|
||||
|
||||
CTri(const float *p1,const float *p2,const float *p3,unsigned int i1,unsigned int i2,unsigned int i3)
|
||||
{
|
||||
mProcessed = 0;
|
||||
mI1 = i1;
|
||||
mI2 = i2;
|
||||
mI3 = i3;
|
||||
|
||||
mP1.Set(p1);
|
||||
mP2.Set(p2);
|
||||
mP3.Set(p3);
|
||||
|
||||
mPlaneD = mNormal.ComputePlane(mP1,mP2,mP3);
|
||||
}
|
||||
|
||||
float Facing(const CTri &t)
|
||||
{
|
||||
float d = mNormal.Dot(t.mNormal);
|
||||
return d;
|
||||
}
|
||||
|
||||
// clip this line segment against this triangle.
|
||||
bool clip(const Vector3d<float> &start,Vector3d<float> &end) const
|
||||
{
|
||||
Vector3d<float> sect;
|
||||
|
||||
bool hit = lineIntersectsTriangle(start.Ptr(), end.Ptr(), mP1.Ptr(), mP2.Ptr(), mP3.Ptr(), sect.Ptr() );
|
||||
|
||||
if ( hit )
|
||||
{
|
||||
end = sect;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
bool Concave(const Vector3d<float> &p,float &distance,Vector3d<float> &n) const
|
||||
{
|
||||
n.NearestPointInTriangle(p,mP1,mP2,mP3);
|
||||
distance = p.Distance(n);
|
||||
return true;
|
||||
}
|
||||
|
||||
void addTri(unsigned int *indices,unsigned int i1,unsigned int i2,unsigned int i3,unsigned int &tcount) const
|
||||
{
|
||||
indices[tcount*3+0] = i1;
|
||||
indices[tcount*3+1] = i2;
|
||||
indices[tcount*3+2] = i3;
|
||||
tcount++;
|
||||
}
|
||||
|
||||
float getVolume(ConvexDecompInterface *callback) const
|
||||
{
|
||||
unsigned int indices[8*3];
|
||||
|
||||
|
||||
unsigned int tcount = 0;
|
||||
|
||||
addTri(indices,0,1,2,tcount);
|
||||
addTri(indices,3,4,5,tcount);
|
||||
|
||||
addTri(indices,0,3,4,tcount);
|
||||
addTri(indices,0,4,1,tcount);
|
||||
|
||||
addTri(indices,1,4,5,tcount);
|
||||
addTri(indices,1,5,2,tcount);
|
||||
|
||||
addTri(indices,0,3,5,tcount);
|
||||
addTri(indices,0,5,2,tcount);
|
||||
|
||||
const float *vertices = mP1.Ptr();
|
||||
|
||||
if ( callback )
|
||||
{
|
||||
unsigned int color = getDebugColor();
|
||||
|
||||
#if 0
|
||||
Vector3d<float> d1 = mNear1;
|
||||
Vector3d<float> d2 = mNear2;
|
||||
Vector3d<float> d3 = mNear3;
|
||||
|
||||
callback->ConvexDebugPoint(mP1.Ptr(),0.01f,0x00FF00);
|
||||
callback->ConvexDebugPoint(mP2.Ptr(),0.01f,0x00FF00);
|
||||
callback->ConvexDebugPoint(mP3.Ptr(),0.01f,0x00FF00);
|
||||
callback->ConvexDebugPoint(d1.Ptr(),0.01f,0xFF0000);
|
||||
callback->ConvexDebugPoint(d2.Ptr(),0.01f,0xFF0000);
|
||||
callback->ConvexDebugPoint(d3.Ptr(),0.01f,0xFF0000);
|
||||
|
||||
callback->ConvexDebugTri(mP1.Ptr(), d1.Ptr(), d1.Ptr(),0x00FF00);
|
||||
callback->ConvexDebugTri(mP2.Ptr(), d2.Ptr(), d2.Ptr(),0x00FF00);
|
||||
callback->ConvexDebugTri(mP3.Ptr(), d3.Ptr(), d3.Ptr(),0x00FF00);
|
||||
|
||||
#else
|
||||
for (unsigned int i=0; i<tcount; i++)
|
||||
{
|
||||
unsigned int i1 = indices[i*3+0];
|
||||
unsigned int i2 = indices[i*3+1];
|
||||
unsigned int i3 = indices[i*3+2];
|
||||
|
||||
const float *p1 = &vertices[ i1*3 ];
|
||||
const float *p2 = &vertices[ i2*3 ];
|
||||
const float *p3 = &vertices[ i3*3 ];
|
||||
|
||||
callback->ConvexDebugTri(p1,p2,p3,color);
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
float v = computeMeshVolume(mP1.Ptr(), tcount, indices );
|
||||
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
float raySect(const Vector3d<float> &p,const Vector3d<float> &dir,Vector3d<float> §) const
|
||||
{
|
||||
float plane[4];
|
||||
|
||||
plane[0] = mNormal.x;
|
||||
plane[1] = mNormal.y;
|
||||
plane[2] = mNormal.z;
|
||||
plane[3] = mPlaneD;
|
||||
|
||||
Vector3d<float> dest = p+dir*100000;
|
||||
|
||||
intersect( p.Ptr(), dest.Ptr(), sect.Ptr(), plane );
|
||||
|
||||
return sect.Distance(p); // return the intersection distance.
|
||||
|
||||
}
|
||||
|
||||
float planeDistance(const Vector3d<float> &p) const
|
||||
{
|
||||
float plane[4];
|
||||
|
||||
plane[0] = mNormal.x;
|
||||
plane[1] = mNormal.y;
|
||||
plane[2] = mNormal.z;
|
||||
plane[3] = mPlaneD;
|
||||
|
||||
return DistToPt( p.Ptr(), plane );
|
||||
|
||||
}
|
||||
|
||||
bool samePlane(const CTri &t) const
|
||||
{
|
||||
const float THRESH = 0.001f;
|
||||
float dd = fabsf( t.mPlaneD - mPlaneD );
|
||||
if ( dd > THRESH ) return false;
|
||||
dd = fabsf( t.mNormal.x - mNormal.x );
|
||||
if ( dd > THRESH ) return false;
|
||||
dd = fabsf( t.mNormal.y - mNormal.y );
|
||||
if ( dd > THRESH ) return false;
|
||||
dd = fabsf( t.mNormal.z - mNormal.z );
|
||||
if ( dd > THRESH ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasIndex(unsigned int i) const
|
||||
{
|
||||
if ( i == mI1 || i == mI2 || i == mI3 ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sharesEdge(const CTri &t) const
|
||||
{
|
||||
bool ret = false;
|
||||
unsigned int count = 0;
|
||||
|
||||
if ( t.hasIndex(mI1) ) count++;
|
||||
if ( t.hasIndex(mI2) ) count++;
|
||||
if ( t.hasIndex(mI3) ) count++;
|
||||
|
||||
if ( count >= 2 ) ret = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void debug(unsigned int color,ConvexDecompInterface *callback)
|
||||
{
|
||||
callback->ConvexDebugTri( mP1.Ptr(), mP2.Ptr(), mP3.Ptr(), color );
|
||||
callback->ConvexDebugTri( mP1.Ptr(), mP1.Ptr(), mNear1.Ptr(), 0xFF0000 );
|
||||
callback->ConvexDebugTri( mP2.Ptr(), mP2.Ptr(), mNear2.Ptr(), 0xFF0000 );
|
||||
callback->ConvexDebugTri( mP2.Ptr(), mP3.Ptr(), mNear3.Ptr(), 0xFF0000 );
|
||||
callback->ConvexDebugPoint( mNear1.Ptr(), 0.01f, 0xFF0000 );
|
||||
callback->ConvexDebugPoint( mNear2.Ptr(), 0.01f, 0xFF0000 );
|
||||
callback->ConvexDebugPoint( mNear3.Ptr(), 0.01f, 0xFF0000 );
|
||||
}
|
||||
|
||||
float area(void)
|
||||
{
|
||||
float a = mConcavity*mP1.Area(mP2,mP3);
|
||||
return a;
|
||||
}
|
||||
|
||||
void addWeighted(WpointVector &list,ConvexDecompInterface *callback)
|
||||
{
|
||||
|
||||
Wpoint p1(mP1,mC1);
|
||||
Wpoint p2(mP2,mC2);
|
||||
Wpoint p3(mP3,mC3);
|
||||
|
||||
Vector3d<float> d1 = mNear1 - mP1;
|
||||
Vector3d<float> d2 = mNear2 - mP2;
|
||||
Vector3d<float> d3 = mNear3 - mP3;
|
||||
|
||||
d1*=WSCALE;
|
||||
d2*=WSCALE;
|
||||
d3*=WSCALE;
|
||||
|
||||
d1 = d1 + mP1;
|
||||
d2 = d2 + mP2;
|
||||
d3 = d3 + mP3;
|
||||
|
||||
Wpoint p4(d1,mC1);
|
||||
Wpoint p5(d2,mC2);
|
||||
Wpoint p6(d3,mC3);
|
||||
|
||||
list.push_back(p1);
|
||||
list.push_back(p2);
|
||||
list.push_back(p3);
|
||||
|
||||
list.push_back(p4);
|
||||
list.push_back(p5);
|
||||
list.push_back(p6);
|
||||
|
||||
#if 0
|
||||
callback->ConvexDebugPoint(mP1.Ptr(),0.01f,0x00FF00);
|
||||
callback->ConvexDebugPoint(mP2.Ptr(),0.01f,0x00FF00);
|
||||
callback->ConvexDebugPoint(mP3.Ptr(),0.01f,0x00FF00);
|
||||
callback->ConvexDebugPoint(d1.Ptr(),0.01f,0xFF0000);
|
||||
callback->ConvexDebugPoint(d2.Ptr(),0.01f,0xFF0000);
|
||||
callback->ConvexDebugPoint(d3.Ptr(),0.01f,0xFF0000);
|
||||
|
||||
callback->ConvexDebugTri(mP1.Ptr(), d1.Ptr(), d1.Ptr(),0x00FF00);
|
||||
callback->ConvexDebugTri(mP2.Ptr(), d2.Ptr(), d2.Ptr(),0x00FF00);
|
||||
callback->ConvexDebugTri(mP3.Ptr(), d3.Ptr(), d3.Ptr(),0x00FF00);
|
||||
|
||||
Vector3d<float> np1 = mP1 + mNormal*0.05f;
|
||||
Vector3d<float> np2 = mP2 + mNormal*0.05f;
|
||||
Vector3d<float> np3 = mP3 + mNormal*0.05f;
|
||||
|
||||
callback->ConvexDebugTri(mP1.Ptr(), np1.Ptr(), np1.Ptr(), 0xFF00FF );
|
||||
callback->ConvexDebugTri(mP2.Ptr(), np2.Ptr(), np2.Ptr(), 0xFF00FF );
|
||||
callback->ConvexDebugTri(mP3.Ptr(), np3.Ptr(), np3.Ptr(), 0xFF00FF );
|
||||
|
||||
callback->ConvexDebugPoint( np1.Ptr(), 0.01F, 0XFF00FF );
|
||||
callback->ConvexDebugPoint( np2.Ptr(), 0.01F, 0XFF00FF );
|
||||
callback->ConvexDebugPoint( np3.Ptr(), 0.01F, 0XFF00FF );
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Vector3d<float> mP1;
|
||||
Vector3d<float> mP2;
|
||||
Vector3d<float> mP3;
|
||||
Vector3d<float> mNear1;
|
||||
Vector3d<float> mNear2;
|
||||
Vector3d<float> mNear3;
|
||||
Vector3d<float> mNormal;
|
||||
float mPlaneD;
|
||||
float mConcavity;
|
||||
float mC1;
|
||||
float mC2;
|
||||
float mC3;
|
||||
unsigned int mI1;
|
||||
unsigned int mI2;
|
||||
unsigned int mI3;
|
||||
int mProcessed; // already been added...
|
||||
};
|
||||
|
||||
typedef std::vector< CTri > CTriVector;
|
||||
|
||||
bool featureMatch(CTri &m,const CTriVector &tris,ConvexDecompInterface *callback,const CTriVector &input_mesh)
|
||||
{
|
||||
|
||||
bool ret = false;
|
||||
|
||||
float neardot = 0.707f;
|
||||
|
||||
m.mConcavity = 0;
|
||||
|
||||
//gLog->Display("*********** FEATURE MATCH *************\r\n");
|
||||
//gLog->Display("Plane: %0.4f,%0.4f,%0.4f %0.4f\r\n", m.mNormal.x, m.mNormal.y, m.mNormal.z, m.mPlaneD );
|
||||
//gLog->Display("*********************************************\r\n");
|
||||
|
||||
CTriVector::const_iterator i;
|
||||
|
||||
CTri nearest;
|
||||
|
||||
|
||||
for (i=tris.begin(); i!=tris.end(); ++i)
|
||||
{
|
||||
const CTri &t = (*i);
|
||||
|
||||
|
||||
//gLog->Display(" HullPlane: %0.4f,%0.4f,%0.4f %0.4f\r\n", t.mNormal.x, t.mNormal.y, t.mNormal.z, t.mPlaneD );
|
||||
|
||||
if ( t.samePlane(m) )
|
||||
{
|
||||
//gLog->Display("*** PLANE MATCH!!!\r\n");
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
float dot = t.mNormal.Dot(m.mNormal);
|
||||
|
||||
if ( dot > neardot )
|
||||
{
|
||||
|
||||
float d1 = t.planeDistance( m.mP1 );
|
||||
float d2 = t.planeDistance( m.mP2 );
|
||||
float d3 = t.planeDistance( m.mP3 );
|
||||
|
||||
if ( d1 > 0.001f || d2 > 0.001f || d3 > 0.001f ) // can't be near coplaner!
|
||||
{
|
||||
|
||||
neardot = dot;
|
||||
|
||||
Vector3d<float> n1,n2,n3;
|
||||
|
||||
t.raySect( m.mP1, m.mNormal, m.mNear1 );
|
||||
t.raySect( m.mP2, m.mNormal, m.mNear2 );
|
||||
t.raySect( m.mP3, m.mNormal, m.mNear3 );
|
||||
|
||||
nearest = t;
|
||||
|
||||
ret = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ( ret )
|
||||
{
|
||||
if ( 0 )
|
||||
{
|
||||
CTriVector::const_iterator i;
|
||||
for (i=input_mesh.begin(); i!=input_mesh.end(); ++i)
|
||||
{
|
||||
const CTri &c = (*i);
|
||||
if ( c.mI1 != m.mI1 && c.mI2 != m.mI2 && c.mI3 != m.mI3 )
|
||||
{
|
||||
c.clip( m.mP1, m.mNear1 );
|
||||
c.clip( m.mP2, m.mNear2 );
|
||||
c.clip( m.mP3, m.mNear3 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//gLog->Display("*********************************************\r\n");
|
||||
//gLog->Display(" HullPlaneNearest: %0.4f,%0.4f,%0.4f %0.4f\r\n", nearest.mNormal.x, nearest.mNormal.y, nearest.mNormal.z, nearest.mPlaneD );
|
||||
|
||||
m.mC1 = m.mP1.Distance( m.mNear1 );
|
||||
m.mC2 = m.mP2.Distance( m.mNear2 );
|
||||
m.mC3 = m.mP3.Distance( m.mNear3 );
|
||||
|
||||
m.mConcavity = m.mC1;
|
||||
|
||||
if ( m.mC2 > m.mConcavity ) m.mConcavity = m.mC2;
|
||||
if ( m.mC3 > m.mConcavity ) m.mConcavity = m.mC3;
|
||||
|
||||
#if 0
|
||||
callback->ConvexDebugTri( m.mP1.Ptr(), m.mP2.Ptr(), m.mP3.Ptr(), 0x00FF00 );
|
||||
callback->ConvexDebugTri( m.mNear1.Ptr(), m.mNear2.Ptr(), m.mNear3.Ptr(), 0xFF0000 );
|
||||
|
||||
callback->ConvexDebugTri( m.mP1.Ptr(), m.mP1.Ptr(), m.mNear1.Ptr(), 0xFFFF00 );
|
||||
callback->ConvexDebugTri( m.mP2.Ptr(), m.mP2.Ptr(), m.mNear2.Ptr(), 0xFFFF00 );
|
||||
callback->ConvexDebugTri( m.mP3.Ptr(), m.mP3.Ptr(), m.mNear3.Ptr(), 0xFFFF00 );
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//gLog->Display("No match\r\n");
|
||||
}
|
||||
|
||||
//gLog->Display("*********************************************\r\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool isFeatureTri(CTri &t,CTriVector &flist,float fc,ConvexDecompInterface *callback,unsigned int color)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if ( t.mProcessed == 0 ) // if not already processed
|
||||
{
|
||||
|
||||
float c = t.mConcavity / fc; // must be within 80% of the concavity of the parent.
|
||||
|
||||
if ( c > 0.85f )
|
||||
{
|
||||
// see if this triangle is a 'feature' triangle. Meaning it shares an
|
||||
// edge with any existing feature triangle and is within roughly the same
|
||||
// concavity of the parent.
|
||||
if ( flist.size() )
|
||||
{
|
||||
CTriVector::iterator i;
|
||||
for (i=flist.begin(); i!=flist.end(); ++i)
|
||||
{
|
||||
CTri &ftri = (*i);
|
||||
if ( ftri.sharesEdge(t) )
|
||||
{
|
||||
t.mProcessed = 2; // it is now part of a feature.
|
||||
flist.push_back(t); // add it to the feature list.
|
||||
// callback->ConvexDebugTri( t.mP1.Ptr(), t.mP2.Ptr(),t.mP3.Ptr(), color );
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
t.mProcessed = 2;
|
||||
flist.push_back(t); // add it to the feature list.
|
||||
// callback->ConvexDebugTri( t.mP1.Ptr(), t.mP2.Ptr(),t.mP3.Ptr(), color );
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
t.mProcessed = 1; // eliminated for this feature, but might be valid for the next one..
|
||||
}
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
float computeConcavity(unsigned int vcount,
|
||||
const float *vertices,
|
||||
unsigned int tcount,
|
||||
const unsigned int *indices,
|
||||
ConvexDecompInterface *callback,
|
||||
float *plane, // plane equation to split on
|
||||
float &volume)
|
||||
{
|
||||
|
||||
|
||||
float cret = 0;
|
||||
volume = 1;
|
||||
|
||||
HullResult result;
|
||||
HullLibrary hl;
|
||||
HullDesc desc;
|
||||
|
||||
desc.mMaxFaces = 256;
|
||||
desc.mMaxVertices = 256;
|
||||
desc.SetHullFlag(QF_TRIANGLES);
|
||||
|
||||
|
||||
desc.mVcount = vcount;
|
||||
desc.mVertices = vertices;
|
||||
desc.mVertexStride = sizeof(float)*3;
|
||||
|
||||
HullError ret = hl.CreateConvexHull(desc,result);
|
||||
|
||||
if ( ret == QE_OK )
|
||||
{
|
||||
|
||||
float bmin[3];
|
||||
float bmax[3];
|
||||
|
||||
float diagonal = getBoundingRegion( result.mNumOutputVertices, result.mOutputVertices, sizeof(float)*3, bmin, bmax );
|
||||
|
||||
float dx = bmax[0] - bmin[0];
|
||||
float dy = bmax[1] - bmin[1];
|
||||
float dz = bmax[2] - bmin[2];
|
||||
|
||||
Vector3d<float> center;
|
||||
|
||||
center.x = bmin[0] + dx*0.5f;
|
||||
center.y = bmin[1] + dy*0.5f;
|
||||
center.z = bmin[2] + dz*0.5f;
|
||||
|
||||
float boundVolume = dx*dy*dz;
|
||||
|
||||
volume = computeMeshVolume2( result.mOutputVertices, result.mNumFaces, result.mIndices );
|
||||
|
||||
#if 1
|
||||
// ok..now..for each triangle on the original mesh..
|
||||
// we extrude the points to the nearest point on the hull.
|
||||
const unsigned int *source = result.mIndices;
|
||||
|
||||
CTriVector tris;
|
||||
|
||||
for (unsigned int i=0; i<result.mNumFaces; i++)
|
||||
{
|
||||
unsigned int i1 = *source++;
|
||||
unsigned int i2 = *source++;
|
||||
unsigned int i3 = *source++;
|
||||
|
||||
const float *p1 = &result.mOutputVertices[i1*3];
|
||||
const float *p2 = &result.mOutputVertices[i2*3];
|
||||
const float *p3 = &result.mOutputVertices[i3*3];
|
||||
|
||||
// callback->ConvexDebugTri(p1,p2,p3,0xFFFFFF);
|
||||
|
||||
CTri t(p1,p2,p3,i1,i2,i3); //
|
||||
tris.push_back(t);
|
||||
}
|
||||
|
||||
// we have not pre-computed the plane equation for each triangle in the convex hull..
|
||||
|
||||
float totalVolume = 0;
|
||||
|
||||
CTriVector ftris; // 'feature' triangles.
|
||||
|
||||
const unsigned int *src = indices;
|
||||
|
||||
|
||||
float maxc=0;
|
||||
|
||||
|
||||
if ( 1 )
|
||||
{
|
||||
CTriVector input_mesh;
|
||||
if ( 1 )
|
||||
{
|
||||
const unsigned int *src = indices;
|
||||
for (unsigned int i=0; i<tcount; i++)
|
||||
{
|
||||
|
||||
unsigned int i1 = *src++;
|
||||
unsigned int i2 = *src++;
|
||||
unsigned int i3 = *src++;
|
||||
|
||||
const float *p1 = &vertices[i1*3];
|
||||
const float *p2 = &vertices[i2*3];
|
||||
const float *p3 = &vertices[i3*3];
|
||||
|
||||
CTri t(p1,p2,p3,i1,i2,i3);
|
||||
input_mesh.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
CTri maxctri;
|
||||
|
||||
for (unsigned int i=0; i<tcount; i++)
|
||||
{
|
||||
|
||||
unsigned int i1 = *src++;
|
||||
unsigned int i2 = *src++;
|
||||
unsigned int i3 = *src++;
|
||||
|
||||
const float *p1 = &vertices[i1*3];
|
||||
const float *p2 = &vertices[i2*3];
|
||||
const float *p3 = &vertices[i3*3];
|
||||
|
||||
CTri t(p1,p2,p3,i1,i2,i3);
|
||||
|
||||
featureMatch(t, tris, callback, input_mesh );
|
||||
|
||||
if ( t.mConcavity > CONCAVE_THRESH )
|
||||
{
|
||||
|
||||
if ( t.mConcavity > maxc )
|
||||
{
|
||||
maxc = t.mConcavity;
|
||||
maxctri = t;
|
||||
}
|
||||
|
||||
float v = t.getVolume(0);
|
||||
totalVolume+=v;
|
||||
ftris.push_back(t);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ( ftris.size() && 0 )
|
||||
{
|
||||
|
||||
// ok..now we extract the triangles which form the maximum concavity.
|
||||
CTriVector major_feature;
|
||||
float maxarea = 0;
|
||||
|
||||
while ( maxc > CONCAVE_THRESH )
|
||||
{
|
||||
|
||||
unsigned int color = getDebugColor(); //
|
||||
|
||||
CTriVector flist;
|
||||
|
||||
bool found;
|
||||
|
||||
float totalarea = 0;
|
||||
|
||||
do
|
||||
{
|
||||
found = false;
|
||||
CTriVector::iterator i;
|
||||
for (i=ftris.begin(); i!=ftris.end(); ++i)
|
||||
{
|
||||
CTri &t = (*i);
|
||||
if ( isFeatureTri(t,flist,maxc,callback,color) )
|
||||
{
|
||||
found = true;
|
||||
totalarea+=t.area();
|
||||
}
|
||||
}
|
||||
} while ( found );
|
||||
|
||||
|
||||
if ( totalarea > maxarea )
|
||||
{
|
||||
major_feature = flist;
|
||||
maxarea = totalarea;
|
||||
}
|
||||
|
||||
maxc = 0;
|
||||
|
||||
for (unsigned int i=0; i<ftris.size(); i++)
|
||||
{
|
||||
CTri &t = ftris[i];
|
||||
if ( t.mProcessed != 2 )
|
||||
{
|
||||
t.mProcessed = 0;
|
||||
if ( t.mConcavity > maxc )
|
||||
{
|
||||
maxc = t.mConcavity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int color = getDebugColor();
|
||||
|
||||
WpointVector list;
|
||||
for (unsigned int i=0; i<major_feature.size(); ++i)
|
||||
{
|
||||
major_feature[i].addWeighted(list,callback);
|
||||
major_feature[i].debug(color,callback);
|
||||
}
|
||||
|
||||
getBestFitPlane( list.size(), &list[0].mPoint.x, sizeof(Wpoint), &list[0].mWeight, sizeof(Wpoint), plane );
|
||||
|
||||
computeSplitPlane( vcount, vertices, tcount, indices, callback, plane );
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
computeSplitPlane( vcount, vertices, tcount, indices, callback, plane );
|
||||
}
|
||||
#endif
|
||||
|
||||
cret = totalVolume;
|
||||
|
||||
hl.ReleaseResult(result);
|
||||
}
|
||||
|
||||
|
||||
return cret;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
60
Extras/ConvexDecomposition/concavity.h
Normal file
60
Extras/ConvexDecomposition/concavity.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef COMPUTE_CONCAVITY_H
|
||||
|
||||
#define COMPUTE_CONCAVITY_H
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
|
||||
namespace ConvexDecomposition
|
||||
{
|
||||
|
||||
class ConvexDecompInterface;
|
||||
|
||||
// compute's how 'concave' this object is and returns the total volume of the
|
||||
// convex hull as well as the volume of the 'concavity' which was found.
|
||||
float computeConcavity(unsigned int vcount,
|
||||
const float *vertices,
|
||||
unsigned int tcount,
|
||||
const unsigned int *indices,
|
||||
ConvexDecompInterface *callback,
|
||||
float *plane,
|
||||
float &volume);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
202
Extras/ConvexDecomposition/fitsphere.cpp
Normal file
202
Extras/ConvexDecomposition/fitsphere.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "fitsphere.h"
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
/*
|
||||
An Efficient Bounding Sphere
|
||||
by Jack Ritter
|
||||
from "Graphics Gems", Academic Press, 1990
|
||||
*/
|
||||
|
||||
/* Routine to calculate tight bounding sphere over */
|
||||
/* a set of points in 3D */
|
||||
/* This contains the routine find_bounding_sphere(), */
|
||||
/* the struct definition, and the globals used for parameters. */
|
||||
/* The abs() of all coordinates must be < BIGNUMBER */
|
||||
/* Code written by Jack Ritter and Lyle Rains. */
|
||||
|
||||
#define BIGNUMBER 100000000.0 /* hundred million */
|
||||
|
||||
static inline void Set(float *n,float x,float y,float z)
|
||||
{
|
||||
n[0] = x;
|
||||
n[1] = y;
|
||||
n[2] = z;
|
||||
};
|
||||
|
||||
static inline void Copy(float *dest,const float *source)
|
||||
{
|
||||
dest[0] = source[0];
|
||||
dest[1] = source[1];
|
||||
dest[2] = source[2];
|
||||
}
|
||||
|
||||
float computeBoundingSphere(unsigned int vcount,const float *points,float *center)
|
||||
{
|
||||
|
||||
float mRadius;
|
||||
float mRadius2;
|
||||
|
||||
float xmin[3];
|
||||
float xmax[3];
|
||||
float ymin[3];
|
||||
float ymax[3];
|
||||
float zmin[3];
|
||||
float zmax[3];
|
||||
float dia1[3];
|
||||
float dia2[3];
|
||||
|
||||
/* FIRST PASS: find 6 minima/maxima points */
|
||||
Set(xmin,BIGNUMBER,BIGNUMBER,BIGNUMBER);
|
||||
Set(xmax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER);
|
||||
Set(ymin,BIGNUMBER,BIGNUMBER,BIGNUMBER);
|
||||
Set(ymax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER);
|
||||
Set(zmin,BIGNUMBER,BIGNUMBER,BIGNUMBER);
|
||||
Set(zmax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER);
|
||||
|
||||
for (unsigned i=0; i<vcount; i++)
|
||||
{
|
||||
const float *caller_p = &points[i*3];
|
||||
|
||||
if (caller_p[0]<xmin[0])
|
||||
Copy(xmin,caller_p); /* New xminimum point */
|
||||
if (caller_p[0]>xmax[0])
|
||||
Copy(xmax,caller_p);
|
||||
if (caller_p[1]<ymin[1])
|
||||
Copy(ymin,caller_p);
|
||||
if (caller_p[1]>ymax[1])
|
||||
Copy(ymax,caller_p);
|
||||
if (caller_p[2]<zmin[2])
|
||||
Copy(zmin,caller_p);
|
||||
if (caller_p[2]>zmax[2])
|
||||
Copy(zmax,caller_p);
|
||||
}
|
||||
|
||||
/* Set xspan = distance between the 2 points xmin & xmax (squared) */
|
||||
float dx = xmax[0] - xmin[0];
|
||||
float dy = xmax[1] - xmin[1];
|
||||
float dz = xmax[2] - xmin[2];
|
||||
float xspan = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
/* Same for y & z spans */
|
||||
dx = ymax[0] - ymin[0];
|
||||
dy = ymax[1] - ymin[1];
|
||||
dz = ymax[2] - ymin[2];
|
||||
float yspan = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
dx = zmax[0] - zmin[0];
|
||||
dy = zmax[1] - zmin[1];
|
||||
dz = zmax[2] - zmin[2];
|
||||
float zspan = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
/* Set points dia1 & dia2 to the maximally separated pair */
|
||||
Copy(dia1,xmin);
|
||||
Copy(dia2,xmax); /* assume xspan biggest */
|
||||
float maxspan = xspan;
|
||||
|
||||
if (yspan>maxspan)
|
||||
{
|
||||
maxspan = yspan;
|
||||
Copy(dia1,ymin);
|
||||
Copy(dia2,ymax);
|
||||
}
|
||||
|
||||
if (zspan>maxspan)
|
||||
{
|
||||
Copy(dia1,zmin);
|
||||
Copy(dia2,zmax);
|
||||
}
|
||||
|
||||
|
||||
/* dia1,dia2 is a diameter of initial sphere */
|
||||
/* calc initial center */
|
||||
center[0] = (dia1[0]+dia2[0])*0.5f;
|
||||
center[1] = (dia1[1]+dia2[1])*0.5f;
|
||||
center[2] = (dia1[2]+dia2[2])*0.5f;
|
||||
|
||||
/* calculate initial radius**2 and radius */
|
||||
|
||||
dx = dia2[0]-center[0]; /* x component of radius vector */
|
||||
dy = dia2[1]-center[1]; /* y component of radius vector */
|
||||
dz = dia2[2]-center[2]; /* z component of radius vector */
|
||||
|
||||
mRadius2 = dx*dx + dy*dy + dz*dz;
|
||||
mRadius = float(sqrt(mRadius2));
|
||||
|
||||
/* SECOND PASS: increment current sphere */
|
||||
|
||||
if ( 1 )
|
||||
{
|
||||
for (unsigned i=0; i<vcount; i++)
|
||||
{
|
||||
const float *caller_p = &points[i*3];
|
||||
|
||||
dx = caller_p[0]-center[0];
|
||||
dy = caller_p[1]-center[1];
|
||||
dz = caller_p[2]-center[2];
|
||||
|
||||
float old_to_p_sq = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
if (old_to_p_sq > mRadius2) /* do r**2 test first */
|
||||
{ /* this point is outside of current sphere */
|
||||
float old_to_p = float(sqrt(old_to_p_sq));
|
||||
/* calc radius of new sphere */
|
||||
mRadius = (mRadius + old_to_p) * 0.5f;
|
||||
mRadius2 = mRadius*mRadius; /* for next r**2 compare */
|
||||
float old_to_new = old_to_p - mRadius;
|
||||
|
||||
/* calc center of new sphere */
|
||||
|
||||
float recip = 1.0f /old_to_p;
|
||||
|
||||
float cx = (mRadius*center[0] + old_to_new*caller_p[0]) * recip;
|
||||
float cy = (mRadius*center[1] + old_to_new*caller_p[1]) * recip;
|
||||
float cz = (mRadius*center[2] + old_to_new*caller_p[2]) * recip;
|
||||
|
||||
Set(center,cx,cy,cz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mRadius;
|
||||
}
|
||||
|
||||
|
||||
43
Extras/ConvexDecomposition/fitsphere.h
Normal file
43
Extras/ConvexDecomposition/fitsphere.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef FIT_SPHERE_H
|
||||
|
||||
#define FIT_SPHERE_H
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
|
||||
float computeBoundingSphere(unsigned int vcount,const float *points,float *center);
|
||||
|
||||
#endif
|
||||
256
Extras/ConvexDecomposition/float_math.cpp
Normal file
256
Extras/ConvexDecomposition/float_math.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "float_math.h"
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
void fm_inverseRT(const float *matrix,const float *pos,float *t) // inverse rotate translate the point.
|
||||
{
|
||||
|
||||
float _x = pos[0] - matrix[3*4+0];
|
||||
float _y = pos[1] - matrix[3*4+1];
|
||||
float _z = pos[2] - matrix[3*4+2];
|
||||
|
||||
// Multiply inverse-translated source vector by inverted rotation transform
|
||||
|
||||
t[0] = (matrix[0*4+0] * _x) + (matrix[0*4+1] * _y) + (matrix[0*4+2] * _z);
|
||||
t[1] = (matrix[1*4+0] * _x) + (matrix[1*4+1] * _y) + (matrix[1*4+2] * _z);
|
||||
t[2] = (matrix[2*4+0] * _x) + (matrix[2*4+1] * _y) + (matrix[2*4+2] * _z);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void fm_identity(float *matrix) // set 4x4 matrix to identity.
|
||||
{
|
||||
matrix[0*4+0] = 1;
|
||||
matrix[1*4+1] = 1;
|
||||
matrix[2*4+2] = 1;
|
||||
matrix[3*4+3] = 1;
|
||||
|
||||
matrix[1*4+0] = 0;
|
||||
matrix[2*4+0] = 0;
|
||||
matrix[3*4+0] = 0;
|
||||
|
||||
matrix[0*4+1] = 0;
|
||||
matrix[2*4+1] = 0;
|
||||
matrix[3*4+1] = 0;
|
||||
|
||||
matrix[0*4+2] = 0;
|
||||
matrix[1*4+2] = 0;
|
||||
matrix[3*4+2] = 0;
|
||||
|
||||
matrix[0*4+3] = 0;
|
||||
matrix[1*4+3] = 0;
|
||||
matrix[2*4+3] = 0;
|
||||
|
||||
}
|
||||
|
||||
void fm_eulerMatrix(float ax,float ay,float az,float *matrix) // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
|
||||
{
|
||||
float quat[4];
|
||||
fm_eulerToQuat(ax,ay,az,quat);
|
||||
fm_quatToMatrix(quat,matrix);
|
||||
}
|
||||
|
||||
void fm_getAABB(unsigned int vcount,const float *points,unsigned int pstride,float *bmin,float *bmax)
|
||||
{
|
||||
|
||||
const unsigned char *source = (const unsigned char *) points;
|
||||
|
||||
bmin[0] = points[0];
|
||||
bmin[1] = points[1];
|
||||
bmin[2] = points[2];
|
||||
|
||||
bmax[0] = points[0];
|
||||
bmax[1] = points[1];
|
||||
bmax[2] = points[2];
|
||||
|
||||
|
||||
for (unsigned int i=1; i<vcount; i++)
|
||||
{
|
||||
source+=pstride;
|
||||
const float *p = (const float *) source;
|
||||
|
||||
if ( p[0] < bmin[0] ) bmin[0] = p[0];
|
||||
if ( p[1] < bmin[1] ) bmin[1] = p[1];
|
||||
if ( p[2] < bmin[2] ) bmin[2] = p[2];
|
||||
|
||||
if ( p[0] > bmax[0] ) bmax[0] = p[0];
|
||||
if ( p[1] > bmax[1] ) bmax[1] = p[1];
|
||||
if ( p[2] > bmax[2] ) bmax[2] = p[2];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fm_eulerToQuat(float roll,float pitch,float yaw,float *quat) // convert euler angles to quaternion.
|
||||
{
|
||||
roll *= 0.5f;
|
||||
pitch *= 0.5f;
|
||||
yaw *= 0.5f;
|
||||
|
||||
float cr = cosf(roll);
|
||||
float cp = cosf(pitch);
|
||||
float cy = cosf(yaw);
|
||||
|
||||
float sr = sinf(roll);
|
||||
float sp = sinf(pitch);
|
||||
float sy = sinf(yaw);
|
||||
|
||||
float cpcy = cp * cy;
|
||||
float spsy = sp * sy;
|
||||
float spcy = sp * cy;
|
||||
float cpsy = cp * sy;
|
||||
|
||||
quat[0] = ( sr * cpcy - cr * spsy);
|
||||
quat[1] = ( cr * spcy + sr * cpsy);
|
||||
quat[2] = ( cr * cpsy - sr * spcy);
|
||||
quat[3] = cr * cpcy + sr * spsy;
|
||||
}
|
||||
|
||||
void fm_quatToMatrix(const float *quat,float *matrix) // convert quaterinion rotation to matrix, zeros out the translation component.
|
||||
{
|
||||
|
||||
float xx = quat[0]*quat[0];
|
||||
float yy = quat[1]*quat[1];
|
||||
float zz = quat[2]*quat[2];
|
||||
float xy = quat[0]*quat[1];
|
||||
float xz = quat[0]*quat[2];
|
||||
float yz = quat[1]*quat[2];
|
||||
float wx = quat[3]*quat[0];
|
||||
float wy = quat[3]*quat[1];
|
||||
float wz = quat[3]*quat[2];
|
||||
|
||||
matrix[0*4+0] = 1 - 2 * ( yy + zz );
|
||||
matrix[1*4+0] = 2 * ( xy - wz );
|
||||
matrix[2*4+0] = 2 * ( xz + wy );
|
||||
|
||||
matrix[0*4+1] = 2 * ( xy + wz );
|
||||
matrix[1*4+1] = 1 - 2 * ( xx + zz );
|
||||
matrix[2*4+1] = 2 * ( yz - wx );
|
||||
|
||||
matrix[0*4+2] = 2 * ( xz - wy );
|
||||
matrix[1*4+2] = 2 * ( yz + wx );
|
||||
matrix[2*4+2] = 1 - 2 * ( xx + yy );
|
||||
|
||||
matrix[3*4+0] =(float) matrix[3*4+1] = matrix[3*4+2] = 0.0f;
|
||||
matrix[0*4+3] =(float) matrix[1*4+3] = matrix[2*4+3] = 0.0f;
|
||||
matrix[3*4+3] =(float) 1.0f;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void fm_quatRotate(const float *quat,const float *v,float *r) // rotate a vector directly by a quaternion.
|
||||
{
|
||||
float left[4];
|
||||
|
||||
left[0] = quat[3]*v[0] + quat[1]*v[2] - v[1]*quat[2];
|
||||
left[1] = quat[3]*v[1] + quat[2]*v[0] - v[2]*quat[0];
|
||||
left[2] = quat[3]*v[2] + quat[0]*v[1] - v[0]*quat[1];
|
||||
left[3] = - quat[0]*v[0] - quat[1]*v[1] - quat[2]*v[2];
|
||||
|
||||
r[0] = (left[3]*-quat[0]) + (quat[3]*left[0]) + (left[1]*-quat[2]) - (-quat[1]*left[2]);
|
||||
r[1] = (left[3]*-quat[1]) + (quat[3]*left[1]) + (left[2]*-quat[0]) - (-quat[2]*left[0]);
|
||||
r[2] = (left[3]*-quat[2]) + (quat[3]*left[2]) + (left[0]*-quat[1]) - (-quat[0]*left[1]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void fm_getTranslation(const float *matrix,float *t)
|
||||
{
|
||||
t[0] = matrix[3*4+0];
|
||||
t[1] = matrix[3*4+1];
|
||||
t[2] = matrix[3*4+2];
|
||||
}
|
||||
|
||||
void fm_matrixToQuat(const float *matrix,float *quat) // convert the 3x3 portion of a 4x4 matrix into a quaterion as x,y,z,w
|
||||
{
|
||||
|
||||
float tr = matrix[0*4+0] + matrix[1*4+1] + matrix[2*4+2];
|
||||
|
||||
// check the diagonal
|
||||
|
||||
if (tr > 0.0f )
|
||||
{
|
||||
float s = (float) sqrt ( (double) (tr + 1.0f) );
|
||||
quat[3] = s * 0.5f;
|
||||
s = 0.5f / s;
|
||||
quat[0] = (matrix[1*4+2] - matrix[2*4+1]) * s;
|
||||
quat[1] = (matrix[2*4+0] - matrix[0*4+2]) * s;
|
||||
quat[2] = (matrix[0*4+1] - matrix[1*4+0]) * s;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// diagonal is negative
|
||||
int nxt[3] = {1, 2, 0};
|
||||
float qa[4];
|
||||
|
||||
int i = 0;
|
||||
|
||||
if (matrix[1*4+1] > matrix[0*4+0]) i = 1;
|
||||
if (matrix[2*4+2] > matrix[i*4+i]) i = 2;
|
||||
|
||||
int j = nxt[i];
|
||||
int k = nxt[j];
|
||||
|
||||
float s = sqrtf ( ((matrix[i*4+i] - (matrix[j*4+j] + matrix[k*4+k])) + 1.0f) );
|
||||
|
||||
qa[i] = s * 0.5f;
|
||||
|
||||
if (s != 0.0f ) s = 0.5f / s;
|
||||
|
||||
qa[3] = (matrix[j*4+k] - matrix[k*4+j]) * s;
|
||||
qa[j] = (matrix[i*4+j] + matrix[j*4+i]) * s;
|
||||
qa[k] = (matrix[i*4+k] + matrix[k*4+i]) * s;
|
||||
|
||||
quat[0] = qa[0];
|
||||
quat[1] = qa[1];
|
||||
quat[2] = qa[2];
|
||||
quat[3] = qa[3];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
float fm_sphereVolume(float radius) // return's the volume of a sphere of this radius (4/3 PI * R cubed )
|
||||
{
|
||||
return (4.0f / 3.0f ) * FM_PI * radius * radius * radius;
|
||||
}
|
||||
63
Extras/ConvexDecomposition/float_math.h
Normal file
63
Extras/ConvexDecomposition/float_math.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef FLOAT_MATH_H
|
||||
|
||||
#define FLOAT_MATH_H
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
// a set of routines that last you do common 3d math
|
||||
// operations without any vector, matrix, or quaternion
|
||||
// classes or templates.
|
||||
//
|
||||
// a vector (or point) is a 'float *' to 3 floating point numbers.
|
||||
// a matrix is a 'float *' to an array of 16 floating point numbers representing a 4x4 transformation matrix compatible with D3D or OGL
|
||||
// a quaternion is a 'float *' to 4 floats representing a quaternion x,y,z,w
|
||||
|
||||
const float FM_PI = 3.141592654f;
|
||||
const float FM_DEG_TO_RAD = ((2.0f * FM_PI) / 360.0f);
|
||||
const float FM_RAD_TO_DEG = (360.0f / (2.0f * FM_PI));
|
||||
|
||||
void fm_identity(float *matrix); // set 4x4 matrix to identity.
|
||||
void fm_inverseRT(const float *matrix,const float *pos,float *t); // inverse rotate translate the point.
|
||||
void fm_eulerMatrix(float ax,float ay,float az,float *matrix); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
|
||||
void fm_getAABB(unsigned int vcount,const float *points,unsigned int pstride,float *bmin,float *bmax);
|
||||
void fm_eulerToQuat(float roll,float pitch,float yaw,float *quat); // convert euler angles to quaternion.
|
||||
void fm_quatToMatrix(const float *quat,float *matrix); // convert quaterinion rotation to matrix, translation set to zero.
|
||||
void fm_quatRotate(const float *quat,const float *v,float *r); // rotate a vector directly by a quaternion.
|
||||
void fm_getTranslation(const float *matrix,float *t);
|
||||
void fm_matrixToQuat(const float *matrix,float *quat); // convert the 3x3 portion of a 4x4 matrix into a quaterion as x,y,z,w
|
||||
float fm_sphereVolume(float radius); // return's the volume of a sphere of this radius (4/3 PI * R cubed )
|
||||
|
||||
#endif
|
||||
128
Extras/ConvexDecomposition/meshvolume.cpp
Normal file
128
Extras/ConvexDecomposition/meshvolume.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#include "meshvolume.h"
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
inline float det(const float *p1,const float *p2,const float *p3)
|
||||
{
|
||||
return p1[0]*p2[1]*p3[2] + p2[0]*p3[1]*p1[2] + p3[0]*p1[1]*p2[2] -p1[0]*p3[1]*p2[2] - p2[0]*p1[1]*p3[2] - p3[0]*p2[1]*p1[2];
|
||||
}
|
||||
|
||||
float computeMeshVolume(const float *vertices,unsigned int tcount,const unsigned int *indices)
|
||||
{
|
||||
float volume = 0;
|
||||
|
||||
const float *p0 = vertices;
|
||||
for (unsigned int i=0; i<tcount; i++,indices+=3)
|
||||
{
|
||||
|
||||
const float *p1 = &vertices[ indices[0]*3 ];
|
||||
const float *p2 = &vertices[ indices[1]*3 ];
|
||||
const float *p3 = &vertices[ indices[2]*3 ];
|
||||
|
||||
volume+=det(p1,p2,p3); // compute the volume of the tetrahedran relative to the origin.
|
||||
}
|
||||
|
||||
volume*=(1.0f/6.0f);
|
||||
if ( volume < 0 )
|
||||
volume*=-1;
|
||||
return volume;
|
||||
}
|
||||
|
||||
|
||||
inline void CrossProduct(const float *a,const float *b,float *cross)
|
||||
{
|
||||
cross[0] = a[1]*b[2] - a[2]*b[1];
|
||||
cross[1] = a[2]*b[0] - a[0]*b[2];
|
||||
cross[2] = a[0]*b[1] - a[1]*b[0];
|
||||
}
|
||||
|
||||
inline float DotProduct(const float *a,const float *b)
|
||||
{
|
||||
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
||||
}
|
||||
|
||||
inline float tetVolume(const float *p0,const float *p1,const float *p2,const float *p3)
|
||||
{
|
||||
float a[3];
|
||||
float b[3];
|
||||
float c[3];
|
||||
|
||||
a[0] = p1[0] - p0[0];
|
||||
a[1] = p1[1] - p0[1];
|
||||
a[2] = p1[2] - p0[2];
|
||||
|
||||
b[0] = p2[0] - p0[0];
|
||||
b[1] = p2[1] - p0[1];
|
||||
b[2] = p2[2] - p0[2];
|
||||
|
||||
c[0] = p3[0] - p0[0];
|
||||
c[1] = p3[1] - p0[1];
|
||||
c[2] = p3[2] - p0[2];
|
||||
|
||||
float cross[3];
|
||||
|
||||
CrossProduct( b, c, cross );
|
||||
|
||||
float volume = DotProduct( a, cross );
|
||||
|
||||
if ( volume < 0 )
|
||||
return -volume;
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
inline float det(const float *p0,const float *p1,const float *p2,const float *p3)
|
||||
{
|
||||
return p1[0]*p2[1]*p3[2] + p2[0]*p3[1]*p1[2] + p3[0]*p1[1]*p2[2] -p1[0]*p3[1]*p2[2] - p2[0]*p1[1]*p3[2] - p3[0]*p2[1]*p1[2];
|
||||
}
|
||||
|
||||
float computeMeshVolume2(const float *vertices,unsigned int tcount,const unsigned int *indices)
|
||||
{
|
||||
float volume = 0;
|
||||
|
||||
const float *p0 = vertices;
|
||||
for (unsigned int i=0; i<tcount; i++,indices+=3)
|
||||
{
|
||||
|
||||
const float *p1 = &vertices[ indices[0]*3 ];
|
||||
const float *p2 = &vertices[ indices[1]*3 ];
|
||||
const float *p3 = &vertices[ indices[2]*3 ];
|
||||
|
||||
volume+=tetVolume(p0,p1,p2,p3); // compute the volume of the tetrahdren relative to the root vertice
|
||||
}
|
||||
|
||||
return volume * (1.0f / 6.0f );
|
||||
}
|
||||
|
||||
45
Extras/ConvexDecomposition/meshvolume.h
Normal file
45
Extras/ConvexDecomposition/meshvolume.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef MESH_VOLUME_H
|
||||
|
||||
#define MESH_VOLUME_H
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
|
||||
float computeMeshVolume(const float *vertices,unsigned int tcount,const unsigned int *indices);
|
||||
float computeMeshVolume2(const float *vertices,unsigned int tcount,const unsigned int *indices);
|
||||
|
||||
|
||||
#endif
|
||||
238
Extras/ConvexDecomposition/planetri.cpp
Normal file
238
Extras/ConvexDecomposition/planetri.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "planetri.h"
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
static inline float DistToPt(const float *p,const float *plane)
|
||||
{
|
||||
float x = p[0];
|
||||
float y = p[1];
|
||||
float z = p[2];
|
||||
float d = x*plane[0] + y*plane[1] + z*plane[2] + plane[3];
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
static PlaneTriResult getSidePlane(const float *p,const float *plane,float epsilon)
|
||||
{
|
||||
|
||||
float d = DistToPt(p,plane);
|
||||
|
||||
if ( (d+epsilon) > 0 )
|
||||
return PTR_FRONT; // it is 'in front' within the provided epsilon value.
|
||||
|
||||
return PTR_BACK;
|
||||
}
|
||||
|
||||
static void add(const float *p,float *dest,unsigned int tstride,unsigned int &pcount)
|
||||
{
|
||||
char *d = (char *) dest;
|
||||
d = d + pcount*tstride;
|
||||
dest = (float *) d;
|
||||
dest[0] = p[0];
|
||||
dest[1] = p[1];
|
||||
dest[2] = p[2];
|
||||
pcount++;
|
||||
assert( pcount <= 4 );
|
||||
}
|
||||
|
||||
|
||||
// assumes that the points are on opposite sides of the plane!
|
||||
static void intersect(const float *p1,const float *p2,float *split,const float *plane)
|
||||
{
|
||||
|
||||
float dp1 = DistToPt(p1,plane);
|
||||
float dp2 = DistToPt(p2,plane);
|
||||
|
||||
float dir[3];
|
||||
|
||||
dir[0] = p2[0] - p1[0];
|
||||
dir[1] = p2[1] - p1[1];
|
||||
dir[2] = p2[2] - p1[2];
|
||||
|
||||
float dot1 = dir[0]*plane[0] + dir[1]*plane[1] + dir[2]*plane[2];
|
||||
float dot2 = dp1 - plane[3];
|
||||
|
||||
float t = -(plane[3] + dot2 ) / dot1;
|
||||
|
||||
split[0] = (dir[0]*t)+p1[0];
|
||||
split[1] = (dir[1]*t)+p1[1];
|
||||
split[2] = (dir[2]*t)+p1[2];
|
||||
|
||||
}
|
||||
|
||||
PlaneTriResult planeTriIntersection(const float *plane, // the plane equation in Ax+By+Cz+D format
|
||||
const float *triangle, // the source triangle.
|
||||
unsigned int tstride, // stride in bytes of the input and output triangles
|
||||
float epsilon, // the co-planer epsilon value.
|
||||
float *front, // the triangle in front of the
|
||||
unsigned int &fcount, // number of vertices in the 'front' triangle
|
||||
float *back, // the triangle in back of the plane
|
||||
unsigned int &bcount) // the number of vertices in the 'back' triangle.
|
||||
{
|
||||
fcount = 0;
|
||||
bcount = 0;
|
||||
|
||||
const char *tsource = (const char *) triangle;
|
||||
|
||||
// get the three vertices of the triangle.
|
||||
const float *p1 = (const float *) (tsource);
|
||||
const float *p2 = (const float *) (tsource+tstride);
|
||||
const float *p3 = (const float *) (tsource+tstride*2);
|
||||
|
||||
|
||||
PlaneTriResult r1 = getSidePlane(p1,plane,epsilon); // compute the side of the plane each vertex is on
|
||||
PlaneTriResult r2 = getSidePlane(p2,plane,epsilon);
|
||||
PlaneTriResult r3 = getSidePlane(p3,plane,epsilon);
|
||||
|
||||
if ( r1 == r2 && r1 == r3 ) // if all three vertices are on the same side of the plane.
|
||||
{
|
||||
if ( r1 == PTR_FRONT ) // if all three are in front of the plane, then copy to the 'front' output triangle.
|
||||
{
|
||||
add(p1,front,tstride,fcount);
|
||||
add(p2,front,tstride,fcount);
|
||||
add(p3,front,tstride,fcount);
|
||||
}
|
||||
else
|
||||
{
|
||||
add(p1,back,tstride,bcount); // if all three are in 'abck' then copy to the 'back' output triangle.
|
||||
add(p2,back,tstride,bcount);
|
||||
add(p3,back,tstride,bcount);
|
||||
}
|
||||
return r1; // if all three points are on the same side of the plane return result
|
||||
}
|
||||
|
||||
// ok.. we need to split the triangle at the plane.
|
||||
|
||||
// First test ray segment P1 to P2
|
||||
if ( r1 == r2 ) // if these are both on the same side...
|
||||
{
|
||||
if ( r1 == PTR_FRONT )
|
||||
{
|
||||
add( p1, front, tstride, fcount );
|
||||
add( p2, front, tstride, fcount );
|
||||
}
|
||||
else
|
||||
{
|
||||
add( p1, back, tstride, bcount );
|
||||
add( p2, back, tstride, bcount );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float split[3]; // split the point
|
||||
intersect(p1,p2,split,plane);
|
||||
|
||||
if ( r1 == PTR_FRONT )
|
||||
{
|
||||
|
||||
add(p1, front, tstride, fcount );
|
||||
add(split, front, tstride, fcount );
|
||||
|
||||
add(split, back, tstride, bcount );
|
||||
add(p2, back, tstride, bcount );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
add(p1, back, tstride, bcount );
|
||||
add(split, back, tstride, bcount );
|
||||
|
||||
add(split, front, tstride, fcount );
|
||||
add(p2, front, tstride, fcount );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Next test ray segment P2 to P3
|
||||
if ( r2 == r3 ) // if these are both on the same side...
|
||||
{
|
||||
if ( r3 == PTR_FRONT )
|
||||
{
|
||||
add( p3, front, tstride, fcount );
|
||||
}
|
||||
else
|
||||
{
|
||||
add( p3, back, tstride, bcount );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float split[3]; // split the point
|
||||
intersect(p2,p3,split,plane);
|
||||
|
||||
if ( r3 == PTR_FRONT )
|
||||
{
|
||||
add(split, front, tstride, fcount );
|
||||
add(split, back, tstride, bcount );
|
||||
|
||||
add(p3, front, tstride, fcount );
|
||||
}
|
||||
else
|
||||
{
|
||||
add(split, front, tstride, fcount );
|
||||
add(split, back, tstride, bcount );
|
||||
|
||||
add(p3, back, tstride, bcount );
|
||||
}
|
||||
}
|
||||
|
||||
// Next test ray segment P3 to P1
|
||||
if ( r3 != r1 ) // if these are both on the same side...
|
||||
{
|
||||
float split[3]; // split the point
|
||||
|
||||
intersect(p3,p1,split,plane);
|
||||
|
||||
if ( r1 == PTR_FRONT )
|
||||
{
|
||||
add(split, front, tstride, fcount );
|
||||
add(split, back, tstride, bcount );
|
||||
}
|
||||
else
|
||||
{
|
||||
add(split, front, tstride, fcount );
|
||||
add(split, back, tstride, bcount );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return PTR_SPLIT;
|
||||
}
|
||||
58
Extras/ConvexDecomposition/planetri.h
Normal file
58
Extras/ConvexDecomposition/planetri.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef PLANE_TRI_H
|
||||
|
||||
#define PLANE_TRI_H
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
|
||||
enum PlaneTriResult
|
||||
{
|
||||
PTR_FRONT,
|
||||
PTR_BACK,
|
||||
PTR_SPLIT,
|
||||
};
|
||||
|
||||
PlaneTriResult planeTriIntersection(const float *plane, // the plane equation in Ax+By+Cz+D format
|
||||
const float *triangle, // the source position triangle.
|
||||
unsigned int tstride, // stride in bytes between vertices of the triangle.
|
||||
float epsilon, // the co-planer epsilon value.
|
||||
float *front, // the triangle in front of the
|
||||
unsigned int &fcount, // number of vertices in the 'front' triangle.
|
||||
float *back, // the triangle in back of the plane
|
||||
unsigned int &bcount); // the number of vertices in the 'back' triangle.
|
||||
|
||||
|
||||
#endif
|
||||
133
Extras/ConvexDecomposition/raytri.cpp
Normal file
133
Extras/ConvexDecomposition/raytri.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "raytri.h"
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
/* a = b - c */
|
||||
#define vector(a,b,c) \
|
||||
(a)[0] = (b)[0] - (c)[0]; \
|
||||
(a)[1] = (b)[1] - (c)[1]; \
|
||||
(a)[2] = (b)[2] - (c)[2];
|
||||
|
||||
|
||||
|
||||
#define innerProduct(v,q) \
|
||||
((v)[0] * (q)[0] + \
|
||||
(v)[1] * (q)[1] + \
|
||||
(v)[2] * (q)[2])
|
||||
|
||||
#define crossProduct(a,b,c) \
|
||||
(a)[0] = (b)[1] * (c)[2] - (c)[1] * (b)[2]; \
|
||||
(a)[1] = (b)[2] * (c)[0] - (c)[2] * (b)[0]; \
|
||||
(a)[2] = (b)[0] * (c)[1] - (c)[0] * (b)[1];
|
||||
|
||||
bool rayIntersectsTriangle(const float *p,const float *d,const float *v0,const float *v1,const float *v2,float &t)
|
||||
{
|
||||
|
||||
float e1[3],e2[3],h[3],s[3],q[3];
|
||||
float a,f,u,v;
|
||||
|
||||
vector(e1,v1,v0);
|
||||
vector(e2,v2,v0);
|
||||
crossProduct(h,d,e2);
|
||||
a = innerProduct(e1,h);
|
||||
|
||||
if (a > -0.00001 && a < 0.00001)
|
||||
return(false);
|
||||
|
||||
f = 1/a;
|
||||
vector(s,p,v0);
|
||||
u = f * (innerProduct(s,h));
|
||||
|
||||
if (u < 0.0 || u > 1.0)
|
||||
return(false);
|
||||
|
||||
crossProduct(q,s,e1);
|
||||
v = f * innerProduct(d,q);
|
||||
if (v < 0.0 || u + v > 1.0)
|
||||
return(false);
|
||||
// at this stage we can compute t to find out where
|
||||
// the intersection point is on the line
|
||||
t = f * innerProduct(e2,q);
|
||||
if (t > 0) // ray intersection
|
||||
return(true);
|
||||
else // this means that there is a line intersection
|
||||
// but not a ray intersection
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
bool lineIntersectsTriangle(const float *rayStart,const float *rayEnd,const float *p1,const float *p2,const float *p3,float *sect)
|
||||
{
|
||||
float dir[3];
|
||||
|
||||
dir[0] = rayEnd[0] - rayStart[0];
|
||||
dir[1] = rayEnd[1] - rayStart[1];
|
||||
dir[2] = rayEnd[2] - rayStart[2];
|
||||
|
||||
float d = sqrtf(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]);
|
||||
float r = 1.0f / d;
|
||||
|
||||
dir[0]*=r;
|
||||
dir[1]*=r;
|
||||
dir[2]*=r;
|
||||
|
||||
|
||||
float t;
|
||||
|
||||
bool ret = rayIntersectsTriangle(rayStart, dir, p1, p2, p3, t );
|
||||
|
||||
if ( ret )
|
||||
{
|
||||
if ( t > d )
|
||||
{
|
||||
sect[0] = rayStart[0] + dir[0]*t;
|
||||
sect[1] = rayStart[1] + dir[1]*t;
|
||||
sect[2] = rayStart[2] + dir[2]*t;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
45
Extras/ConvexDecomposition/raytri.h
Normal file
45
Extras/ConvexDecomposition/raytri.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef RAY_TRI_H
|
||||
|
||||
#define RAY_TRI_H
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
|
||||
// returns true if the ray intersects the triangle.
|
||||
bool lineIntersectsTriangle(const float *rayStart,const float *rayEnd,const float *p1,const float *p2,const float *p3,float *sect);
|
||||
bool rayIntersectsTriangle(const float *p,const float *d,const float *v0,const float *v1,const float *v2,float &t);
|
||||
|
||||
#endif
|
||||
308
Extras/ConvexDecomposition/splitplane.cpp
Normal file
308
Extras/ConvexDecomposition/splitplane.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
#include "splitplane.h"
|
||||
#include "ConvexDecomposition.h"
|
||||
#include "cd_vector.h"
|
||||
#include "cd_hull.h"
|
||||
#include "cd_wavefront.h"
|
||||
#include "bestfit.h"
|
||||
#include "PlaneTri.h"
|
||||
#include "vlookup.h"
|
||||
#include "meshvolume.h"
|
||||
|
||||
namespace ConvexDecomposition
|
||||
{
|
||||
|
||||
static void computePlane(const float *A,const float *B,const float *C,float *plane)
|
||||
{
|
||||
|
||||
float vx = (B[0] - C[0]);
|
||||
float vy = (B[1] - C[1]);
|
||||
float vz = (B[2] - C[2]);
|
||||
|
||||
float wx = (A[0] - B[0]);
|
||||
float wy = (A[1] - B[1]);
|
||||
float wz = (A[2] - B[2]);
|
||||
|
||||
float vw_x = vy * wz - vz * wy;
|
||||
float vw_y = vz * wx - vx * wz;
|
||||
float vw_z = vx * wy - vy * wx;
|
||||
|
||||
float mag = sqrtf((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
|
||||
|
||||
if ( mag < 0.000001f )
|
||||
{
|
||||
mag = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mag = 1.0f/mag;
|
||||
}
|
||||
|
||||
float x = vw_x * mag;
|
||||
float y = vw_y * mag;
|
||||
float z = vw_z * mag;
|
||||
|
||||
|
||||
float D = 0.0f - ((x*A[0])+(y*A[1])+(z*A[2]));
|
||||
|
||||
plane[0] = x;
|
||||
plane[1] = y;
|
||||
plane[2] = z;
|
||||
plane[3] = D;
|
||||
|
||||
}
|
||||
|
||||
class Rect3d
|
||||
{
|
||||
public:
|
||||
Rect3d(void) { };
|
||||
|
||||
Rect3d(const float *bmin,const float *bmax)
|
||||
{
|
||||
|
||||
mMin[0] = bmin[0];
|
||||
mMin[1] = bmin[1];
|
||||
mMin[2] = bmin[2];
|
||||
|
||||
mMax[0] = bmax[0];
|
||||
mMax[1] = bmax[1];
|
||||
mMax[2] = bmax[2];
|
||||
|
||||
}
|
||||
|
||||
void SetMin(const float *bmin)
|
||||
{
|
||||
mMin[0] = bmin[0];
|
||||
mMin[1] = bmin[1];
|
||||
mMin[2] = bmin[2];
|
||||
}
|
||||
|
||||
void SetMax(const float *bmax)
|
||||
{
|
||||
mMax[0] = bmax[0];
|
||||
mMax[1] = bmax[1];
|
||||
mMax[2] = bmax[2];
|
||||
}
|
||||
|
||||
void SetMin(float x,float y,float z)
|
||||
{
|
||||
mMin[0] = x;
|
||||
mMin[1] = y;
|
||||
mMin[2] = z;
|
||||
}
|
||||
|
||||
void SetMax(float x,float y,float z)
|
||||
{
|
||||
mMax[0] = x;
|
||||
mMax[1] = y;
|
||||
mMax[2] = z;
|
||||
}
|
||||
|
||||
float mMin[3];
|
||||
float mMax[3];
|
||||
};
|
||||
|
||||
void splitRect(unsigned int axis,
|
||||
const Rect3d &source,
|
||||
Rect3d &b1,
|
||||
Rect3d &b2,
|
||||
const float *midpoint)
|
||||
{
|
||||
switch ( axis )
|
||||
{
|
||||
case 0:
|
||||
b1.SetMin(source.mMin);
|
||||
b1.SetMax( midpoint[0], source.mMax[1], source.mMax[2] );
|
||||
|
||||
b2.SetMin( midpoint[0], source.mMin[1], source.mMin[2] );
|
||||
b2.SetMax(source.mMax);
|
||||
|
||||
break;
|
||||
case 1:
|
||||
b1.SetMin(source.mMin);
|
||||
b1.SetMax( source.mMax[0], midpoint[1], source.mMax[2] );
|
||||
|
||||
b2.SetMin( source.mMin[0], midpoint[1], source.mMin[2] );
|
||||
b2.SetMax(source.mMax);
|
||||
|
||||
break;
|
||||
case 2:
|
||||
b1.SetMin(source.mMin);
|
||||
b1.SetMax( source.mMax[0], source.mMax[1], midpoint[2] );
|
||||
|
||||
b2.SetMin( source.mMin[0], source.mMin[1], midpoint[2] );
|
||||
b2.SetMax(source.mMax);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool computeSplitPlane(unsigned int vcount,
|
||||
const float *vertices,
|
||||
unsigned int tcount,
|
||||
const unsigned int *indices,
|
||||
ConvexDecompInterface *callback,
|
||||
float *plane)
|
||||
{
|
||||
bool cret = false;
|
||||
|
||||
|
||||
float bmin[3] = { 1e9, 1e9, 1e9 };
|
||||
float bmax[3] = { -1e9, -1e9, -1e9 };
|
||||
|
||||
for (unsigned int i=0; i<vcount; i++)
|
||||
{
|
||||
const float *p = &vertices[i*3];
|
||||
|
||||
if ( p[0] < bmin[0] ) bmin[0] = p[0];
|
||||
if ( p[1] < bmin[1] ) bmin[1] = p[1];
|
||||
if ( p[2] < bmin[2] ) bmin[2] = p[2];
|
||||
|
||||
if ( p[0] > bmax[0] ) bmax[0] = p[0];
|
||||
if ( p[1] > bmax[1] ) bmax[1] = p[1];
|
||||
if ( p[2] > bmax[2] ) bmax[2] = p[2];
|
||||
|
||||
}
|
||||
|
||||
float dx = bmax[0] - bmin[0];
|
||||
float dy = bmax[1] - bmin[1];
|
||||
float dz = bmax[2] - bmin[2];
|
||||
|
||||
|
||||
float laxis = dx;
|
||||
|
||||
unsigned int axis = 0;
|
||||
|
||||
if ( dy > dx )
|
||||
{
|
||||
axis = 1;
|
||||
laxis = dy;
|
||||
}
|
||||
|
||||
if ( dz > dx && dz > dy )
|
||||
{
|
||||
axis = 2;
|
||||
laxis = dz;
|
||||
}
|
||||
|
||||
float p1[3];
|
||||
float p2[3];
|
||||
float p3[3];
|
||||
|
||||
p3[0] = p2[0] = p1[0] = bmin[0] + dx*0.5f;
|
||||
p3[1] = p2[1] = p1[1] = bmin[1] + dy*0.5f;
|
||||
p3[2] = p2[2] = p1[2] = bmin[2] + dz*0.5f;
|
||||
|
||||
Rect3d b(bmin,bmax);
|
||||
|
||||
Rect3d b1,b2;
|
||||
|
||||
splitRect(axis,b,b1,b2,p1);
|
||||
|
||||
|
||||
// callback->ConvexDebugBound(b1.mMin,b1.mMax,0x00FF00);
|
||||
// callback->ConvexDebugBound(b2.mMin,b2.mMax,0xFFFF00);
|
||||
|
||||
switch ( axis )
|
||||
{
|
||||
case 0:
|
||||
p2[1] = bmin[1];
|
||||
p2[2] = bmin[2];
|
||||
|
||||
if ( dz > dy )
|
||||
{
|
||||
p3[1] = bmax[1];
|
||||
p3[2] = bmin[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
p3[1] = bmin[1];
|
||||
p3[2] = bmax[2];
|
||||
}
|
||||
|
||||
break;
|
||||
case 1:
|
||||
p2[0] = bmin[0];
|
||||
p2[2] = bmin[2];
|
||||
|
||||
if ( dx > dz )
|
||||
{
|
||||
p3[0] = bmax[0];
|
||||
p3[2] = bmin[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
p3[0] = bmin[0];
|
||||
p3[2] = bmax[2];
|
||||
}
|
||||
|
||||
break;
|
||||
case 2:
|
||||
p2[0] = bmin[0];
|
||||
p2[1] = bmin[1];
|
||||
|
||||
if ( dx > dy )
|
||||
{
|
||||
p3[0] = bmax[0];
|
||||
p3[1] = bmin[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
p3[0] = bmin[0];
|
||||
p3[1] = bmax[1];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// callback->ConvexDebugTri(p1,p2,p3,0xFF0000);
|
||||
|
||||
computePlane(p1,p2,p3,plane);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
59
Extras/ConvexDecomposition/splitplane.h
Normal file
59
Extras/ConvexDecomposition/splitplane.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef SPLIT_PLANE_H
|
||||
|
||||
#define SPLIT_PLANE_H
|
||||
|
||||
//** Computes an 'optimal' split plane for the supplied mesh.
|
||||
//** needs much improvement since it currently just splits along
|
||||
//** the longest side of the AABB.
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
|
||||
namespace ConvexDecomposition
|
||||
{
|
||||
|
||||
class ConvexDecompInterface;
|
||||
|
||||
bool computeSplitPlane(unsigned int vcount,
|
||||
const float *vertices,
|
||||
unsigned int tcount,
|
||||
const unsigned int *indices,
|
||||
ConvexDecompInterface *callback,
|
||||
float *plane);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
304
Extras/ConvexDecomposition/vlookup.cpp
Normal file
304
Extras/ConvexDecomposition/vlookup.cpp
Normal file
@@ -0,0 +1,304 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#pragma warning(disable:4786)
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
// CodeSnippet provided by John W. Ratcliff
|
||||
// on March 23, 2006.
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// Personal website: http://jratcliffscarab.blogspot.com
|
||||
// Coding Website: http://codesuppository.blogspot.com
|
||||
// FundRaising Blog: http://amillionpixels.blogspot.com
|
||||
// Fundraising site: http://www.amillionpixels.us
|
||||
// New Temple Site: http://newtemple.blogspot.com
|
||||
//
|
||||
// This snippet shows how to 'hide' the complexity of
|
||||
// the STL by wrapping some useful piece of functionality
|
||||
// around a handful of discrete API calls.
|
||||
//
|
||||
// This API allows you to create an indexed triangle list
|
||||
// from a collection of raw input triangles. Internally
|
||||
// it uses an STL set to build the lookup table very rapidly.
|
||||
//
|
||||
// Here is how you would use it to build an indexed triangle
|
||||
// list from a raw list of triangles.
|
||||
//
|
||||
// (1) create a 'VertexLookup' interface by calling
|
||||
//
|
||||
// VertexLook vl = Vl_createVertexLookup();
|
||||
//
|
||||
// (2) For each vertice in each triangle call:
|
||||
//
|
||||
// unsigned int i1 = Vl_getIndex(vl,p1);
|
||||
// unsigned int i2 = Vl_getIndex(vl,p2);
|
||||
// unsigned int i3 = Vl_getIndex(vl,p3);
|
||||
//
|
||||
// save the 3 indices into your triangle list array.
|
||||
//
|
||||
// (3) Get the vertex array by calling:
|
||||
//
|
||||
// const float *vertices = Vl_getVertices(vl);
|
||||
//
|
||||
// (4) Get the number of vertices so you can copy them into
|
||||
// your own buffer.
|
||||
// unsigned int vcount = Vl_getVcount(vl);
|
||||
//
|
||||
// (5) Release the VertexLookup interface when you are done with it.
|
||||
// Vl_releaseVertexLookup(vl);
|
||||
//
|
||||
// Teaches the following lessons:
|
||||
//
|
||||
// How to wrap the complexity of STL and C++ classes around a
|
||||
// simple API interface.
|
||||
//
|
||||
// How to use an STL set and custom comparator operator for
|
||||
// a complex data type.
|
||||
//
|
||||
// How to create a template class.
|
||||
//
|
||||
// How to achieve significant performance improvements by
|
||||
// taking advantage of built in STL containers in just
|
||||
// a few lines of code.
|
||||
//
|
||||
// You could easily modify this code to support other vertex
|
||||
// formats with any number of interpolants.
|
||||
|
||||
|
||||
|
||||
|
||||
#include "vlookup.h"
|
||||
|
||||
namespace Vlookup
|
||||
{
|
||||
|
||||
class VertexPosition
|
||||
{
|
||||
public:
|
||||
VertexPosition(void) { };
|
||||
VertexPosition(const float *p)
|
||||
{
|
||||
mPos[0] = p[0];
|
||||
mPos[1] = p[1];
|
||||
mPos[2] = p[2];
|
||||
};
|
||||
|
||||
void Set(int index,const float *pos)
|
||||
{
|
||||
const float * p = &pos[index*3];
|
||||
|
||||
mPos[0] = p[0];
|
||||
mPos[1] = p[1];
|
||||
mPos[2] = p[2];
|
||||
|
||||
};
|
||||
|
||||
float GetX(void) const { return mPos[0]; };
|
||||
float GetY(void) const { return mPos[1]; };
|
||||
float GetZ(void) const { return mPos[2]; };
|
||||
|
||||
float mPos[3];
|
||||
};
|
||||
|
||||
|
||||
template <class Type> class VertexLess
|
||||
{
|
||||
public:
|
||||
typedef std::vector< Type > VertexVector;
|
||||
|
||||
bool operator()(int v1,int v2) const;
|
||||
|
||||
static void SetSearch(const Type& match,VertexVector *list)
|
||||
{
|
||||
mFind = match;
|
||||
mList = list;
|
||||
};
|
||||
|
||||
private:
|
||||
const Type& Get(int index) const
|
||||
{
|
||||
if ( index == -1 ) return mFind;
|
||||
VertexVector &vlist = *mList;
|
||||
return vlist[index];
|
||||
}
|
||||
static Type mFind; // vertice to locate.
|
||||
static VertexVector *mList;
|
||||
};
|
||||
|
||||
template <class Type> class VertexPool
|
||||
{
|
||||
public:
|
||||
typedef std::set<int, VertexLess<Type> > VertexSet;
|
||||
typedef std::vector< Type > VertexVector;
|
||||
|
||||
int GetVertex(const Type& vtx)
|
||||
{
|
||||
VertexLess<Type>::SetSearch(vtx,&mVtxs);
|
||||
VertexSet::iterator found;
|
||||
found = mVertSet.find( -1 );
|
||||
if ( found != mVertSet.end() )
|
||||
{
|
||||
return *found;
|
||||
}
|
||||
int idx = (int)mVtxs.size();
|
||||
mVtxs.push_back( vtx );
|
||||
mVertSet.insert( idx );
|
||||
return idx;
|
||||
};
|
||||
|
||||
const float * GetPos(int idx) const
|
||||
{
|
||||
return mVtxs[idx].mPos;
|
||||
}
|
||||
|
||||
const Type& Get(int idx) const
|
||||
{
|
||||
return mVtxs[idx];
|
||||
};
|
||||
|
||||
unsigned int GetSize(void) const
|
||||
{
|
||||
return mVtxs.size();
|
||||
};
|
||||
|
||||
void Clear(int reservesize) // clear the vertice pool.
|
||||
{
|
||||
mVertSet.clear();
|
||||
mVtxs.clear();
|
||||
mVtxs.reserve(reservesize);
|
||||
};
|
||||
|
||||
const VertexVector& GetVertexList(void) const { return mVtxs; };
|
||||
|
||||
void Set(const Type& vtx)
|
||||
{
|
||||
mVtxs.push_back(vtx);
|
||||
}
|
||||
|
||||
unsigned int GetVertexCount(void) const
|
||||
{
|
||||
return mVtxs.size();
|
||||
};
|
||||
|
||||
|
||||
Type * GetBuffer(void)
|
||||
{
|
||||
return &mVtxs[0];
|
||||
};
|
||||
|
||||
private:
|
||||
VertexSet mVertSet; // ordered list.
|
||||
VertexVector mVtxs; // set of vertices.
|
||||
};
|
||||
|
||||
|
||||
VertexPosition VertexLess<VertexPosition>::mFind;
|
||||
std::vector<VertexPosition > *VertexLess<VertexPosition>::mList=0;
|
||||
|
||||
bool VertexLess<VertexPosition>::operator()(int v1,int v2) const
|
||||
{
|
||||
|
||||
const VertexPosition& a = Get(v1);
|
||||
const VertexPosition& b = Get(v2);
|
||||
|
||||
int ixA = (int) (a.GetX()*10000.0f);
|
||||
int ixB = (int) (b.GetX()*10000.0f);
|
||||
|
||||
if ( ixA < ixB ) return true;
|
||||
if ( ixA > ixB ) return false;
|
||||
|
||||
int iyA = (int) (a.GetY()*10000.0f);
|
||||
int iyB = (int) (b.GetY()*10000.0f);
|
||||
|
||||
if ( iyA < iyB ) return true;
|
||||
if ( iyA > iyB ) return false;
|
||||
|
||||
int izA = (int) (a.GetZ()*10000.0f);
|
||||
int izB = (int) (b.GetZ()*10000.0f);
|
||||
|
||||
if ( izA < izB ) return true;
|
||||
if ( izA > izB ) return false;
|
||||
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
using namespace Vlookup;
|
||||
|
||||
VertexLookup Vl_createVertexLookup(void)
|
||||
{
|
||||
VertexLookup ret = new VertexPool< VertexPosition >;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Vl_releaseVertexLookup(VertexLookup vlook)
|
||||
{
|
||||
VertexPool< VertexPosition > *vp = (VertexPool< VertexPosition > *) vlook;
|
||||
delete vp;
|
||||
}
|
||||
|
||||
unsigned int Vl_getIndex(VertexLookup vlook,const float *pos) // get index.
|
||||
{
|
||||
VertexPool< VertexPosition > *vp = (VertexPool< VertexPosition > *) vlook;
|
||||
VertexPosition p(pos);
|
||||
return vp->GetVertex(p);
|
||||
}
|
||||
|
||||
const float * Vl_getVertices(VertexLookup vlook)
|
||||
{
|
||||
VertexPool< VertexPosition > *vp = (VertexPool< VertexPosition > *) vlook;
|
||||
return vp->GetPos(0);
|
||||
}
|
||||
|
||||
|
||||
unsigned int Vl_getVcount(VertexLookup vlook)
|
||||
{
|
||||
VertexPool< VertexPosition > *vp = (VertexPool< VertexPosition > *) vlook;
|
||||
return vp->GetVertexCount();
|
||||
}
|
||||
119
Extras/ConvexDecomposition/vlookup.h
Normal file
119
Extras/ConvexDecomposition/vlookup.h
Normal file
@@ -0,0 +1,119 @@
|
||||
#ifndef VLOOKUP_H
|
||||
|
||||
#define VLOOKUP_H
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
Copyright (c) 2004 Open Dynamics Framework Group
|
||||
www.physicstools.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use 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 Open Dynamics Framework Group nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
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 INTEL 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.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
// http://codesuppository.blogspot.com
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// http://www.amillionpixels.us
|
||||
//
|
||||
|
||||
|
||||
// CodeSnippet provided by John W. Ratcliff
|
||||
// on March 23, 2006.
|
||||
//
|
||||
// mailto: jratcliff@infiniplex.net
|
||||
//
|
||||
// Personal website: http://jratcliffscarab.blogspot.com
|
||||
// Coding Website: http://codesuppository.blogspot.com
|
||||
// FundRaising Blog: http://amillionpixels.blogspot.com
|
||||
// Fundraising site: http://www.amillionpixels.us
|
||||
// New Temple Site: http://newtemple.blogspot.com
|
||||
//
|
||||
// This snippet shows how to 'hide' the complexity of
|
||||
// the STL by wrapping some useful piece of functionality
|
||||
// around a handful of discrete API calls.
|
||||
//
|
||||
// This API allows you to create an indexed triangle list
|
||||
// from a collection of raw input triangles. Internally
|
||||
// it uses an STL set to build the lookup table very rapidly.
|
||||
//
|
||||
// Here is how you would use it to build an indexed triangle
|
||||
// list from a raw list of triangles.
|
||||
//
|
||||
// (1) create a 'VertexLookup' interface by calling
|
||||
//
|
||||
// VertexLook vl = Vl_createVertexLookup();
|
||||
//
|
||||
// (2) For each vertice in each triangle call:
|
||||
//
|
||||
// unsigned int i1 = Vl_getIndex(vl,p1);
|
||||
// unsigned int i2 = Vl_getIndex(vl,p2);
|
||||
// unsigned int i3 = Vl_getIndex(vl,p3);
|
||||
//
|
||||
// save the 3 indices into your triangle list array.
|
||||
//
|
||||
// (3) Get the vertex array by calling:
|
||||
//
|
||||
// const float *vertices = Vl_getVertices(vl);
|
||||
//
|
||||
// (4) Get the number of vertices so you can copy them into
|
||||
// your own buffer.
|
||||
// unsigned int vcount = Vl_getVcount(vl);
|
||||
//
|
||||
// (5) Release the VertexLookup interface when you are done with it.
|
||||
// Vl_releaseVertexLookup(vl);
|
||||
//
|
||||
// Teaches the following lessons:
|
||||
//
|
||||
// How to wrap the complexity of STL and C++ classes around a
|
||||
// simple API interface.
|
||||
//
|
||||
// How to use an STL set and custom comparator operator for
|
||||
// a complex data type.
|
||||
//
|
||||
// How to create a template class.
|
||||
//
|
||||
// How to achieve significant performance improvements by
|
||||
// taking advantage of built in STL containers in just
|
||||
// a few lines of code.
|
||||
//
|
||||
// You could easily modify this code to support other vertex
|
||||
// formats with any number of interpolants.
|
||||
//
|
||||
// Hide C++ classes from the rest of your application by
|
||||
// keeping them in the CPP and wrapping them in a namespace
|
||||
// Uses an STL set to create an index table for a bunch of vertex positions
|
||||
// used typically to re-index a collection of raw triangle data.
|
||||
|
||||
|
||||
typedef void * VertexLookup;
|
||||
|
||||
VertexLookup Vl_createVertexLookup(void);
|
||||
void Vl_releaseVertexLookup(VertexLookup vlook);
|
||||
|
||||
unsigned int Vl_getIndex(VertexLookup vlook,const float *pos); // get index.
|
||||
const float * Vl_getVertices(VertexLookup vlook);
|
||||
unsigned int Vl_getVcount(VertexLookup vlook);
|
||||
|
||||
|
||||
#endif
|
||||
227
Extras/ExtraSolid35/CombinedSimplexSolver.cpp
Normal file
227
Extras/ExtraSolid35/CombinedSimplexSolver.cpp
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Erwin Coumans http://www.erwincoumans.com
|
||||
*
|
||||
* Permission to use, copy, modify, distribute and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appear in all copies.
|
||||
* Erwin Coumans makes no representations about the suitability
|
||||
* of this software for any purpose.
|
||||
* It is provided "as is" without express or implied warranty.
|
||||
*/
|
||||
|
||||
#include "CombinedSimplexSolver.h"
|
||||
#include <stdio.h>
|
||||
//switch off asserts
|
||||
//#define MY_ASSERT assert
|
||||
#define MY_ASSERT
|
||||
|
||||
bool useVoronoi = true;
|
||||
|
||||
CombinedSimplexSolver::CombinedSimplexSolver()
|
||||
:m_useVoronoiSolver(useVoronoi)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CombinedSimplexSolver::reset()
|
||||
{
|
||||
m_voronoiSolver.reset();
|
||||
m_johnsonSolver.reset();
|
||||
}
|
||||
|
||||
|
||||
void CombinedSimplexSolver::addVertex(const SimdVector3& w, const SimdPoint3& p, const SimdPoint3& q)
|
||||
{
|
||||
printf("addVertex (%f %f %f)\n",w[0],w[1],w[2]);
|
||||
m_voronoiSolver.addVertex(w,p,q);
|
||||
m_johnsonSolver.addVertex(w,p,q);
|
||||
int i;
|
||||
i=0;
|
||||
|
||||
SimdPoint3 vp1,vp2;
|
||||
SimdPoint3 jp1,jp2;
|
||||
/*
|
||||
bool isClosest0 = m_voronoiSolver.closest(vp1);
|
||||
bool isClosest1 = m_johnsonSolver.closest(vp1);
|
||||
|
||||
m_voronoiSolver.compute_points(vp1, vp2);
|
||||
m_johnsonSolver.compute_points(jp1,jp2);
|
||||
i=0;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CombinedSimplexSolver::closest(SimdVector3& v)
|
||||
{
|
||||
bool result0 = 0;
|
||||
bool result1 = 0;
|
||||
|
||||
SimdVector3 v0,v1;
|
||||
|
||||
result0 = m_voronoiSolver.closest(v0);
|
||||
result1 = m_johnsonSolver.closest(v1);
|
||||
|
||||
if (result0 != result1)
|
||||
{
|
||||
result0 = m_voronoiSolver.closest(v0);
|
||||
result1 = m_johnsonSolver.closest(v1);
|
||||
int i;
|
||||
i=0;
|
||||
}
|
||||
if (m_useVoronoiSolver)
|
||||
{
|
||||
v = v0;
|
||||
return result0;
|
||||
}
|
||||
|
||||
v = v1;
|
||||
return result1;
|
||||
}
|
||||
|
||||
SimdScalar CombinedSimplexSolver::maxVertex()
|
||||
{
|
||||
SimdScalar maxv0 = m_voronoiSolver.maxVertex();
|
||||
SimdScalar maxv1 = m_johnsonSolver.maxVertex();
|
||||
MY_ASSERT(maxv0 = maxv1);
|
||||
if (m_useVoronoiSolver)
|
||||
return maxv0;
|
||||
|
||||
return maxv1;
|
||||
}
|
||||
|
||||
bool CombinedSimplexSolver::fullSimplex() const
|
||||
{
|
||||
bool fullSimplex0 = m_voronoiSolver.fullSimplex();
|
||||
bool fullSimplex1 = m_johnsonSolver.fullSimplex();
|
||||
MY_ASSERT(fullSimplex0 == fullSimplex1);
|
||||
|
||||
if (m_useVoronoiSolver)
|
||||
return fullSimplex0;
|
||||
|
||||
return fullSimplex1;
|
||||
}
|
||||
|
||||
int CombinedSimplexSolver::getSimplex(SimdPoint3 *pBuf, SimdPoint3 *qBuf, SimdVector3 *yBuf) const
|
||||
{
|
||||
|
||||
|
||||
int simplex0 = m_voronoiSolver.getSimplex(pBuf, qBuf, yBuf);
|
||||
int simplex1 = m_johnsonSolver.getSimplex(pBuf, qBuf, yBuf);
|
||||
// MY_ASSERT(simplex0 == simplex1);
|
||||
if (m_useVoronoiSolver)
|
||||
{
|
||||
return m_voronoiSolver.getSimplex(pBuf, qBuf, yBuf);
|
||||
}
|
||||
|
||||
return simplex1;
|
||||
}
|
||||
|
||||
void CombinedSimplexSolver::debugPrint()
|
||||
{
|
||||
SimdPoint3 pBuf0[4];
|
||||
SimdPoint3 qBuf0[4];
|
||||
SimdPoint3 yBuf0[4];
|
||||
SimdPoint3 pBuf1[4];
|
||||
SimdPoint3 qBuf1[4];
|
||||
SimdPoint3 yBuf1[4];
|
||||
int verts0,verts1;
|
||||
|
||||
verts0 = m_voronoiSolver.getSimplex(&pBuf0[0], &qBuf0[0], &yBuf0[0]);
|
||||
verts1 = m_johnsonSolver.getSimplex(&pBuf1[0], &qBuf1[0], &yBuf1[0]);
|
||||
printf("numverts0 = %d, numverts1 = %d\n",verts0,verts1);
|
||||
for (int i=0;i<verts0;i++)
|
||||
{
|
||||
printf("vert0 pBuf %d = %f , %f , %f\n",i,pBuf0[i].x(),pBuf0[i].y(),pBuf0[i].z());
|
||||
printf("vert0 qBuf %d = %f , %f , %f\n",i,qBuf0[i].x(),qBuf0[i].y(),qBuf0[i].z());
|
||||
printf("vert0 yBuf %d = %f , %f , %f\n",i,yBuf0[i].x(),yBuf0[i].y(),yBuf0[i].z());
|
||||
}
|
||||
|
||||
for (int i=0;i<verts1;i++)
|
||||
{
|
||||
printf("vert1 pBuf %d = %f , %f , %f\n",i,pBuf1[i].x(),pBuf1[i].y(),pBuf1[i].z());
|
||||
printf("vert1 qBuf %d = %f , %f , %f\n",i,qBuf1[i].x(),qBuf1[i].y(),qBuf1[i].z());
|
||||
printf("vert1 yBuf %d = %f , %f , %f\n",i,yBuf1[i].x(),yBuf1[i].y(),yBuf1[i].z());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
bool CombinedSimplexSolver::inSimplex(const SimdVector3& w)
|
||||
{
|
||||
bool insimplex0 = m_voronoiSolver.inSimplex(w);
|
||||
bool insimplex1 = m_johnsonSolver.inSimplex(w);
|
||||
|
||||
if (insimplex0 != insimplex1)
|
||||
{
|
||||
debugPrint();
|
||||
|
||||
|
||||
}
|
||||
if (m_useVoronoiSolver)
|
||||
return insimplex0;
|
||||
|
||||
return insimplex1;
|
||||
|
||||
}
|
||||
void CombinedSimplexSolver::backup_closest(SimdVector3& v)
|
||||
{
|
||||
SimdVector3 v0,v1;
|
||||
|
||||
m_voronoiSolver.backup_closest(v0);
|
||||
m_johnsonSolver.backup_closest(v1);
|
||||
if (m_useVoronoiSolver)
|
||||
{
|
||||
v = v0;
|
||||
} else
|
||||
{
|
||||
v = v1;
|
||||
}
|
||||
}
|
||||
|
||||
bool CombinedSimplexSolver::emptySimplex() const
|
||||
{
|
||||
bool empty0 = m_voronoiSolver.emptySimplex();
|
||||
bool empty1 = m_johnsonSolver.emptySimplex();
|
||||
MY_ASSERT(empty0 == empty1);
|
||||
if (m_useVoronoiSolver)
|
||||
return empty0;
|
||||
|
||||
return empty1;
|
||||
}
|
||||
|
||||
void CombinedSimplexSolver::compute_points(SimdPoint3& p1, SimdPoint3& p2)
|
||||
{
|
||||
SimdPoint3 tmpP1,tmpP2;
|
||||
SimdPoint3 tmpJP1,tmpJP2;
|
||||
|
||||
m_voronoiSolver.compute_points(tmpP1,tmpP2);
|
||||
m_johnsonSolver.compute_points(tmpJP1,tmpJP2);
|
||||
|
||||
if (m_useVoronoiSolver)
|
||||
{
|
||||
p1 = tmpP1;
|
||||
p2 = tmpP2;
|
||||
}
|
||||
else
|
||||
{
|
||||
p1 = tmpJP1;
|
||||
p2 = tmpJP2;
|
||||
}
|
||||
}
|
||||
|
||||
int CombinedSimplexSolver::numVertices() const
|
||||
{
|
||||
int numverts0 = m_voronoiSolver.numVertices();
|
||||
int numverts1 = m_johnsonSolver.numVertices();
|
||||
MY_ASSERT(numverts0==numverts1);
|
||||
if (numverts0 != numverts1)
|
||||
{
|
||||
printf("--------- (numverts0 != numverts1) -----------------------\n");
|
||||
}
|
||||
printf("numverts0 = %d, numverts1 %d \n",numverts0,numverts1);
|
||||
|
||||
if (m_useVoronoiSolver)
|
||||
return numverts0;
|
||||
|
||||
return numverts1;
|
||||
}
|
||||
62
Extras/ExtraSolid35/CombinedSimplexSolver.h
Normal file
62
Extras/ExtraSolid35/CombinedSimplexSolver.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Erwin Coumans http://www.erwincoumans.com
|
||||
*
|
||||
* Permission to use, copy, modify, distribute and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appear in all copies.
|
||||
* Erwin Coumans makes no representations about the suitability
|
||||
* of this software for any purpose.
|
||||
* It is provided "as is" without express or implied warranty.
|
||||
*/
|
||||
|
||||
#ifndef COMBINED_SIMPLEX_SOLVER
|
||||
#define COMBINED_SIMPLEX_SOLVER
|
||||
|
||||
#include "NarrowPhaseCollision/SimplexSolverInterface.h"
|
||||
#include "NarrowPhaseCollision/VoronoiSimplexSolver.h"
|
||||
#include "Solid3JohnsonSimplexSolver.h"
|
||||
|
||||
/// CombinedSimplexSolver runs both Solid and Voronoi Simplex Solver for comparison
|
||||
class CombinedSimplexSolver: public SimplexSolverInterface
|
||||
{
|
||||
VoronoiSimplexSolver m_voronoiSolver;
|
||||
// VoronoiSimplexSolver m_johnsonSolver;
|
||||
|
||||
Solid3JohnsonSimplexSolver m_johnsonSolver;
|
||||
|
||||
bool m_useVoronoiSolver;
|
||||
|
||||
void debugPrint();
|
||||
|
||||
public:
|
||||
CombinedSimplexSolver();
|
||||
|
||||
virtual ~CombinedSimplexSolver() {};
|
||||
|
||||
virtual void reset();
|
||||
|
||||
virtual void addVertex(const SimdVector3& w, const SimdPoint3& p, const SimdPoint3& q);
|
||||
|
||||
virtual bool closest(SimdVector3& v);
|
||||
|
||||
virtual SimdScalar maxVertex();
|
||||
|
||||
virtual bool fullSimplex() const;
|
||||
|
||||
virtual int getSimplex(SimdPoint3 *pBuf, SimdPoint3 *qBuf, SimdVector3 *yBuf) const;
|
||||
|
||||
virtual bool inSimplex(const SimdVector3& w);
|
||||
|
||||
virtual void backup_closest(SimdVector3& v) ;
|
||||
|
||||
virtual bool emptySimplex() const;
|
||||
|
||||
virtual void compute_points(SimdPoint3& p1, SimdPoint3& p2);
|
||||
|
||||
virtual int numVertices() const;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //COMBINED_SIMPLEX_SOLVER
|
||||
137
Extras/ExtraSolid35/ExtraSolid35_vc7.vcproj
Normal file
137
Extras/ExtraSolid35/ExtraSolid35_vc7.vcproj
Normal file
@@ -0,0 +1,137 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="ExtraSolid35"
|
||||
ProjectGUID="{23F98301-2F09-4064-86CC-AB00D097BFB6}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\Bullet;..\..\LinearMath"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/ExtraSolid35.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\Bullet;..\..\LinearMath"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/ExtraSolid35.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath=".\CombinedSimplexSolver.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Solid3EpaPenetrationDepth.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Solid3JohnsonSimplexSolver.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath=".\CombinedSimplexSolver.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Solid3EpaPenetrationDepth.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Solid3JohnsonSimplexSolver.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\ReadMe.txt">
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
195
Extras/ExtraSolid35/ExtraSolid35_vc8.vcproj
Normal file
195
Extras/ExtraSolid35/ExtraSolid35_vc8.vcproj
Normal file
@@ -0,0 +1,195 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="ExtraSolid35"
|
||||
ProjectGUID="{23F98301-2F09-4064-86CC-AB00D097BFB6}"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\Bullet;..\..\LinearMath"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/ExtraSolid35.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\Bullet;..\..\LinearMath"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/ExtraSolid35.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\CombinedSimplexSolver.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Solid3EpaPenetrationDepth.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Solid3JohnsonSimplexSolver.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\CombinedSimplexSolver.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Solid3EpaPenetrationDepth.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Solid3JohnsonSimplexSolver.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\ReadMe.txt"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
110
Extras/ExtraSolid35/LICENSE_QPL.txt
Normal file
110
Extras/ExtraSolid35/LICENSE_QPL.txt
Normal file
@@ -0,0 +1,110 @@
|
||||
|
||||
The SOLID library is Copyright (C) 2001-2003 Dtecta.
|
||||
|
||||
You may use, distribute and copy the SOLID library under the terms of
|
||||
the Q Public License, which is displayed below.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
THE Q PUBLIC LICENSE
|
||||
version 1.0
|
||||
|
||||
Copyright (C) 1999-2000 Trolltech AS, Norway.
|
||||
Everyone is permitted to copy and
|
||||
distribute this license document.
|
||||
|
||||
The intent of this license is to establish freedom to share and change the
|
||||
software regulated by this license under the open source model.
|
||||
|
||||
This license applies to any software containing a notice placed by the
|
||||
copyright holder saying that it may be distributed under the terms of
|
||||
the Q Public License version 1.0. Such software is herein referred to as
|
||||
the Software. This license covers modification and distribution of the
|
||||
Software, use of third-party application programs based on the Software,
|
||||
and development of free software which uses the Software.
|
||||
|
||||
Granted Rights
|
||||
|
||||
1. You are granted the non-exclusive rights set forth in this license
|
||||
provided you agree to and comply with any and all conditions in this
|
||||
license. Whole or partial distribution of the Software, or software
|
||||
items that link with the Software, in any form signifies acceptance of
|
||||
this license.
|
||||
|
||||
2. You may copy and distribute the Software in unmodified form provided
|
||||
that the entire package, including - but not restricted to - copyright,
|
||||
trademark notices and disclaimers, as released by the initial developer
|
||||
of the Software, is distributed.
|
||||
|
||||
3. You may make modifications to the Software and distribute your
|
||||
modifications, in a form that is separate from the Software, such as
|
||||
patches. The following restrictions apply to modifications:
|
||||
|
||||
a. Modifications must not alter or remove any copyright notices in
|
||||
the Software.
|
||||
|
||||
b. When modifications to the Software are released under this
|
||||
license, a non-exclusive royalty-free right is granted to the
|
||||
initial developer of the Software to distribute your modification
|
||||
in future versions of the Software provided such versions remain
|
||||
available under these terms in addition to any other license(s) of
|
||||
the initial developer.
|
||||
|
||||
4. You may distribute machine-executable forms of the Software or
|
||||
machine-executable forms of modified versions of the Software, provided
|
||||
that you meet these restrictions:
|
||||
|
||||
a. You must include this license document in the distribution.
|
||||
|
||||
b. You must ensure that all recipients of the machine-executable forms
|
||||
are also able to receive the complete machine-readable source code
|
||||
to the distributed Software, including all modifications, without
|
||||
any charge beyond the costs of data transfer, and place prominent
|
||||
notices in the distribution explaining this.
|
||||
|
||||
c. You must ensure that all modifications included in the
|
||||
machine-executable forms are available under the terms of this
|
||||
license.
|
||||
|
||||
5. You may use the original or modified versions of the Software to
|
||||
compile, link and run application programs legally developed by you
|
||||
or by others.
|
||||
|
||||
6. You may develop application programs, reusable components and other
|
||||
software items that link with the original or modified versions of the
|
||||
Software. These items, when distributed, are subject to the following
|
||||
requirements:
|
||||
|
||||
a. You must ensure that all recipients of machine-executable forms of
|
||||
these items are also able to receive and use the complete
|
||||
machine-readable source code to the items without any charge
|
||||
beyond the costs of data transfer.
|
||||
|
||||
b. You must explicitly license all recipients of your items to use
|
||||
and re-distribute original and modified versions of the items in
|
||||
both machine-executable and source code forms. The recipients must
|
||||
be able to do so without any charges whatsoever, and they must be
|
||||
able to re-distribute to anyone they choose.
|
||||
|
||||
|
||||
c. If the items are not available to the general public, and the
|
||||
initial developer of the Software requests a copy of the items,
|
||||
then you must supply one.
|
||||
|
||||
Limitations of Liability
|
||||
|
||||
In no event shall the initial developers or copyright holders be liable
|
||||
for any damages whatsoever, including - but not restricted to - lost
|
||||
revenue or profits or other direct, indirect, special, incidental or
|
||||
consequential damages, even if they have been advised of the possibility
|
||||
of such damages, except to the extent invariable law, if any, provides
|
||||
otherwise.
|
||||
|
||||
No Warranty
|
||||
|
||||
The Software and this license document are provided AS IS with NO WARRANTY
|
||||
OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE.
|
||||
Choice of Law
|
||||
|
||||
This license is governed by the Laws of Norway. Disputes shall be settled
|
||||
by Oslo City Court.
|
||||
21
Extras/ExtraSolid35/ReadMe.txt
Normal file
21
Extras/ExtraSolid35/ReadMe.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
========================================================================
|
||||
STATIC LIBRARY : Solid35 Project Overview
|
||||
========================================================================
|
||||
|
||||
AppWizard has created this Solid35 library project for you.
|
||||
No source files were created as part of your project.
|
||||
|
||||
|
||||
Solid35.vcproj
|
||||
This is the main project file for VC++ projects generated using an Application Wizard.
|
||||
It contains information about the version of Visual C++ that generated the file, and
|
||||
information about the platforms, configurations, and project features selected with the
|
||||
Application Wizard.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Other notes:
|
||||
|
||||
AppWizard uses "TODO:" comments to indicate parts of the source code you
|
||||
should add to or customize.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
129
Extras/ExtraSolid35/Solid35.vcproj
Normal file
129
Extras/ExtraSolid35/Solid35.vcproj
Normal file
@@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="OptionalSolid35"
|
||||
ProjectGUID="{698BA0FD-10D3-4F4C-8686-1303D6273D46}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/Solid35.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
||||
RuntimeLibrary="4"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/Solid35.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath=".\Solid3EpaPenetrationDepth.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Solid3JohnsonSimplexSolver.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath=".\Solid3EpaPenetrationDepth.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Solid3JohnsonSimplexSolver.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\ReadMe.txt">
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
587
Extras/ExtraSolid35/Solid3EpaPenetrationDepth.cpp
Normal file
587
Extras/ExtraSolid35/Solid3EpaPenetrationDepth.cpp
Normal file
@@ -0,0 +1,587 @@
|
||||
/*
|
||||
* SOLID - Software Library for Interference Detection
|
||||
*
|
||||
* Copyright (C) 2001-2003 Dtecta. All rights reserved.
|
||||
*
|
||||
* This library may be distributed under the terms of the Q Public License
|
||||
* (QPL) as defined by Trolltech AS of Norway and appearing in the file
|
||||
* LICENSE.QPL included in the packaging of this file.
|
||||
*
|
||||
* This library may be distributed and/or modified under the terms of the
|
||||
* GNU General Public License (GPL) version 2 as published by the Free Software
|
||||
* Foundation and appearing in the file LICENSE.GPL included in the
|
||||
* packaging of this file.
|
||||
*
|
||||
* This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Commercial use or any other use of this library not covered by either
|
||||
* the QPL or the GPL requires an additional license from Dtecta.
|
||||
* Please contact info@dtecta.com for enquiries about the terms of commercial
|
||||
* use of this library.
|
||||
*/
|
||||
|
||||
#include "Solid3EpaPenetrationDepth.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "NarrowPhaseCollision/SimplexSolverInterface.h"
|
||||
#include "CollisionShapes/ConvexShape.h"
|
||||
#include "GEN_MinMax.h"
|
||||
|
||||
#define ASSERT_MESSAGE
|
||||
|
||||
class ReplaceMeAccuracy {
|
||||
public:
|
||||
static SimdScalar rel_error2; // squared relative error in the computed distance
|
||||
static SimdScalar depth_tolerance; // terminate EPA if upper_bound <= depth_tolerance * dist2
|
||||
static SimdScalar tol_error; // error tolerance if the distance is almost zero
|
||||
|
||||
static void setAccuracy(SimdScalar rel_error)
|
||||
{
|
||||
rel_error2 = rel_error * rel_error;
|
||||
depth_tolerance = SimdScalar(1.0f) + SimdScalar(2.0f) * rel_error;
|
||||
}
|
||||
|
||||
static void setTolerance(SimdScalar epsilon)
|
||||
{
|
||||
tol_error = epsilon;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static const SimdScalar rel_error = SimdScalar(1.0e-3);
|
||||
|
||||
SimdScalar ReplaceMeAccuracy::rel_error2 = rel_error * rel_error;
|
||||
SimdScalar ReplaceMeAccuracy::depth_tolerance = SimdScalar(1.0) + SimdScalar(2.0) * rel_error;
|
||||
SimdScalar ReplaceMeAccuracy::tol_error = SIMD_EPSILON;
|
||||
|
||||
|
||||
|
||||
|
||||
class ReplaceMeFacet;
|
||||
|
||||
|
||||
class ReplaceMeEdge {
|
||||
public:
|
||||
ReplaceMeEdge() {}
|
||||
ReplaceMeEdge(ReplaceMeFacet *facet, int index) :
|
||||
m_facet(facet),
|
||||
m_index(index) {}
|
||||
|
||||
ReplaceMeFacet *getFacet() const { return m_facet; }
|
||||
int getIndex() const { return m_index; }
|
||||
|
||||
int getSource() const;
|
||||
int getTarget() const;
|
||||
|
||||
private:
|
||||
ReplaceMeFacet *m_facet;
|
||||
int m_index;
|
||||
};
|
||||
|
||||
typedef std::vector<ReplaceMeEdge> ReplaceMeEdgeBuffer;
|
||||
|
||||
|
||||
class ReplaceMeFacet {
|
||||
public:
|
||||
ReplaceMeFacet() {}
|
||||
ReplaceMeFacet(int i0, int i1, int i2)
|
||||
: m_obsolete(false)
|
||||
{
|
||||
m_indices[0] = i0;
|
||||
m_indices[1] = i1;
|
||||
m_indices[2] = i2;
|
||||
}
|
||||
|
||||
inline int operator[](int i) const { return m_indices[i]; }
|
||||
|
||||
bool link(int edge0, ReplaceMeFacet *facet, int edge1);
|
||||
|
||||
|
||||
bool isObsolete() const { return m_obsolete; }
|
||||
|
||||
|
||||
bool computeClosest(const SimdVector3 *verts);
|
||||
|
||||
const SimdVector3& getClosest() const { return m_closest; }
|
||||
|
||||
bool isClosestInternal() const
|
||||
{
|
||||
return m_lambda1 >= SimdScalar(0.0) &&
|
||||
m_lambda2 >= SimdScalar(0.0) &&
|
||||
m_lambda1 + m_lambda2 <= m_det;
|
||||
}
|
||||
|
||||
SimdScalar getDist2() const { return m_dist2; }
|
||||
|
||||
SimdPoint3 getClosestPoint(const SimdPoint3 *points) const
|
||||
{
|
||||
const SimdPoint3& p0 = points[m_indices[0]];
|
||||
|
||||
return p0 + (m_lambda1 * (points[m_indices[1]] - p0) +
|
||||
m_lambda2 * (points[m_indices[2]] - p0)) / m_det;
|
||||
}
|
||||
|
||||
void silhouette(const SimdVector3& w, ReplaceMeEdgeBuffer& edgeBuffer)
|
||||
{
|
||||
edgeBuffer.clear();
|
||||
m_obsolete = true;
|
||||
m_adjFacets[0]->silhouette(m_adjEdges[0], w, edgeBuffer);
|
||||
m_adjFacets[1]->silhouette(m_adjEdges[1], w, edgeBuffer);
|
||||
m_adjFacets[2]->silhouette(m_adjEdges[2], w, edgeBuffer);
|
||||
}
|
||||
|
||||
private:
|
||||
void silhouette(int index, const SimdVector3& w, ReplaceMeEdgeBuffer& edgeBuffer);
|
||||
|
||||
int m_indices[3];
|
||||
bool m_obsolete;
|
||||
ReplaceMeFacet *m_adjFacets[3];
|
||||
int m_adjEdges[3];
|
||||
|
||||
SimdScalar m_det;
|
||||
SimdScalar m_lambda1;
|
||||
SimdScalar m_lambda2;
|
||||
SimdVector3 m_closest;
|
||||
SimdScalar m_dist2;
|
||||
};
|
||||
|
||||
|
||||
inline int incMod3(int i) { return ++i % 3; }
|
||||
|
||||
|
||||
bool ReplaceMeFacet::link(int edge0, ReplaceMeFacet *facet, int edge1)
|
||||
{
|
||||
m_adjFacets[edge0] = facet;
|
||||
m_adjEdges[edge0] = edge1;
|
||||
facet->m_adjFacets[edge1] = this;
|
||||
facet->m_adjEdges[edge1] = edge0;
|
||||
|
||||
bool b = m_indices[edge0] == facet->m_indices[incMod3(edge1)] &&
|
||||
m_indices[incMod3(edge0)] == facet->m_indices[edge1];
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
bool ReplaceMeFacet::computeClosest(const SimdVector3 *verts)
|
||||
{
|
||||
const SimdVector3& p0 = verts[m_indices[0]];
|
||||
|
||||
SimdVector3 v1 = verts[m_indices[1]] - p0;
|
||||
SimdVector3 v2 = verts[m_indices[2]] - p0;
|
||||
SimdScalar v1dv1 = v1.length2();
|
||||
SimdScalar v1dv2 = v1.dot(v2);
|
||||
SimdScalar v2dv2 = v2.length2();
|
||||
SimdScalar p0dv1 = p0.dot(v1);
|
||||
SimdScalar p0dv2 = p0.dot(v2);
|
||||
|
||||
m_det = v1dv1 * v2dv2 - v1dv2 * v1dv2; // non-negative
|
||||
//printf("m_det = %f\n",m_det);
|
||||
//ASSERT(m_det >= 0.f);
|
||||
|
||||
if (m_det >= (SIMD_EPSILON*SIMD_EPSILON)) {
|
||||
|
||||
m_lambda1 = p0dv2 * v1dv2 - p0dv1 * v2dv2;
|
||||
m_lambda2 = p0dv1 * v1dv2 - p0dv2 * v1dv1;
|
||||
|
||||
m_closest = p0 + (m_lambda1 * v1 + m_lambda2 * v2) / m_det;
|
||||
m_dist2 = m_closest.length2();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReplaceMeFacet::silhouette(int index, const SimdVector3& w,
|
||||
ReplaceMeEdgeBuffer& edgeBuffer)
|
||||
{
|
||||
if (!m_obsolete) {
|
||||
if (m_closest.dot(w) < m_dist2) {
|
||||
edgeBuffer.push_back(ReplaceMeEdge(this, index));
|
||||
}
|
||||
else {
|
||||
m_obsolete = true; // Facet is visible
|
||||
int next = incMod3(index);
|
||||
m_adjFacets[next]->silhouette(m_adjEdges[next], w, edgeBuffer);
|
||||
next = incMod3(next);
|
||||
m_adjFacets[next]->silhouette(m_adjEdges[next], w, edgeBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline int ReplaceMeEdge::getSource() const
|
||||
{
|
||||
return (*m_facet)[m_index];
|
||||
}
|
||||
|
||||
inline int ReplaceMeEdge::getTarget() const
|
||||
{
|
||||
return (*m_facet)[incMod3(m_index)];
|
||||
}
|
||||
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
const int MaxSupportPoints = 100;//1000;
|
||||
const int MaxFacets = 200;//b2000;
|
||||
|
||||
static SimdPoint3 pBuf[MaxSupportPoints];
|
||||
static SimdPoint3 qBuf[MaxSupportPoints];
|
||||
static SimdVector3 yBuf[MaxSupportPoints];
|
||||
|
||||
static ReplaceMeFacet facetBuf[MaxFacets];
|
||||
static int freeFacet = 0;
|
||||
static ReplaceMeFacet *facetHeap[MaxFacets];
|
||||
static int num_facets;
|
||||
|
||||
class ReplaceMeFacetComp {
|
||||
public:
|
||||
|
||||
bool operator()(const ReplaceMeFacet *face1, const ReplaceMeFacet *face2)
|
||||
{
|
||||
return face1->getDist2() > face2->getDist2();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ReplaceMeFacetComp myFacetComp;
|
||||
|
||||
inline ReplaceMeFacet *addFacet(int i0, int i1, int i2,
|
||||
SimdScalar lower2, SimdScalar upper2)
|
||||
{
|
||||
assert(i0 != i1 && i0 != i2 && i1 != i2);
|
||||
if (freeFacet < MaxFacets)
|
||||
{
|
||||
ReplaceMeFacet *facet = new(&facetBuf[freeFacet++]) ReplaceMeFacet(i0, i1, i2);
|
||||
#ifdef DEBUG
|
||||
std::cout << "Facet " << i0 << ' ' << i1 << ' ' << i2;
|
||||
#endif
|
||||
if (facet->computeClosest(yBuf))
|
||||
{
|
||||
if (facet->isClosestInternal() &&
|
||||
lower2 <= facet->getDist2() && facet->getDist2() <= upper2)
|
||||
{
|
||||
facetHeap[num_facets++] = facet;
|
||||
ASSERT_MESSAGE(num_facets<MaxFacets,"Error in facet/pendepth");
|
||||
|
||||
std::push_heap(&facetHeap[0], &facetHeap[num_facets], myFacetComp);
|
||||
#ifdef DEBUG
|
||||
std::cout << " accepted" << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cout << " rejected, ";
|
||||
if (!facet->isClosestInternal())
|
||||
{
|
||||
std::cout << "closest point not internal";
|
||||
}
|
||||
else if (lower2 > facet->getDist2())
|
||||
{
|
||||
std::cout << "facet is closer than orignal facet";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "facet is further than upper bound";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
return facet;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline bool originInTetrahedron(const SimdVector3& p1, const SimdVector3& p2,
|
||||
const SimdVector3& p3, const SimdVector3& p4)
|
||||
{
|
||||
SimdVector3 normal1 = (p2 - p1).cross(p3 - p1);
|
||||
SimdVector3 normal2 = (p3 - p2).cross(p4 - p2);
|
||||
SimdVector3 normal3 = (p4 - p3).cross(p1 - p3);
|
||||
SimdVector3 normal4 = (p1 - p4).cross(p2 - p4);
|
||||
|
||||
return
|
||||
(normal1.dot(p1) > SimdScalar(0.0)) != (normal1.dot(p4) > SimdScalar(0.0)) &&
|
||||
(normal2.dot(p2) > SimdScalar(0.0)) != (normal2.dot(p1) > SimdScalar(0.0)) &&
|
||||
(normal3.dot(p3) > SimdScalar(0.0)) != (normal3.dot(p2) > SimdScalar(0.0)) &&
|
||||
(normal4.dot(p4) > SimdScalar(0.0)) != (normal4.dot(p3) > SimdScalar(0.0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Solid3EpaPenetrationDepth::CalcPenDepth( SimplexSolverInterface& simplexSolver,
|
||||
ConvexShape* convexA,ConvexShape* convexB,
|
||||
const SimdTransform& transformA,const SimdTransform& transformB,
|
||||
SimdVector3& v, SimdPoint3& pa, SimdPoint3& pb)
|
||||
{
|
||||
|
||||
int num_verts = simplexSolver.getSimplex(pBuf, qBuf, yBuf);
|
||||
|
||||
switch (num_verts)
|
||||
{
|
||||
case 1:
|
||||
// Touching contact. Yes, we have a collision,
|
||||
// but no penetration.
|
||||
return false;
|
||||
case 2:
|
||||
{
|
||||
// We have a line segment inside the Minkowski sum containing the
|
||||
// origin. Blow it up by adding three additional support points.
|
||||
|
||||
SimdVector3 dir = (yBuf[1] - yBuf[0]).normalized();
|
||||
int axis = dir.furthestAxis();
|
||||
|
||||
static SimdScalar sin_60 = 0.8660254037f;//84438646763723170752941.22474487f;//13915890490986420373529;//
|
||||
|
||||
SimdQuaternion rot(dir[0] * sin_60, dir[1] * sin_60, dir[2] * sin_60, SimdScalar(0.5));
|
||||
SimdMatrix3x3 rot_mat(rot);
|
||||
|
||||
SimdVector3 aux1 = dir.cross(SimdVector3(axis == 0, axis == 1, axis == 2));
|
||||
SimdVector3 aux2 = rot_mat * aux1;
|
||||
SimdVector3 aux3 = rot_mat * aux2;
|
||||
|
||||
pBuf[2] = transformA(convexA->LocalGetSupportingVertex(aux1*transformA.getBasis()));
|
||||
qBuf[2] = transformB(convexB->LocalGetSupportingVertex((-aux1)*transformB.getBasis()));
|
||||
yBuf[2] = pBuf[2] - qBuf[2];
|
||||
|
||||
pBuf[3] = transformA(convexA->LocalGetSupportingVertex(aux2*transformA.getBasis()));
|
||||
qBuf[3] = transformB(convexB->LocalGetSupportingVertex((-aux2)*transformB.getBasis()));
|
||||
yBuf[3] = pBuf[3] - qBuf[3];
|
||||
|
||||
pBuf[4] = transformA(convexA->LocalGetSupportingVertex(aux3*transformA.getBasis()));
|
||||
qBuf[4] = transformB(convexB->LocalGetSupportingVertex((-aux3)*transformB.getBasis()));
|
||||
yBuf[4] = pBuf[4] - qBuf[4];
|
||||
|
||||
if (originInTetrahedron(yBuf[0], yBuf[2], yBuf[3], yBuf[4]))
|
||||
{
|
||||
pBuf[1] = pBuf[4];
|
||||
qBuf[1] = qBuf[4];
|
||||
yBuf[1] = yBuf[4];
|
||||
}
|
||||
else if (originInTetrahedron(yBuf[1], yBuf[2], yBuf[3], yBuf[4]))
|
||||
{
|
||||
pBuf[0] = pBuf[4];
|
||||
qBuf[0] = qBuf[4];
|
||||
yBuf[0] = yBuf[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Origin not in initial polytope
|
||||
return false;
|
||||
}
|
||||
|
||||
num_verts = 4;
|
||||
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
// We have a triangle inside the Minkowski sum containing
|
||||
// the origin. First blow it up.
|
||||
|
||||
SimdVector3 v1 = yBuf[1] - yBuf[0];
|
||||
SimdVector3 v2 = yBuf[2] - yBuf[0];
|
||||
SimdVector3 vv = v1.cross(v2);
|
||||
|
||||
pBuf[3] = transformA(convexA->LocalGetSupportingVertex(vv*transformA.getBasis()));
|
||||
qBuf[3] = transformB(convexB->LocalGetSupportingVertex((-vv)*transformB.getBasis()));
|
||||
yBuf[3] = pBuf[3] - qBuf[3];
|
||||
pBuf[4] = transformA(convexA->LocalGetSupportingVertex((-vv)*transformA.getBasis()));
|
||||
qBuf[4] = transformB(convexB->LocalGetSupportingVertex(vv*transformB.getBasis()));
|
||||
yBuf[4] = pBuf[4] - qBuf[4];
|
||||
|
||||
|
||||
if (originInTetrahedron(yBuf[0], yBuf[1], yBuf[2], yBuf[4]))
|
||||
{
|
||||
pBuf[3] = pBuf[4];
|
||||
qBuf[3] = qBuf[4];
|
||||
yBuf[3] = yBuf[4];
|
||||
}
|
||||
else if (!originInTetrahedron(yBuf[0], yBuf[1], yBuf[2], yBuf[3]))
|
||||
{
|
||||
// Origin not in initial polytope
|
||||
return false;
|
||||
}
|
||||
|
||||
num_verts = 4;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We have a tetrahedron inside the Minkowski sum containing
|
||||
// the origin (if GJK did it's job right ;-)
|
||||
|
||||
|
||||
if (!originInTetrahedron(yBuf[0], yBuf[1], yBuf[2], yBuf[3]))
|
||||
{
|
||||
// assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
num_facets = 0;
|
||||
freeFacet = 0;
|
||||
|
||||
ReplaceMeFacet *f0 = addFacet(0, 1, 2, SimdScalar(0.0), SIMD_INFINITY);
|
||||
ReplaceMeFacet *f1 = addFacet(0, 3, 1, SimdScalar(0.0), SIMD_INFINITY);
|
||||
ReplaceMeFacet *f2 = addFacet(0, 2, 3, SimdScalar(0.0), SIMD_INFINITY);
|
||||
ReplaceMeFacet *f3 = addFacet(1, 3, 2, SimdScalar(0.0), SIMD_INFINITY);
|
||||
|
||||
if (!f0 || f0->getDist2() == SimdScalar(0.0) ||
|
||||
!f1 || f1->getDist2() == SimdScalar(0.0) ||
|
||||
!f2 || f2->getDist2() == SimdScalar(0.0) ||
|
||||
!f3 || f3->getDist2() == SimdScalar(0.0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
f0->link(0, f1, 2);
|
||||
f0->link(1, f3, 2);
|
||||
f0->link(2, f2, 0);
|
||||
f1->link(0, f2, 2);
|
||||
f1->link(1, f3, 0);
|
||||
f2->link(1, f3, 1);
|
||||
|
||||
if (num_facets == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// at least one facet on the heap.
|
||||
|
||||
ReplaceMeEdgeBuffer edgeBuffer(20);
|
||||
|
||||
ReplaceMeFacet *facet = 0;
|
||||
|
||||
SimdScalar upper_bound2 = SIMD_INFINITY;
|
||||
|
||||
do {
|
||||
facet = facetHeap[0];
|
||||
std::pop_heap(&facetHeap[0], &facetHeap[num_facets], myFacetComp);
|
||||
--num_facets;
|
||||
|
||||
if (!facet->isObsolete())
|
||||
{
|
||||
assert(facet->getDist2() > SimdScalar(0.0));
|
||||
|
||||
if (num_verts == MaxSupportPoints)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cout << "Ouch, no convergence!!!" << std::endl;
|
||||
#endif
|
||||
ASSERT_MESSAGE(false,"Error: pendepth calc failed");
|
||||
break;
|
||||
}
|
||||
|
||||
pBuf[num_verts] = transformA(convexA->LocalGetSupportingVertex((facet->getClosest())*transformA.getBasis()));
|
||||
qBuf[num_verts] = transformB(convexB->LocalGetSupportingVertex((-facet->getClosest())*transformB.getBasis()));
|
||||
yBuf[num_verts] = pBuf[num_verts] - qBuf[num_verts];
|
||||
|
||||
|
||||
int index = num_verts++;
|
||||
SimdScalar far_dist2 = yBuf[index].dot(facet->getClosest());
|
||||
|
||||
|
||||
// Make sure the support mapping is OK.
|
||||
//assert(far_dist2 > SimdScalar(0.0));
|
||||
|
||||
//
|
||||
// this is to avoid problems with implicit-sphere-touching contact
|
||||
//
|
||||
if (far_dist2 < SimdScalar(0.0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GEN_set_min(upper_bound2, (far_dist2 * far_dist2) / facet->getDist2());
|
||||
|
||||
if (upper_bound2 <= ReplaceMeAccuracy::depth_tolerance * facet->getDist2()
|
||||
#define CHECK_NEW_SUPPORT
|
||||
#ifdef CHECK_NEW_SUPPORT
|
||||
|| yBuf[index] == yBuf[(*facet)[0]]
|
||||
|| yBuf[index] == yBuf[(*facet)[1]]
|
||||
|| yBuf[index] == yBuf[(*facet)[2]]
|
||||
#endif
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Compute the silhouette cast by the new vertex
|
||||
// Note that the new vertex is on the positive side
|
||||
// of the current facet, so the current facet is will
|
||||
// not be in the convex hull. Start local search
|
||||
// from this facet.
|
||||
|
||||
facet->silhouette(yBuf[index], edgeBuffer);
|
||||
|
||||
if (edgeBuffer.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ReplaceMeEdgeBuffer::const_iterator it = edgeBuffer.begin();
|
||||
ReplaceMeFacet *firstFacet =
|
||||
addFacet((*it).getTarget(), (*it).getSource(),
|
||||
index, facet->getDist2(), upper_bound2);
|
||||
|
||||
if (!firstFacet)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
firstFacet->link(0, (*it).getFacet(), (*it).getIndex());
|
||||
ReplaceMeFacet *lastFacet = firstFacet;
|
||||
|
||||
++it;
|
||||
for (; it != edgeBuffer.end(); ++it)
|
||||
{
|
||||
ReplaceMeFacet *newFacet =
|
||||
addFacet((*it).getTarget(), (*it).getSource(),
|
||||
index, facet->getDist2(), upper_bound2);
|
||||
|
||||
if (!newFacet)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!newFacet->link(0, (*it).getFacet(), (*it).getIndex()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!newFacet->link(2, lastFacet, 1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
lastFacet = newFacet;
|
||||
}
|
||||
if (it != edgeBuffer.end())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
firstFacet->link(2, lastFacet, 1);
|
||||
}
|
||||
}
|
||||
while (num_facets > 0 && facetHeap[0]->getDist2() <= upper_bound2);
|
||||
|
||||
#ifdef DEBUG
|
||||
std::cout << "#facets left = " << num_facets << std::endl;
|
||||
#endif
|
||||
|
||||
v = facet->getClosest();
|
||||
pa = facet->getClosestPoint(pBuf);
|
||||
pb = facet->getClosestPoint(qBuf);
|
||||
return true;
|
||||
}
|
||||
|
||||
42
Extras/ExtraSolid35/Solid3EpaPenetrationDepth.h
Normal file
42
Extras/ExtraSolid35/Solid3EpaPenetrationDepth.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* SOLID - Software Library for Interference Detection
|
||||
*
|
||||
* Copyright (C) 2001-2003 Dtecta. All rights reserved.
|
||||
*
|
||||
* This library may be distributed under the terms of the Q Public License
|
||||
* (QPL) as defined by Trolltech AS of Norway and appearing in the file
|
||||
* LICENSE.QPL included in the packaging of this file.
|
||||
*
|
||||
* This library may be distributed and/or modified under the terms of the
|
||||
* GNU General Public License (GPL) version 2 as published by the Free Software
|
||||
* Foundation and appearing in the file LICENSE.GPL included in the
|
||||
* packaging of this file.
|
||||
*
|
||||
* This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Commercial use or any other use of this library not covered by either
|
||||
* the QPL or the GPL requires an additional license from Dtecta.
|
||||
* Please contact info@dtecta.com for enquiries about the terms of commercial
|
||||
* use of this library.
|
||||
*/
|
||||
|
||||
#ifndef SOLID3_EPA_PENETRATION_DEPTH_H
|
||||
#define SOLID3_EPA_PENETRATION_DEPTH_H
|
||||
|
||||
|
||||
#include "NarrowPhaseCollision/ConvexPenetrationDepthSolver.h"
|
||||
|
||||
/// Solid3EpaPenetrationDepth contains the 'Expanding Polytope Algorithm' from Solid 3.5
|
||||
class Solid3EpaPenetrationDepth : public ConvexPenetrationDepthSolver
|
||||
{
|
||||
public:
|
||||
|
||||
virtual bool CalcPenDepth(SimplexSolverInterface& simplexSolver,
|
||||
ConvexShape* convexA,ConvexShape* convexB,
|
||||
const SimdTransform& transformA,const SimdTransform& transformB,
|
||||
SimdVector3& v, SimdPoint3& pa, SimdPoint3& pb);
|
||||
|
||||
};
|
||||
|
||||
#endif //SOLID3_EPA_PENETRATION_DEPTH_H
|
||||
450
Extras/ExtraSolid35/Solid3JohnsonSimplexSolver.cpp
Normal file
450
Extras/ExtraSolid35/Solid3JohnsonSimplexSolver.cpp
Normal file
@@ -0,0 +1,450 @@
|
||||
/*
|
||||
* SOLID - Software Library for Interference Detection
|
||||
*
|
||||
* Copyright (C) 2001-2003 Dtecta. All rights reserved.
|
||||
*
|
||||
* This library may be distributed under the terms of the Q Public License
|
||||
* (QPL) as defined by Trolltech AS of Norway and appearing in the file
|
||||
* LICENSE.QPL included in the packaging of this file.
|
||||
*
|
||||
* This library may be distributed and/or modified under the terms of the
|
||||
* GNU General Public License (GPL) version 2 as published by the Free Software
|
||||
* Foundation and appearing in the file LICENSE.GPL included in the
|
||||
* packaging of this file.
|
||||
*
|
||||
* This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Commercial use or any other use of this library not covered by either
|
||||
* the QPL or the GPL requires an additional license from Dtecta.
|
||||
* Please contact info@dtecta.com for enquiries about the terms of commercial
|
||||
* use of this library.
|
||||
*/
|
||||
|
||||
#include "Solid3JohnsonSimplexSolver.h"
|
||||
#include "GEN_MinMax.h"
|
||||
|
||||
//#define USE_BACKUP_PROCEDURE
|
||||
//#define FAST_CLOSEST
|
||||
|
||||
Solid3JohnsonSimplexSolver::Solid3JohnsonSimplexSolver()
|
||||
:
|
||||
m_bits1(0x0),
|
||||
m_all_bits(0x0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Solid3JohnsonSimplexSolver::~Solid3JohnsonSimplexSolver()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Solid3JohnsonSimplexSolver::reset()
|
||||
{
|
||||
m_bits1 = 0x0;
|
||||
m_all_bits = 0x0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Solid3JohnsonSimplexSolver::addVertex(const SimdVector3& w)
|
||||
{
|
||||
assert(!fullSimplex());
|
||||
m_last = 0;
|
||||
m_last_bit = 0x1;
|
||||
while (contains(m_bits1, m_last_bit))
|
||||
{
|
||||
++m_last;
|
||||
m_last_bit <<= 1;
|
||||
}
|
||||
m_y[m_last] = w;
|
||||
m_ylen2[m_last] = w.length2();
|
||||
m_all_bits = m_bits1 | m_last_bit;
|
||||
|
||||
update_cache();
|
||||
compute_det();
|
||||
}
|
||||
|
||||
void Solid3JohnsonSimplexSolver::addVertex(const SimdVector3& w, const SimdPoint3& p, const SimdPoint3& q)
|
||||
{
|
||||
addVertex(w);
|
||||
m_p[m_last] = p;
|
||||
m_q[m_last] = q;
|
||||
}
|
||||
|
||||
bool Solid3JohnsonSimplexSolver::emptySimplex() const
|
||||
{
|
||||
return m_bits1 == 0x0;
|
||||
}
|
||||
|
||||
bool Solid3JohnsonSimplexSolver::fullSimplex() const
|
||||
{
|
||||
return m_bits1 == 0xf;
|
||||
}
|
||||
|
||||
SimdScalar Solid3JohnsonSimplexSolver::maxVertex()
|
||||
{
|
||||
return m_maxlen2;
|
||||
}
|
||||
|
||||
bool Solid3JohnsonSimplexSolver::closest(SimdVector3& v)
|
||||
{
|
||||
#ifdef FAST_CLOSEST
|
||||
T_Bits s;
|
||||
for (s = m_bits1; s != 0x0; --s)
|
||||
{
|
||||
if (subseteq(s, m_bits1) && valid(s | m_last_bit))
|
||||
{
|
||||
//update bits !
|
||||
m_bits1 = s | m_last_bit;
|
||||
compute_vector(m_bits1, v);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (valid(m_last_bit))
|
||||
{
|
||||
//update bits !
|
||||
m_bits1 = m_last_bit;
|
||||
m_maxlen2 = m_ylen2[m_last];
|
||||
v = m_y[m_last];
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
T_Bits s;
|
||||
for (s = m_all_bits; s != 0x0; --s)
|
||||
{
|
||||
if (subseteq(s, m_all_bits) && valid(s))
|
||||
{
|
||||
m_bits1 = s;
|
||||
compute_vector(m_bits1, v);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Original GJK calls the backup procedure at this point.
|
||||
#ifdef USE_BACKUP_PROCEDURE
|
||||
backup_closest(SimdVector3& v);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int Solid3JohnsonSimplexSolver::getSimplex(SimdPoint3 *pBuf, SimdPoint3 *qBuf, SimdVector3 *yBuf) const
|
||||
{
|
||||
int num_verts = 0;
|
||||
int i;
|
||||
T_Bits bit;
|
||||
for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
|
||||
{
|
||||
if (contains(m_bits1, bit))
|
||||
{
|
||||
pBuf[num_verts] = m_p[i];
|
||||
qBuf[num_verts] = m_q[i];
|
||||
yBuf[num_verts] = m_y[i];
|
||||
|
||||
#ifdef DEBUG
|
||||
std::cout << "Point " << i << " = " << m_y[i] << std::endl;
|
||||
#endif
|
||||
|
||||
++num_verts;
|
||||
}
|
||||
}
|
||||
return num_verts;
|
||||
}
|
||||
|
||||
bool Solid3JohnsonSimplexSolver::inSimplex(const SimdVector3& w)
|
||||
{
|
||||
int i;
|
||||
T_Bits bit;
|
||||
for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
|
||||
{
|
||||
if (contains(m_all_bits, bit) && w == m_y[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Solid3JohnsonSimplexSolver::backup_closest(SimdVector3& v)
|
||||
{
|
||||
SimdScalar min_dist2 = SIMD_INFINITY;
|
||||
|
||||
T_Bits s;
|
||||
for (s = m_all_bits; s != 0x0; --s)
|
||||
{
|
||||
if (subseteq(s, m_all_bits) && proper(s))
|
||||
{
|
||||
SimdVector3 u;
|
||||
compute_vector(s, u);
|
||||
SimdScalar dist2 = u.length2();
|
||||
if (dist2 < min_dist2)
|
||||
{
|
||||
min_dist2 = dist2;
|
||||
//update bits !
|
||||
m_bits1 = s;
|
||||
v = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Solid3JohnsonSimplexSolver::compute_points(SimdPoint3& p1, SimdPoint3& p2)
|
||||
{
|
||||
SimdScalar sum = SimdScalar(0.0);
|
||||
p1.setValue(SimdScalar(0.0), SimdScalar(0.0), SimdScalar(0.0));
|
||||
p2.setValue(SimdScalar(0.0), SimdScalar(0.0), SimdScalar(0.0));
|
||||
int i;
|
||||
T_Bits bit;
|
||||
for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
|
||||
{
|
||||
if (contains(m_bits1, bit))
|
||||
{
|
||||
sum += m_det[m_bits1][i];
|
||||
p1 += m_p[i] * m_det[m_bits1][i];
|
||||
p2 += m_q[i] * m_det[m_bits1][i];
|
||||
}
|
||||
}
|
||||
|
||||
assert(sum > SimdScalar(0.0));
|
||||
SimdScalar s = SimdScalar(1.0) / sum;
|
||||
p1 *= s;
|
||||
p2 *= s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int Solid3JohnsonSimplexSolver::numVertices() const
|
||||
{
|
||||
int numverts = 0;
|
||||
int i,bit;
|
||||
for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
|
||||
{
|
||||
if (contains(m_bits1, bit))
|
||||
{
|
||||
numverts++;
|
||||
}
|
||||
}
|
||||
return numverts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////
|
||||
//internal
|
||||
|
||||
inline void Solid3JohnsonSimplexSolver::update_cache()
|
||||
{
|
||||
int i;
|
||||
T_Bits bit;
|
||||
for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
|
||||
{
|
||||
if (contains(m_bits1, bit))
|
||||
{
|
||||
m_edge[i][m_last] = m_y[i] - m_y[m_last];
|
||||
m_edge[m_last][i] = -m_edge[i][m_last];
|
||||
|
||||
#ifdef JOHNSON_ROBUST
|
||||
m_norm[i][m_last] = m_norm[m_last][i] = m_edge[i][m_last].length2();
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Solid3JohnsonSimplexSolver::valid(T_Bits s)
|
||||
{
|
||||
int i;
|
||||
T_Bits bit;
|
||||
for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
|
||||
{
|
||||
if (contains(m_all_bits, bit))
|
||||
{
|
||||
if (contains(s, bit))
|
||||
{
|
||||
if (m_det[s][i] <= SimdScalar(0.0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_det[s | bit][i] > SimdScalar(0.0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Solid3JohnsonSimplexSolver::proper(T_Bits s)
|
||||
{
|
||||
int i;
|
||||
T_Bits bit;
|
||||
for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
|
||||
{
|
||||
if (contains(s, bit) && m_det[s][i] <= SimdScalar(0.0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Solid3JohnsonSimplexSolver::compute_vector(T_Bits s, SimdVector3& v)
|
||||
{
|
||||
m_maxlen2 = SimdScalar(0.0);
|
||||
SimdScalar sum = SimdScalar(0.0);
|
||||
v .setValue(SimdScalar(0.0), SimdScalar(0.0), SimdScalar(0.0));
|
||||
|
||||
int i;
|
||||
T_Bits bit;
|
||||
for (i = 0, bit = 0x1; i < 4; ++i, bit <<= 1)
|
||||
{
|
||||
if (contains(s, bit))
|
||||
{
|
||||
sum += m_det[s][i];
|
||||
GEN_set_max(m_maxlen2, m_ylen2[i]);
|
||||
v += m_y[i] * m_det[s][i];
|
||||
}
|
||||
}
|
||||
|
||||
assert(sum > SimdScalar(0.0));
|
||||
|
||||
v /= sum;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef JOHNSON_ROBUST
|
||||
|
||||
inline void Solid3JohnsonSimplexSolver::compute_det()
|
||||
{
|
||||
m_det[m_last_bit][m_last] = 1;
|
||||
|
||||
int i;
|
||||
T_Bits si;
|
||||
for (i = 0, si = 0x1; i < 4; ++i, si <<= 1)
|
||||
{
|
||||
if (contains(m_bits1, si))
|
||||
{
|
||||
T_Bits s2 = si | m_last_bit;
|
||||
m_det[s2][i] = m_edge[m_last][i].dot(m_y[m_last]);
|
||||
m_det[s2][m_last] = m_edge[i][m_last].dot(m_y[i]);
|
||||
|
||||
int j;
|
||||
T_Bits sj;
|
||||
for (j = 0, sj = 0x1; j < i; ++j, sj <<= 1)
|
||||
{
|
||||
if (contains(m_bits1, sj))
|
||||
{
|
||||
int k;
|
||||
T_Bits s3 = sj | s2;
|
||||
|
||||
k = m_norm[i][j] < m_norm[m_last][j] ? i : m_last;
|
||||
m_det[s3][j] = m_det[s2][i] * m_edge[k][j].dot(m_y[i]) +
|
||||
m_det[s2][m_last] * m_edge[k][j].dot(m_y[m_last]);
|
||||
k = m_norm[j][i] < m_norm[m_last][i] ? j : m_last;
|
||||
m_det[s3][i] = m_det[sj|m_last_bit][j] * m_edge[k][i].dot(m_y[j]) +
|
||||
m_det[sj|m_last_bit][m_last] * m_edge[k][i].dot(m_y[m_last]);
|
||||
k = m_norm[i][m_last] < m_norm[j][m_last] ? i : j;
|
||||
m_det[s3][m_last] = m_det[sj|si][j] * m_edge[k][m_last].dot(m_y[j]) +
|
||||
m_det[sj|si][i] * m_edge[k][m_last].dot(m_y[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_all_bits == 0xf)
|
||||
{
|
||||
int k;
|
||||
|
||||
k = m_norm[1][0] < m_norm[2][0] ? (m_norm[1][0] < m_norm[3][0] ? 1 : 3) : (m_norm[2][0] < m_norm[3][0] ? 2 : 3);
|
||||
|
||||
m_det[0xf][0] = m_det[0xe][1] * m_edge[k][0].dot(m_y[1]) +
|
||||
m_det[0xe][2] * m_edge[k][0].dot(m_y[2]) +
|
||||
m_det[0xe][3] * m_edge[k][0].dot(m_y[3]);
|
||||
|
||||
k = m_norm[0][1] < m_norm[2][1] ? (m_norm[0][1] < m_norm[3][1] ? 0 : 3) : (m_norm[2][1] < m_norm[3][1] ? 2 : 3);
|
||||
|
||||
m_det[0xf][1] = m_det[0xd][0] * m_edge[k][1].dot(m_y[0]) +
|
||||
m_det[0xd][2] * m_edge[k][1].dot(m_y[2]) +
|
||||
m_det[0xd][3] * m_edge[k][1].dot(m_y[3]);
|
||||
|
||||
k = m_norm[0][2] < m_norm[1][2] ? (m_norm[0][2] < m_norm[3][2] ? 0 : 3) : (m_norm[1][2] < m_norm[3][2] ? 1 : 3);
|
||||
|
||||
m_det[0xf][2] = m_det[0xb][0] * m_edge[k][2].dot(m_y[0]) +
|
||||
m_det[0xb][1] * m_edge[k][2].dot(m_y[1]) +
|
||||
m_det[0xb][3] * m_edge[k][2].dot(m_y[3]);
|
||||
|
||||
k = m_norm[0][3] < m_norm[1][3] ? (m_norm[0][3] < m_norm[2][3] ? 0 : 2) : (m_norm[1][3] < m_norm[2][3] ? 1 : 2);
|
||||
|
||||
m_det[0xf][3] = m_det[0x7][0] * m_edge[k][3].dot(m_y[0]) +
|
||||
m_det[0x7][1] * m_edge[k][3].dot(m_y[1]) +
|
||||
m_det[0x7][2] * m_edge[k][3].dot(m_y[2]);
|
||||
}
|
||||
}
|
||||
|
||||
#else //JOHNSON_ROBUST
|
||||
|
||||
|
||||
inline void Solid3JohnsonSimplexSolver::compute_det()
|
||||
{
|
||||
m_det[m_last_bit][m_last] = 1;
|
||||
|
||||
int i;
|
||||
T_Bits si;
|
||||
for (i = 0, si = 0x1; i < 4; ++i, si <<= 1)
|
||||
{
|
||||
if (contains(m_bits1, si))
|
||||
{
|
||||
T_Bits s2 = si | m_last_bit;
|
||||
m_det[s2][i] = m_edge[m_last][i].dot(m_y[m_last]);
|
||||
m_det[s2][m_last] = m_edge[i][m_last].dot(m_y[i]);
|
||||
|
||||
int j;
|
||||
T_Bits sj;
|
||||
for (j = 0, sj = 0x1; j < i; ++j, sj <<= 1)
|
||||
{
|
||||
if (contains(m_bits1, sj))
|
||||
{
|
||||
T_Bits s3 = sj | s2;
|
||||
m_det[s3][j] = m_det[s2][i] * m_edge[i][j].dot(m_y[i]) +
|
||||
m_det[s2][m_last] * m_edge[i][j].dot(m_y[m_last]);
|
||||
m_det[s3][i] = m_det[sj|m_last_bit][j] * m_edge[j][i].dot(m_y[j]) +
|
||||
m_det[sj|m_last_bit][m_last] * m_edge[j][i].dot(m_y[m_last]);
|
||||
m_det[s3][m_last] = m_det[sj|si][j] * m_edge[j][m_last].dot(m_y[j]) +
|
||||
m_det[sj|si][i] * m_edge[j][m_last].dot(m_y[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_all_bits == 0xf)
|
||||
{
|
||||
m_det[0xf][0] = m_det[0xe][1] * m_edge[1][0].dot(m_y[1]) +
|
||||
m_det[0xe][2] * m_edge[1][0].dot(m_y[2]) +
|
||||
m_det[0xe][3] * m_edge[1][0].dot(m_y[3]);
|
||||
m_det[0xf][1] = m_det[0xd][0] * m_edge[0][1].dot(m_y[0]) +
|
||||
m_det[0xd][2] * m_edge[0][1].dot(m_y[2]) +
|
||||
m_det[0xd][3] * m_edge[0][1].dot(m_y[3]);
|
||||
m_det[0xf][2] = m_det[0xb][0] * m_edge[0][2].dot(m_y[0]) +
|
||||
m_det[0xb][1] * m_edge[0][2].dot(m_y[1]) +
|
||||
m_det[0xb][3] * m_edge[0][2].dot(m_y[3]);
|
||||
m_det[0xf][3] = m_det[0x7][0] * m_edge[0][3].dot(m_y[0]) +
|
||||
m_det[0x7][1] * m_edge[0][3].dot(m_y[1]) +
|
||||
m_det[0x7][2] * m_edge[0][3].dot(m_y[2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //JOHNSON_ROBUST
|
||||
105
Extras/ExtraSolid35/Solid3JohnsonSimplexSolver.h
Normal file
105
Extras/ExtraSolid35/Solid3JohnsonSimplexSolver.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* SOLID - Software Library for Interference Detection
|
||||
*
|
||||
* Copyright (C) 2001-2003 Dtecta. All rights reserved.
|
||||
*
|
||||
* This library may be distributed under the terms of the Q Public License
|
||||
* (QPL) as defined by Trolltech AS of Norway and appearing in the file
|
||||
* LICENSE.QPL included in the packaging of this file.
|
||||
*
|
||||
* This library may be distributed and/or modified under the terms of the
|
||||
* GNU General Public License (GPL) version 2 as published by the Free Software
|
||||
* Foundation and appearing in the file LICENSE.GPL included in the
|
||||
* packaging of this file.
|
||||
*
|
||||
* This library is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Commercial use or any other use of this library not covered by either
|
||||
* the QPL or the GPL requires an additional license from Dtecta.
|
||||
* Please contact info@dtecta.com for enquiries about the terms of commercial
|
||||
* use of this library.
|
||||
*/
|
||||
|
||||
#ifndef SOLID3JOHNSON_SIMPLEX_SOLVER_H
|
||||
#define SOLID3JOHNSON_SIMPLEX_SOLVER_H
|
||||
|
||||
#include "NarrowPhaseCollision/SimplexSolverInterface.h"
|
||||
|
||||
//#define JOHNSON_ROBUST
|
||||
|
||||
|
||||
/// Solid3JohnsonSimplexSolver contains Johnson subdistance algorithm from Solid 3.5 library
|
||||
class Solid3JohnsonSimplexSolver : public SimplexSolverInterface
|
||||
{
|
||||
|
||||
private:
|
||||
typedef unsigned int T_Bits;
|
||||
inline static bool subseteq(T_Bits a, T_Bits b) { return (a & b) == a; }
|
||||
inline static bool contains(T_Bits a, T_Bits b) { return (a & b) != 0x0; }
|
||||
|
||||
void update_cache();
|
||||
void compute_det();
|
||||
bool valid(T_Bits s);
|
||||
bool proper(T_Bits s);
|
||||
void compute_vector(T_Bits s, SimdVector3& v);
|
||||
|
||||
|
||||
SimdScalar m_det[16][4]; // cached sub-determinants
|
||||
SimdVector3 m_edge[4][4];
|
||||
|
||||
#ifdef JOHNSON_ROBUST
|
||||
SimdScalar m_norm[4][4];
|
||||
#endif
|
||||
|
||||
SimdPoint3 m_p[4]; // support points of object A in local coordinates
|
||||
SimdPoint3 m_q[4]; // support points of object B in local coordinates
|
||||
SimdVector3 m_y[4]; // support points of A - B in world coordinates
|
||||
SimdScalar m_ylen2[4]; // Squared lengths support points y
|
||||
|
||||
SimdScalar m_maxlen2; // Maximum squared length to a vertex of the current
|
||||
// simplex
|
||||
T_Bits m_bits1; // identifies current simplex
|
||||
T_Bits m_last; // identifies last found support point
|
||||
T_Bits m_last_bit; // m_last_bit == 0x1 << last
|
||||
T_Bits m_all_bits; // m_all_bits == m_bits | m_last_bit
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void addVertex(const SimdVector3& w);
|
||||
|
||||
public:
|
||||
Solid3JohnsonSimplexSolver();
|
||||
|
||||
virtual ~Solid3JohnsonSimplexSolver();
|
||||
|
||||
virtual void reset();
|
||||
|
||||
virtual void addVertex(const SimdVector3& w, const SimdPoint3& p, const SimdPoint3& q);
|
||||
|
||||
virtual bool closest(SimdVector3& v);
|
||||
|
||||
virtual SimdScalar maxVertex();
|
||||
|
||||
virtual bool fullSimplex() const;
|
||||
|
||||
virtual int getSimplex(SimdPoint3 *pBuf, SimdPoint3 *qBuf, SimdVector3 *yBuf) const;
|
||||
|
||||
virtual bool inSimplex(const SimdVector3& w);
|
||||
|
||||
virtual void backup_closest(SimdVector3& v) ;
|
||||
|
||||
virtual bool emptySimplex() const ;
|
||||
|
||||
virtual void compute_points(SimdPoint3& p1, SimdPoint3& p2) ;
|
||||
|
||||
virtual int numVertices() const ;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //SOLID3JOHNSON_SIMPLEX_SOLVER_H
|
||||
BIN
Extras/FCollada/COLLADA_Specification_140.pdf
Normal file
BIN
Extras/FCollada/COLLADA_Specification_140.pdf
Normal file
Binary file not shown.
145
Extras/FCollada/Changes.txt
Normal file
145
Extras/FCollada/Changes.txt
Normal file
@@ -0,0 +1,145 @@
|
||||
Release 1.08
|
||||
[ zhang 04-04-06] FXC exports images within <effect>, but ColladaMaya looks for images in <library_images>. Disable the error return in image loading in FCDEffectParameterSurface, and add the dump of images in the FCDEffect.
|
||||
[glaforte 03-04-06] Export and Documentation: Documenting the FCDSceneNode class. Added the FCDTFactory class to easily create and import new transforms. Fixed the parenting of transforms inside scene nodes. Changed the visual scene node<64>s target flag into a target counter, in case there are multiple cameras/lights that target the same visual scene node. Documented the FCDTransform class and all its up-classes.
|
||||
[ aazar 03-04-06] Fixed with Guillaume a curve cloning issue and removed the ownsCurve boolean from FCDAnimated.
|
||||
[ aazar 02-04-06] Fixed a code typo that prevented the loading of some physics scenes.
|
||||
[glaforte 02-04-06] Export and Documentation: Documented the FCDAnimation class and added necessary functions to insert/release/retrieve child elements. Documented/refactored the FCDAnimated base class and its many up-classes. Wrote an automated test procedure for the animation tree export/re-import. Added to this test the creation of an animation curve and placing that animation curve to affect one component of a light color. Added and implemented generic creating functions for the typed animated up-classes: these will be used to add animation curves. To add new animations, I need access to the animatable parameters directly, so I added to cameras, lights, materials and effect parameters accessor that return the float references not as constant. Documented the FCDAnimationChannel class and added the necessary mutators/curve insertion/release functionality. Documented the FCDAnimationCurve class and the FCDAnimationMultiCurve class.
|
||||
[glaforte 02-04-06] Export and Documentation: Documented the FUDaeWriter namespace. Documented the FUCrc32 namespace, the FUDebug and the FUAssert functions, the FUObject and the FUObjectContainer classes.
|
||||
[ aazar 28-04-06] Implemented Guillaume's suggestion for FCDEffectParameterSurfaceInit and created a factory along with clone methods. It might be a good idea to move these guys to a new file though, as FCDEffectParameterSurface.h/cpp are getting crowded.
|
||||
[glaforte 28-04-06] Export and Documentation: Documented the FCDExtra tree class and its technique/node sub-classes, also added the necessary information modifying/pulling and pushing functionality. Wrote an automated test for the export/re-import of a custom <extra> information tree. Documented the FUUniqueStringMapT template and started documenting the FUDaeWriter.h namespace.
|
||||
[ zhang 28-04-06] Added "channels" and "format_hint" COLLADA tokens.
|
||||
[glaforte 28-04-06] Export and Documentation: Documented the FUStringConversion, the FCDEntity, the FCDTargetedEntity classes.
|
||||
[glaforte 25-04-06] Export and Documentation: Added an automated import/re-export test for a simple skin controller with two joints and on top of a mesh. Added one automated import/re-import test for a simple morpher on top of spline. Fixed the export of the skin controller: wrong count on the accessor of the bind-pose source and the wrong source id was used for the influence weight input in the <vertex_weights> element. Added an automated test for the export/re-import of the orthographic camera.
|
||||
[glaforte 25-04-06] Export and Documentation: Documented the FCDEffectParameterSurface class, its initialization method sub-classes, the FCDController class, the FCDSkinController class and the FCDMorphController class. Added the FCDMorphTarget class, as the weight must now be attached to the controller at all times: before, I had a separate STL vector with the weights and on a resize, all the animations would have been lost. Added modifiers/pullers and pushers to these classes. Fixed ColladaMaya, ColladaMax and the viewer for the interface change in the morph controller class.
|
||||
[ aazar 25-04-06] Fixed bug that would cause crash in FCDMaterialInstance if a controller had another controller as a base target. Fixed a bug where the wrong nodes would be sent to the animation linking, preventing correct shading animation. Fixed driven animation by fixing some bugs in FCollada for the driver.
|
||||
[glaforte 25-04-06] Documentation and Export: Documented the FCDEffectParameterSurface class and its initialization method sub-classes. Added modifiers/pullers and pushers to these classes.
|
||||
[glaforte 25-04-06] Fixed the import of the orthographic camera: it always failed as the camera strangely became both orthographic and perspective at the same time.
|
||||
[glaforte 24-04-06] Export and Documentation: Documented the FCDImage class and added new modifiers/pullers/pushers. Modified the automated export/re-import test for the profile COMMON material to include a few textures and added the export/re-import of a few images for these textures. Fixed the export of COLLADA images: the id was missing and the filename was not a valid URL. Documented the FCDEffectParameterFactory class, the FCDEffectParameterList class, the FCDEffectParameter class and most of its derivates: the FCDEffectParameterSurface class is not yet documented. Added modifiers/pullers and pushers to all these classes, as well. Improved the document parsing error reporting by adding the line number on all the warnings/errors reported.
|
||||
[glaforte 22-04-06] Export and Documentation: Documented the FCDTexture class. The FCDEffectStandard class now always owns all its textures, as I added the texture push/pull for this class. It will be easier that way for COLLADA 1.3 backward compatibility: the texture entities are cloned. Documented the FCDEffectPassShader and fixes a few typos and grammar mistakes in the documentation.
|
||||
[glaforte 21-04-06] Export and Documentation: Documented the FCDEffectTechnique class and the FCDEffectPass class. Documented the FCDEffectCode class. Fixed the STL-related doxygen warnings.
|
||||
[ aazar 20-04-06] Added a check for zero-length in FMVector3::NormalizeIt().
|
||||
[glaforte 20-04-06] Export and Documentation: The output file for the export/re-import automated test is starting to contain important information: ran it through a XML validator and fixed the validation issues: quite a few missing <20>sid<69> and <20>url<72> attributes, as well as quite a few required nodes: <20><node> in an empty visual scene<6E>, <20><pass> in an empty effect technique<75>...
|
||||
[glaforte 20-04-06] Export and Documentation: Documented the FCDEffectStandard class and the FCDEffectProfileFX class. Wrote two automated tests for the export and re-import of the CG and COMMON profile materials. Simplified the documentation, removing all the "defines a" and "defines the", to be simply "A" and "The".
|
||||
[glaforte 20-04-06] Export and Documentation: Documented the FCDEffect class. I realized that the FCDEffect class can still hold only one effect profile. Renamed the FCDEffectProfile class into the FCDEffectProfileFX class. Created a new FCDEffectProfile class which is the base class for the FCDEffectProfileFX and the FCDEffectStandard classes. Refactored the FCDEffect class to contain a list of FCDEffectProfile objects. Documented/implemented the FCDEffectProfile class. Updated ColladaMaya, ColladaMax and the Feeling Viewer to use the new effect/profile architecture.
|
||||
[ aazar 19-04-06] Fixed material instancing issue with geometry controllers.
|
||||
[glaforte 17-04-06] Export and Documentation: Started writing the export-import test for the materials/effects classes. Documented the FCDMaterialLibrary and FCDMaterial classes. Removed the ClearDaeIdWithoutTouchingTheUniqueMap function from the FCDObjectWithId class and refactored the import of materials to handle empty materials correctly. This will need to be re-tested with COLLADA 1.3 materials.
|
||||
[glaforte 17-04-06] Export and Documentation: Added Doxygen group for all the math classes. Re-organized the automated export/import test into multiple files and a namespace. Wrote an automated test for the export/import of lights. Fixed the case of the exported light type. Added un-implemented RemoveEntity function to the library. This function will require a lot of extra structure.
|
||||
[glaforte 17-04-06] Documentation: Finished (finally), the documentation of the FCDCamera class. Corrected some doxygen warnings in the polygon set class and the document class.
|
||||
|
||||
Release 1.07
|
||||
[glaforte 13-04-06] FCollada: Corrected a small application-compatibility issue found in ColladaMax.
|
||||
[glaforte 13-04-06] FCollada: Added basic exception handling in non-debug builds and fixed XSI import of animation curve tangents [theirs are 2D points, we use the strange bezier derivate].
|
||||
[ aazar 13-04-06] Fixed overwrite/clone bug in the FCDEffectParameterSurface. Everything works back correctly with shaders. Fixed reading of multiple <init_from> elements. Fixed reading of gravity and timestep in the Collada file. Added angular velocity to physics
|
||||
[ zhang 13-04-06] Traverse the group node and looking for <bind_material> to import light link.
|
||||
[ aazar 12-04-06] Fixed bug in file path reading for FCDEffectCode. This fixed the rendering for a few Cg datasets. Rewrote the FCDEffectParameterSurface class to support the 40,000 new initialization possibilities of a surface.
|
||||
[ zhang 12-04-06] Modified FindNamedAnimated() with string operations.
|
||||
[glaforte 11-04-06] Integration: Integrated the errors found within FCollada by Autodesk's recent changes to ColladaMax.
|
||||
[glaforte 10-04-06] Export and Documentation: Continued writing a simple test scenario for a mesh export/import: added a list of static indices for the vertex positions and colors to export and verify on re-import. Added functions to the mesh polygon set interface to add and remove faces. Since holes and faces are listed together within the face-vertex degree list for a polygon set, added function to access the hole/face information using an iterative index for faces.
|
||||
[glaforte 07-04-06] Export and Documentation: Wrote the export/re-import test for the geometry sources. Fixed a memory hog within the DAE import code. Added a new constructor and an equivalency function for the FloatList class, which is now a class rather than a typedef. Added push/pull function for polygon set inputs as well as some renaming.
|
||||
[glaforte 07-04-06] Export and Documentation: Documented the FCDGeometryPolygons and FCDGeometryPolygonsInput classes. Removed the <20>sourceId?member from the polygon set input class, as it now contains a pointer to the data source. Improved the interface of the geometry polygon set class. Added FMFloat and FMInteger, in order to better classify the information previously contained within FUtils.h. FMath.h now includes all the mathematical classes below it, rather than have FUtils includes them.
|
||||
[glaforte 06-04-06] Export and documentation: Started an export/re-import test for a geometry mesh. Documented the FCDGeometryMesh class at the same time as I added the information pushing functions and improved on the interface of the class. Documented the FCDGeometrySource class. Created a new sub-class: FCDObjectWithId, so that non-entity objects which require a unique id have access to that functionality. Documented the FCDObject and FCDObjectWithId classes. Fixed the export of the geometry source.
|
||||
[glaforte 06-04-06] Export and Documentation: Enabled and fixed the MSVC 64-bit warnings: many integer types went from uint32 to size_t, which is unsigned, or intptr_t, which is signed. LibXML required a lot of work, as there are many 8-bit string substractions to calculate sizes. Removed from LibXML the "trio" classes, which were unused.
|
||||
[ aazar 06-04-06] Fixed bug in FCDEffectParameter concerning 1D, 3D and Cube samplers.
|
||||
|
||||
Release 1.06
|
||||
[glaforte 05-04-06] Zapped a few Doxygen warnings.
|
||||
[glaforte 05-04-06] Documented FUDateTime.h. Documented FUXmlWriter.h.
|
||||
[glaforte 05-04-06] Removed the FPoint and FMatrix typedefs. Everyone should use FMVector3 and FMMatrix44 instead. Documented the FUStatus class and some of the FUtils.h macros. Added FUString.h which includes string-related macros/functions previously found in FUtils.h.
|
||||
[glaforte 05-04-06] Work from two weeks ago: continued the documentation of the FCDCamera class.
|
||||
[glaforte 04-04-06] Bug #38: Debug crash when importing. Reported by Alfred, this issue occurs only when importing a COLLADA document that has some visibility animation. This bug was due to leaking animation curves, when the animation curves for visibility were cloned in FCollada.
|
||||
[ zhang 31-03-06] FCDEffectParameterBool returns boolean value
|
||||
[ aazar 28-03-06] Implemented hack to allow Collada 1.3 materials and effects to load properly with the unique IDs. Simplified the FCDMaterialLibrary::LoadFromXML.
|
||||
[glaforte 27-03-06] Updated the documentation for FCDLibrary and up-ed the version of the FCollada library.
|
||||
|
||||
Internal Release 1.05
|
||||
[glaforte 27-03-06] Export and Documentation: Wrote the documentation for the FCDGeometry class. Added the CreateMesh and CreateSpline functions to the FCDGeometry class, in order to create a new mesh/spline for a new geometry object. Fixed the export of the camera, which was missing the <optics> element. Fixed the re-import of the entity notes: Refactored the extra structure containment. The FCDEntity base class now contains the extra structure. Documented and wrote an import/export test for the FCDGeometrySpline class. Implemented the export of splines. Improved the interface of the FCDGeometrySpline class so that retrieving information for splines is slightly less convoluted.
|
||||
[ aazar 27-03-06] Fixed loading of physics scene since unique names have been implemented. We now load the rigid constraints and bodies correctly from sid instead of id, but looking them up in their physics model.
|
||||
[glaforte 24-03-06] Added a test sequence for the export/import/push of camera information. Started documenting the FCDCamera class.
|
||||
[glaforte 24-03-06] Completed the first draft Doxygeon documentation for the FCDocument class.
|
||||
[ aazar 24-03-06] Completed some WriteToXML functions in physics classes. Fixed some bugs in the analytical geometries.
|
||||
[glaforte 24-03-06] Started the documentation of the FCDocument class and header.
|
||||
[glaforte 23-03-06] More information pushing: of transforms. Some re-organization of the scene node class header with some accessor additions. Initialization of the matrix can now take in a constant list of floats. Added testing of the pushing/export/import of transforms.
|
||||
[ aazar 23-03-06] Adapted FCDImage to read in height, width and depth.
|
||||
[glaforte 23-03-06] Started a full, simple, import-export scene test for visual scenes within FColladaTest. Wrote the push for libraries entities and the scene node transforms/children. Added the unique name map for the entities. Write out default names for all the entities, targeted or otherwise. Fixed a few export issues: empty names and the push of visual scene when there are no roots.
|
||||
[glaforte 23-03-06] Implemented the export of the animation clips. Added accessors for the parent of an animation channel.
|
||||
[ aazar 22-03-06] Fixed rigid constraint angular limit bug.
|
||||
[ aazar 17-03-06] In FCDPhysicsRigidConstraint, added reading in of translation/rotation nodes inside rigid constraint attachment, and fixed a bug in reading interpenetrate node.
|
||||
[glaforte 17-03-06] Added a flushing function to FULogFile.
|
||||
[claforte 16-03-06] Fixed crash when exporting the default sphere in ColladaMaya: due to the string builder not being initialized properly.
|
||||
[ aazar 16-03-06] Initialization and bug fix in FCDPhysicsRigidConstraint.
|
||||
[glaforte 16-03-06] Animation clips don't have Ids when exported from ColladaMaya, right now so work-around them when importing in FCollada.
|
||||
[claforte 15-03-06] Fixed import problems with files loaded from FX Composer 2, that have surfaces with no <init_from> image.
|
||||
[ aazar 15-03-06] Fixed Analytical shape reading from Collada file, and set only one radius per cylinder/capsule. Fixed bug in reading rigid constraints in FCDPhysicsModelInstance. Fixed bugs in reading rigid contraints parameters in FCDPhysicsRigidConstraint. Fixed bug reading in gravity in FCDPhysicsSceneNode.
|
||||
[ aleung 15-03-06] Fixed Maya parameters nodes that were missing in FCDEffectStandard.
|
||||
[glaforte 14-03-06] PS3: Fixed up the strlen within the string builder. Modified the absolute path creation with the FUFileManager.
|
||||
[ aazar 13-03-06] Updated the LoadFromXML functions of the analytical geometries to take into account they have no Id. Added some Get functions to the FCDPhysicsRigidConstraint.
|
||||
[claforte 13-03-06] Port to PS3: Fixed many warnings, e.g. missing newline at the end of include, enums were not using latest C++ spec, etc. Added #ifdefs related to PPU (PowerPC Unit), for stuff OpenGL ES-specific limitations, missing time() function, etc. Fixed bug in FindHierarchyChildBySid. Introduced some abstractions, e.g. fglActiveTexture and fglClientActiveTexture, to simplify support for OpenGL ES. Replaced Configure-generated makefile in PS3 DevIL by a hand-written one. Note that the ported version compiles and runs on the PS3, but nothing shows up due to #ifdef-ed code that needs to be written.
|
||||
[glaforte 13-03-06] Added to FDCSkinController::ReduceInfluences a minimum weight threshold.
|
||||
[ aazar 10-03-06] Mostly all physics-related: Completed the FCollada part for importing.
|
||||
[ aazar 10-03-06] Added cloning support for FCDAnimated, FCDAnimationClip and FCDAnimationCurve objects.
|
||||
[ aazar 10-03-06] Added SetClassName in FUObject so that classes can better identify themselves.
|
||||
[ aazar 10-03-06] Corrected a suspected bug in material and effect flattening.
|
||||
[ aazar 10-03-06] Fixed bug in creation of FCDPhysicsRigidConstraintInstance where it would try to compare the parent's type to the wrong one.
|
||||
[glaforte 08-03-06] Added a unique name map that somewhat generates unique names. Added whether the FMath classes are used within FCollada to the doxygen documentation. Some improvements on the FCollada test project.
|
||||
|
||||
Release 1.04
|
||||
[ aleung 06-03-06] Fixed up the Doxygen script for an improved main page template, files, global functions and completed the documentation of the FMath classes.
|
||||
[ aleung 03-03-06] Wrote an initial doxygen script. Started documenting the FMath classes for Doxygen.
|
||||
[glaforte 02-03-06] Planned the refactoring of the animation classes in order to support import/export/push/pull correctly. Added to the FCDAnimationCurve all the information necessary for it to do its own import/export. Similarly for FCDAnimationMultiCurve. When registering the animated values for export, just write out the targets to the curves. Implemented the recursive export of the animation trees.
|
||||
[glaforte 02-03-06] Fixed memory overwrite within the FUStringBuilder template class.
|
||||
[ zhang 28-02-06] Correct the float parameter min/max parsing.
|
||||
[glaforte 27-02-06] Removed the Maya-Max type references from FCollada. Fixed the compilation errors in FUtils.
|
||||
[glaforte 25-02-06] Added FUAssert and included Blinn shading on a few levels.
|
||||
[glaforte 23-02-06] Fixed-up the STL #includes, in an attempt to fix the FCollada DLL.
|
||||
[glaforte 23-02-06] 06-003-07: Fixed the loading of this skin test case, coming from COLLADA 1.3: the geometry cloning was not working when overriding the position-source.
|
||||
[glaforte 23-02-06] ColladaMaya Fixes: Fixed the morph target input types. Fixed the array export types to be IDREF_arrays as well as their accessor parameter types to be IDREF. Fixed the import of the animation drivers: the input driver target processing was not correctly.
|
||||
[ aleung 22-02-06] Performance: performance boost by reserving all the memory at once for the tessellations.
|
||||
[ aazar 21-02-06] Physics: Completed FCDPhysicsShape and FCDAnalyticalGeometry, added FCDPhysicsScene class separate from FCDScene. Fixed many parsing bugs (mostly related to the order of parsing and instantiation) and some crashes related to incomplete destructors. It is now possible to load physics scenes and the FCD classes will read in correctly all the physics information.
|
||||
[ aazar 21-02-06] Physics: Created the FCDPhysicsRigidConstraintInstance class. Completed the LoadXML for the FCDPhysicsRigidConstraint class.
|
||||
[glaforte 21-02-06] Importer: Fixed the scene node animation import sampling.
|
||||
[ aazar 20-02-06] Physics: Added lots of stuff for 1.4 Physics support. Some nodes are not complete yet, so don't try importing physics datasets as it will probably crash. The main nodes that need more work are the FCDPhysicsShape and the FCDPhysicsAnalyticalGeometry (need to derive classes for sphere, box, capsule, etc).
|
||||
[ aazar 20-02-06] Physics: The other change worth mentioning is a slight modification in the ToFloat functions of the FUStringConversion, to check for infinity. That's a sensitive function and if something goes wrong, the whole rendering gets screwed up.
|
||||
[glaforte 19-02-06] Light/Camera Export: Added and implemented the WriteToXML for the FCDlight and FCDCamera classes, writing out all the different supported light/camera types and the extra parameters for both Max and Maya, with their animations.
|
||||
|
||||
Release 1.03
|
||||
[glaforte 15-02-06] Fixed the matrix flattening of scene nodes.
|
||||
[glaforte 15-02-06] Fixed the import of scene node's notes/user-properties.
|
||||
[glaforte 14-02-06] Standard Material Export: Wrote the export of the standard material texture and its animated placement/projection parameters.
|
||||
[glaforte 13-02-06] Standard Material Export: Implemented the export of the standard material<61>s parameters and texture lists. Split the export function into four functions that export either the textures belong to the correct texture channel(s) as a standard material parameter, or the <color>/<float> element with its animation, if there is one.
|
||||
[glaforte 11-02-06] Controller Export: Added and implemented the WriteToXML to the FCDController, FCDMorphController and FCDSkinController classes. Added morph method string conversion. Implemented the export of IDRef arrays and sources. Corrected the missing id/name for the <geometry> element export. Corrected the extra ??in the morph target source. Corrected the <20>float?parameter type used too often in accessors.
|
||||
[glaforte 10-02-06] Fixed the ordering of the cloning, so that the FCDEffectCode objects are always cloned before the passes.
|
||||
[glaforte 09-02-06] Material Export: Split the FCDEffectPass class into itself and the FCDEffectPassShader class, which will hold all custom shader information, instead of assuming there are exactly one vertex and one fragment shader. Implemented the XML export of the FCDEffectPass and the FCDEffectPassShader classes. Created the FCDEffectCode class to hold both <include> and <code> ColladaFX element values. Corrected the <shader><name> element to read in the contents as the name and to use the <20>source?attribute for name-matching with the <include>/<code> elements.
|
||||
[glaforte 08-02-06] Instantiation Export: Added the basic WriteToXML functionality to the effects/materials and the instances.
|
||||
[glaforte 08-02-06] Fixed memory-related crash within the effect parameter release.
|
||||
[ aleung 08-02-06] Fixed compilation error in FCDMorphController.
|
||||
[glaforte 08-02-06] Instantiation Refactoring: Added the parsing of the <20>platform?attribute for ColladaFX profiles. Refactored the material instance class to hold the simple bind information as well. Added material <20>flattening?to the material instance class, so that viewers can assume only ColladaFX techniques hold parameters. The parameter values are trickled down by matching references. All the <newparam> parameters are trickled down, while the <setparam> parameters overwrite the <newparam> parameters below. Implemented the WriteToXML functions for the effect, the effect profile and the effect technique classes. Added the parsing of the <technique_hint> elements at the material level.
|
||||
[glaforte 08-02-06] Instantiation Refactoring: Added FCDEffectParameterList class, based on the std:vector of parameters, adding a parameter lookup-by-name function. Refactored the FCDEffectParameter to not be tied to a <20>pass?object, as a parent. The parameters now use their own reference string for error-reporting. Added a parameter list at the material, effect, profile and technique levels. Refactored the <20>pass?to hold simple bind information, rather than all the parameters.
|
||||
[glaforte 08-02-06] Instantiation Refactoring: In order to support correctly the export of geometry/controller instances, some refactoring is necessary, with respect to material parameters and their binding. The plan is to move from flattening materials on import to flattening materials on-demand, keeping the parameter override information around so that it can be modified and exported correctly.
|
||||
[glaforte 07-02-06] Animation Export: Remove empty animation libraries.
|
||||
[ aazar 07-02-06] Fixed a crash when releasing FCDocument, due to non-virtual destructors and missing memory deallocations.
|
||||
[glaforte 07-02-06] Animation Export: Implemented XML export functions for the basic animation curve: splitting the export of the sources, samplers and channels, in order to keep the <animation> element enforced ordering. Wrote the XML export functions for the merged animation curve, with a custom stride and multiple accessor parameters. Implemented the export of animated translations and rotations. Tested with a simple, animated DAE file. Found/Investigated memory corruption crash: was due to wrong include being added to the tools?project. Corrected id-generation for the animation sources, the export of float arrays.
|
||||
[glaforte 07-02-06] Animation Export: New feature: when generating a <20>sid? look for uniqueness, within the scope. Use an incremental counter appended to the wanted <20>sid?value, in order to generate unique sids. Fixed duplicated VERTEX geometry input, found within my current test case. Added the animation export to the other transformation elements.
|
||||
[glaforte 06-02-06] Animation Export: Plan out the export of animation curves, animated values and animation clips, for FCollada. Implemented the cleaning-up of name and id string values, in order to strip them of the invalid characters, on export. Save the node for the animation library in the FCDocument object. Added a function to export the animated value, if it has curves attached to it. Added and Implemented WriteToXML function for the animated value: check for curve merging, and then export either the merged curve or the individual curves.
|
||||
[glaforte 05-02-06] DLL Project: Some refactoring related to the usage of int8. Added functions to FUFileManager for relative/absolute/url filenames.
|
||||
[glaforte 05-02-06] Material Export: The material library now exports effects for ColladaFX profiles and the standard profile, as well as materials with instantiated effects. The image library now exports file images correctly.
|
||||
[claforte 03-02-06] Modified definitions used in ColladaMaya physics export: <limits> instead of <limit>, <ref_attachment>.
|
||||
[glaforte 03-02-06] Geometry Export/Refactoring: Added WriteToXML functions at the relevant levels. Split the FCDGeometry class into the spline and mesh components. This modifies the API for the FCollada: merge in the changes within the viewer.
|
||||
[glaforte 03-02-06] Import/Export of Asset tag: Added FCDAsset and FCDAssetContributor elements. Added FUDateTime class and its string parsing mechanism: mostly for the UTC times in the asset tags.
|
||||
|
||||
Release 1.02
|
||||
[glaforte 02-02-06] Some corrections of warnings/errors for MacOSX and GCC.
|
||||
[glaforte 01-02-06] Refactored the FUStringConversion header to have more inlined functions and reverted the changes on the ToFloat, ToUInt and ToInt functions to use our own parsing functions, as they were much faster than fstrtoX.
|
||||
[glaforte 31-01-06] FCollada Extra Tree: Added and Implemented FCDExtra, FCDETechnique and FCDENode classes. Added an FCDExtra object to the scene node.
|
||||
[glaforte 31-01-06] FCollada Extra Tree and Animations: Added FCDAnimatedCustom class that contains animation curves of any sizes and their float* targets directly. Refactored the animation system to link animations right away, resulting in a much smaller FCDAnimated object count. FCDENode contains an FCDAnimatedCustom object. Modified the scene node object to parse and extra the Max and Maya-specific parameters and their animations directly from the extra tree.
|
||||
[ aazar 31-01-06] Created FCDEffectTechnique class to support multiple techniques in ColladaFX. FCDEffectProfile now has a list of FCDEffectTechnique, which has a list of FCDEffectPass, which has a list of FCDEffectParameters.
|
||||
[glaforte 30-01-06] Added to FCDocument the export functions: WriteToFile and WriteDocumentToXML(). I'll be propagating these over the other FCDx classes.
|
||||
[glaforte 30-01-06] Added writing utility namespaces: FUXmlWriter and FUDaeWriter. Ported ColladaMaya's XML writing functions over to the FUXmlWriter, but FUDaeWriter is still empty.
|
||||
[glaforte 30-01-06] Added to FCDLibrary, FCDEntity and FCDSceneNode some basic writing functionality.
|
||||
[glaforte 30-01-06] Made all the write to XML functions const.
|
||||
[glaforte 30-01-06] Added ToString functions for FPoint and FMatrix, with length conversion.
|
||||
[glaforte 30-01-06] Added to FCDTransform and its derivates, XML writing functions.
|
||||
|
||||
Release 1.01
|
||||
[glaforte 30-01-06] First official version: includes all the modifications to the FS import classes made for the different projects,
|
||||
[glaforte 30-01-06] up to now. Added DLL support and unicode support to the project(s).
|
||||
|
||||
84
Extras/FCollada/Copyright.txt
Normal file
84
Extras/FCollada/Copyright.txt
Normal file
@@ -0,0 +1,84 @@
|
||||
You can get more information and the latest versions of the FCollada library
|
||||
on our website.
|
||||
|
||||
Feel free to drop us an email if you want more information on using the library.
|
||||
|
||||
Guillaume Laforte
|
||||
glaforte@feelingsoftware.com
|
||||
|
||||
Feeling Software Inc.
|
||||
http://www.feelingsoftware.com
|
||||
|
||||
|
||||
Copyright and License information:
|
||||
------------------------------------
|
||||
|
||||
|
||||
FCollada:
|
||||
----------
|
||||
Copyright 2006 Feeling Software.
|
||||
Under MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
|
||||
FS import classes:
|
||||
-----------------------
|
||||
Copyright 2005-2006 Feeling Software and
|
||||
Copyright 2005-2006 Autodesk Media Entertainment.
|
||||
Under MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
|
||||
LibXML2:
|
||||
---------
|
||||
Except where otherwise noted in the source code (e.g. the files
|
||||
hash.c,
|
||||
list.c and the trio files, which are covered by a similar
|
||||
licence but
|
||||
with different Copyright notices) all the files are:
|
||||
|
||||
|
||||
|
||||
Copyright (C) 1998-2003 Daniel Veillard. All Rights Reserved.
|
||||
|
||||
|
||||
Permission is hereby granted, free of charge,
|
||||
to any person obtaining a copy
|
||||
of this software and associated documentation
|
||||
files (the "Software"), to deal
|
||||
in the Software without restriction, including
|
||||
without limitation the rights
|
||||
to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell
|
||||
copies of the Software, and to
|
||||
permit persons to whom the Software is fur-
|
||||
nished to do so, subject
|
||||
to the following conditions:
|
||||
|
||||
The above copyright notice and this
|
||||
permission notice shall be included in
|
||||
all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FIT-
|
||||
NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE
|
||||
DANIEL VEILLARD BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
|
||||
NECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
|
||||
Except as contained in this notice, the name of Daniel
|
||||
Veillard shall not
|
||||
be used in advertising or otherwise to
|
||||
promote the sale, use or other deal-
|
||||
ings in this Software
|
||||
without prior written authorization from him.
|
||||
|
||||
39
Extras/FCollada/DLLEntry.cpp
Normal file
39
Extras/FCollada/DLLEntry.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
HINSTANCE hInstance = NULL;
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE _hInstance, ULONG UNUSED(fdwReason), LPVOID UNUSED(lpvReserved))
|
||||
{
|
||||
hInstance = _hInstance;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
namespace FCollada
|
||||
{
|
||||
FCOLLADA_EXPORT unsigned long GetVersion() { return FCOLLADA_VERSION; }
|
||||
};
|
||||
|
||||
#include "FMath/FMColor.h"
|
||||
#include "FUtils/FUDebug.h"
|
||||
#include "FUtils/FULogFile.h"
|
||||
|
||||
// Trick the linker so that it adds the functionalities of the classes that are not used internally.
|
||||
FCOLLADA_EXPORT void TrickLinker()
|
||||
{
|
||||
// FMColor
|
||||
FMColor* color = NULL;
|
||||
float* f = NULL;
|
||||
color->ToFloats(f, 4);
|
||||
|
||||
// FULogFile
|
||||
FULogFile* logFile = NULL;
|
||||
logFile->WriteLine("Test");
|
||||
|
||||
// FUDebug
|
||||
DebugOut("Tricking Linker...");
|
||||
}
|
||||
1237
Extras/FCollada/Doxyfile
Normal file
1237
Extras/FCollada/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
544
Extras/FCollada/FCDocument/FCDAnimated.cpp
Normal file
544
Extras/FCollada/FCDocument/FCDAnimated.cpp
Normal file
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDAnimationChannel.h"
|
||||
#include "FCDocument/FCDAnimationCurve.h"
|
||||
#include "FCDocument/FCDAnimationMultiCurve.h"
|
||||
#include "FCDocument/FCDAnimated.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDAnimated::FCDAnimated(FCDocument* document, size_t valueCount) : FCDObject(document, "FCDAnimated")
|
||||
{
|
||||
arrayElement = -1;
|
||||
|
||||
// Allocate the values/qualifiers/curves arrays
|
||||
values.resize(valueCount, NULL);
|
||||
qualifiers.resize(valueCount, "");
|
||||
curves.resize(valueCount, NULL);
|
||||
}
|
||||
|
||||
FCDAnimated::~FCDAnimated()
|
||||
{
|
||||
values.clear();
|
||||
qualifiers.clear();
|
||||
curves.clear();
|
||||
}
|
||||
|
||||
// Assigns a curve to a value of the animated element.
|
||||
bool FCDAnimated::SetCurve(size_t index, FCDAnimationCurve* curve)
|
||||
{
|
||||
FUAssert(index < GetValueCount(), return false);
|
||||
curves.at(index) = curve;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Removes the curve affecting a value of the animated element.
|
||||
bool FCDAnimated::RemoveCurve(size_t index)
|
||||
{
|
||||
FUAssert(index < GetValueCount(), return false);
|
||||
bool hasCurve = curves[index] != NULL;
|
||||
curves[index] = NULL;
|
||||
return hasCurve;
|
||||
}
|
||||
|
||||
bool FCDAnimated::Link(xmlNode* node)
|
||||
{
|
||||
bool linked = false;
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
// Write down the expected target string for the given node
|
||||
FUDaeParser::CalculateNodeTargetPointer(node, pointer);
|
||||
|
||||
// Check if this animated value is used as a driver
|
||||
linked |= GetDocument()->LinkDriver(this);
|
||||
|
||||
// Retrieve the list of the channels pointing to this node
|
||||
FCDAnimationChannelList channels;
|
||||
GetDocument()->FindAnimationChannels(pointer, channels);
|
||||
linked |= ProcessChannels(channels);
|
||||
}
|
||||
else linked = true;
|
||||
|
||||
if (linked)
|
||||
{
|
||||
// Register this animated value with the document
|
||||
GetDocument()->RegisterAnimatedValue(this);
|
||||
}
|
||||
|
||||
return linked;
|
||||
}
|
||||
|
||||
bool FCDAnimated::ProcessChannels(FCDAnimationChannelList& channels)
|
||||
{
|
||||
bool linked = false;
|
||||
for (FCDAnimationChannelList::iterator it = channels.begin(); it != channels.end(); ++it)
|
||||
{
|
||||
FCDAnimationChannel* channel = *it;
|
||||
const FCDAnimationCurveList& channelCurves = channel->GetCurves();
|
||||
if (channelCurves.empty()) continue;
|
||||
|
||||
// Retrieve the channel's qualifier and check for a requested matrix element
|
||||
string qualifier = channel->GetTargetQualifier();
|
||||
if (arrayElement != -1)
|
||||
{
|
||||
int32 element = ReadTargetMatrixElement(qualifier);
|
||||
if (arrayElement != element) continue;
|
||||
}
|
||||
|
||||
if (qualifier.empty())
|
||||
{
|
||||
// An empty qualifier implies that the channel should provide ALL the curves
|
||||
for (size_t i = 0; i < channelCurves.size() && i < curves.size(); ++i)
|
||||
{
|
||||
curves[i] = channelCurves[i];
|
||||
linked = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Attempt to match the qualifier with this animated qualifiers
|
||||
size_t index;
|
||||
for (index = 0; index < qualifiers.size(); ++index)
|
||||
{
|
||||
if (qualifiers[index] == qualifier) break;
|
||||
}
|
||||
|
||||
// Check for a matrix element instead
|
||||
if (index == qualifiers.size()) index = ReadTargetMatrixElement(qualifier);
|
||||
if (index < qualifiers.size())
|
||||
{
|
||||
curves[index] = channelCurves.front();
|
||||
linked = true;
|
||||
}
|
||||
/* else return status.Fail(FS("Invalid qualifier for animation channel target: ") + TO_FSTRING(pointer)); */
|
||||
}
|
||||
}
|
||||
|
||||
if (linked)
|
||||
{
|
||||
// Now that the curves are imported: set their target information
|
||||
for (size_t i = 0; i < curves.size(); ++i)
|
||||
{
|
||||
if (curves[i] != NULL)
|
||||
{
|
||||
curves[i]->SetTargetElement(arrayElement);
|
||||
curves[i]->SetTargetQualifier(qualifiers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return linked;
|
||||
}
|
||||
|
||||
const string& FCDAnimated::GetQualifier(size_t index) const
|
||||
{
|
||||
FUAssert(index < GetValueCount(), return emptyString);
|
||||
return qualifiers.at(index);
|
||||
}
|
||||
|
||||
// Retrieves an animated value, given a valid qualifier
|
||||
float* FCDAnimated::FindValue(const string& qualifier)
|
||||
{
|
||||
for (size_t i = 0; i < qualifiers.size(); ++i)
|
||||
{
|
||||
if (qualifiers[i] == qualifier) return values[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
const float* FCDAnimated::FindValue(const string& qualifier) const
|
||||
{
|
||||
for (size_t i = 0; i < qualifiers.size(); ++i)
|
||||
{
|
||||
if (qualifiers[i] == qualifier) return values[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Retrieve the index of a given qualifier
|
||||
size_t FCDAnimated::FindQualifier(const char* qualifier) const
|
||||
{
|
||||
for (size_t i = 0; i < qualifiers.size(); ++i)
|
||||
{
|
||||
if (qualifiers[i] == qualifier) return i;
|
||||
}
|
||||
|
||||
// Otherwise, check for a matrix element
|
||||
string q = qualifier;
|
||||
int32 matrixElement = FUDaeParser::ReadTargetMatrixElement(q);
|
||||
if (matrixElement >= 0 && matrixElement < (int32) qualifiers.size()) return matrixElement;
|
||||
return size_t(-1);
|
||||
}
|
||||
|
||||
// Retrieve the index of a given value pointer
|
||||
size_t FCDAnimated::FindValue(const float* value) const
|
||||
{
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
{
|
||||
if (values[i] == value) return i;
|
||||
}
|
||||
return size_t(-1);
|
||||
}
|
||||
|
||||
// Returns whether any of the contained curves are non-NULL
|
||||
bool FCDAnimated::HasCurve() const
|
||||
{
|
||||
FCDAnimationCurveList::const_iterator cit;
|
||||
for (cit = curves.begin(); cit != curves.end() && (*cit) == NULL; ++cit) {}
|
||||
return cit != curves.end();
|
||||
}
|
||||
|
||||
// Create one multi-curve out of this animated value's single curves
|
||||
FCDAnimationMultiCurve* FCDAnimated::CreateMultiCurve() const
|
||||
{
|
||||
FloatList defaultValues;
|
||||
size_t count = values.size();
|
||||
defaultValues.resize(count);
|
||||
for (size_t i = 0; i < count; ++i) defaultValues[i] = (*values[i]);
|
||||
|
||||
vector<const FCDAnimationCurve*> toMerge;
|
||||
toMerge.resize(count);
|
||||
for (size_t i = 0; i < count; ++i) toMerge[i] = curves[i];
|
||||
return FCDAnimationMultiCurve::MergeCurves(toMerge, defaultValues);
|
||||
}
|
||||
|
||||
// Create one multi-curve out of the single curves from many FCDAnimated objects
|
||||
FCDAnimationMultiCurve* FCDAnimated::CreateMultiCurve(const FCDAnimatedList& toMerge)
|
||||
{
|
||||
// Calculate the total dimension of the curve to create
|
||||
size_t count = 0;
|
||||
for (FCDAnimatedList::const_iterator cit = toMerge.begin(); cit != toMerge.end(); ++cit)
|
||||
{
|
||||
count += (*cit)->GetValueCount();
|
||||
}
|
||||
|
||||
// Generate the list of default values and the list of curves
|
||||
FloatList defaultValues(count, 0.0f);
|
||||
vector<const FCDAnimationCurve*> curves(count, NULL);
|
||||
size_t offset = 0;
|
||||
for (FCDAnimatedList::const_iterator cit = toMerge.begin(); cit != toMerge.end(); ++cit)
|
||||
{
|
||||
size_t localCount = (*cit)->GetValueCount();
|
||||
for (size_t i = 0; i < localCount; ++i)
|
||||
{
|
||||
defaultValues[offset + i] = *(*cit)->GetValue(i);
|
||||
curves[offset + i] = (*cit)->GetCurve(i);
|
||||
}
|
||||
offset += localCount;
|
||||
}
|
||||
|
||||
return FCDAnimationMultiCurve::MergeCurves(curves, defaultValues);
|
||||
}
|
||||
|
||||
// Sample the animated values for a given time
|
||||
void FCDAnimated::Evaluate(float time)
|
||||
{
|
||||
size_t valueCount = values.size();
|
||||
size_t curveCount = curves.size();
|
||||
size_t count = min(curveCount, valueCount);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
// Retrieve the curve and the corresponding value
|
||||
FCDAnimationCurve* curve = curves[i];
|
||||
if (curve == NULL) continue;
|
||||
float* value = values[i];
|
||||
if (value == NULL) continue;
|
||||
|
||||
// Evaluate the curve at this time
|
||||
(*value) = curve->Evaluate(time);
|
||||
}
|
||||
}
|
||||
|
||||
FCDAnimated* FCDAnimated::Clone(FCDocument* document)
|
||||
{
|
||||
FCDAnimated* clone = new FCDAnimated(document, GetValueCount());
|
||||
clone->arrayElement = arrayElement;
|
||||
for(size_t i = 0; i < curves.size(); ++i)
|
||||
{
|
||||
clone->curves[i] = curves[i]->Clone();
|
||||
}
|
||||
clone->pointer = pointer;
|
||||
clone->qualifiers = qualifiers;
|
||||
clone->values = values;
|
||||
document->RegisterAnimatedValue(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
// Clones the whole animated associated with a given value.
|
||||
FCDAnimated* FCDAnimated::Clone(FCDocument* document, const float* animatedValue, FloatPtrList& newAnimatedValues)
|
||||
{
|
||||
const FCDAnimated* toClone = document->FindAnimatedValue(animatedValue);
|
||||
if (toClone == NULL) return NULL;
|
||||
|
||||
FCDAnimated* clone = new FCDAnimated(document, toClone->GetValueCount());
|
||||
clone->arrayElement = toClone->arrayElement;
|
||||
for(size_t i = 0; i < toClone->curves.size(); ++i)
|
||||
{
|
||||
clone->curves[i] = toClone->curves[i];
|
||||
}
|
||||
|
||||
clone->pointer = toClone->pointer;
|
||||
clone->qualifiers = toClone->qualifiers;
|
||||
clone->values = newAnimatedValues;
|
||||
document->RegisterAnimatedValue(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
FCDAnimatedFloat::FCDAnimatedFloat(FCDocument* document, float* value, int32 _arrayElement) : FCDAnimated(document, 1)
|
||||
{
|
||||
values[0] = value;
|
||||
qualifiers[0] = "";
|
||||
arrayElement = _arrayElement;
|
||||
}
|
||||
|
||||
FCDAnimatedFloat* FCDAnimatedFloat::Create(FCDocument* document, float* value, int32 arrayElement)
|
||||
{
|
||||
FCDAnimatedFloat* animated = new FCDAnimatedFloat(document, value, arrayElement);
|
||||
if (!animated->Link(NULL)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
FCDAnimatedFloat* FCDAnimatedFloat::Create(FCDocument* document, xmlNode* node, float* value, int32 arrayElement)
|
||||
{
|
||||
FCDAnimatedFloat* animated = new FCDAnimatedFloat(document, value, arrayElement);
|
||||
if (!animated->Link(node)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
|
||||
FCDAnimated* FCDAnimatedFloat::Clone(FCDocument* document, const float* oldValue, float* newValue)
|
||||
{
|
||||
FloatPtrList newValues;
|
||||
newValues.push_back(newValue);
|
||||
return FCDAnimated::Clone(document, oldValue, newValues);
|
||||
}
|
||||
|
||||
FCDAnimatedPoint3::FCDAnimatedPoint3(FCDocument* document, FMVector3* value, int32 _arrayElement) : FCDAnimated(document, 3)
|
||||
{
|
||||
values[0] = &value->x; values[1] = &value->y; values[2] = &value->z;
|
||||
qualifiers[0] = ".X"; qualifiers[1] = ".Y"; qualifiers[2] = ".Z";
|
||||
arrayElement = _arrayElement;
|
||||
}
|
||||
|
||||
FCDAnimatedPoint3* FCDAnimatedPoint3::Create(FCDocument* document, FMVector3* value, int32 arrayElement)
|
||||
{
|
||||
FCDAnimatedPoint3* animated = new FCDAnimatedPoint3(document, value, arrayElement);
|
||||
if (!animated->Link(NULL)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
FCDAnimatedPoint3* FCDAnimatedPoint3::Create(FCDocument* document, xmlNode* node, FMVector3* value, int32 arrayElement)
|
||||
{
|
||||
FCDAnimatedPoint3* animated = new FCDAnimatedPoint3(document, value, arrayElement);
|
||||
if (!animated->Link(node)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
|
||||
FCDAnimated* FCDAnimatedPoint3::Clone(FCDocument* document, const FMVector3* oldValue, FMVector3* newValue)
|
||||
{
|
||||
FloatPtrList newValues;
|
||||
newValues.push_back(&newValue->x); newValues.push_back(&newValue->y); newValues.push_back(&newValue->z);
|
||||
return FCDAnimated::Clone(document, &oldValue->x, newValues);
|
||||
}
|
||||
|
||||
FCDAnimatedColor::FCDAnimatedColor(FCDocument* document, FMVector3* value, int32 _arrayElement) : FCDAnimated(document, 3)
|
||||
{
|
||||
values[0] = &value->x; values[1] = &value->y; values[2] = &value->z;
|
||||
qualifiers[0] = ".R"; qualifiers[1] = ".G"; qualifiers[2] = ".B";
|
||||
arrayElement = _arrayElement;
|
||||
}
|
||||
|
||||
FCDAnimatedColor* FCDAnimatedColor::Create(FCDocument* document, FMVector3* value, int32 arrayElement)
|
||||
{
|
||||
FCDAnimatedColor* animated = new FCDAnimatedColor(document, value, arrayElement);
|
||||
if (!animated->Link(NULL)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
FCDAnimatedColor* FCDAnimatedColor::Create(FCDocument* document, xmlNode* node, FMVector3* value, int32 arrayElement)
|
||||
{
|
||||
FCDAnimatedColor* animated = new FCDAnimatedColor(document, value, arrayElement);
|
||||
if (!animated->Link(node)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
|
||||
FCDAnimated* FCDAnimatedColor::Clone(FCDocument* document, const FMVector3* oldValue, FMVector3* newValue)
|
||||
{
|
||||
FloatPtrList newValues; newValues.push_back(&newValue->x); newValues.push_back(&newValue->y); newValues.push_back(&newValue->z);
|
||||
return FCDAnimated::Clone(document, &oldValue->x, newValues);
|
||||
}
|
||||
|
||||
FCDAnimatedAngle::FCDAnimatedAngle(FCDocument* document, float* value, int32 _arrayElement) : FCDAnimated(document, 1)
|
||||
{
|
||||
values[0] = value;
|
||||
qualifiers[0] = ".ANGLE";
|
||||
arrayElement = _arrayElement;
|
||||
}
|
||||
|
||||
FCDAnimatedAngle* FCDAnimatedAngle::Create(FCDocument* document, float* value, int32 arrayElement)
|
||||
{
|
||||
FCDAnimatedAngle* animated = new FCDAnimatedAngle(document, value, arrayElement);
|
||||
if (!animated->Link(NULL)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
FCDAnimatedAngle* FCDAnimatedAngle::Create(FCDocument* document, xmlNode* node, float* value, int32 arrayElement)
|
||||
{
|
||||
FCDAnimatedAngle* animated = new FCDAnimatedAngle(document, value, arrayElement);
|
||||
if (!animated->Link(node)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
|
||||
FCDAnimated* FCDAnimatedAngle::Clone(FCDocument* document, const float* oldValue, float* newValue)
|
||||
{
|
||||
FloatPtrList newValues;
|
||||
newValues.push_back(newValue);
|
||||
return FCDAnimated::Clone(document, oldValue, newValues);
|
||||
}
|
||||
|
||||
FCDAnimatedAngleAxis::FCDAnimatedAngleAxis(FCDocument* document, FMVector3* axis, float* angle, int32 _arrayElement) : FCDAnimated(document, 4)
|
||||
{
|
||||
values[0] = &axis->x; values[1] = &axis->y; values[2] = &axis->z; values[3] = angle;
|
||||
qualifiers[0] = ".X"; qualifiers[1] = ".Y"; qualifiers[2] = ".Z"; qualifiers[3] = ".ANGLE";
|
||||
arrayElement = _arrayElement;
|
||||
}
|
||||
|
||||
FCDAnimatedAngleAxis* FCDAnimatedAngleAxis::Create(FCDocument* document, FMVector3* axis, float* angle, int32 arrayElement)
|
||||
{
|
||||
FCDAnimatedAngleAxis* animated = new FCDAnimatedAngleAxis(document, axis, angle, arrayElement);
|
||||
if (!animated->Link(NULL)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
FCDAnimatedAngleAxis* FCDAnimatedAngleAxis::Create(FCDocument* document, xmlNode* node, FMVector3* axis, float* angle, int32 arrayElement)
|
||||
{
|
||||
FCDAnimatedAngleAxis* animated = new FCDAnimatedAngleAxis(document, axis, angle, arrayElement);
|
||||
if (!animated->Link(node)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
|
||||
FCDAnimated* FCDAnimatedAngleAxis::Clone(FCDocument* document, const float* oldAngle, FMVector3* newAxis, float* newAngle)
|
||||
{
|
||||
FloatPtrList newValues;
|
||||
newValues.push_back(&newAxis->x); newValues.push_back(&newAxis->y); newValues.push_back(&newAxis->z);
|
||||
newValues.push_back(newAngle);
|
||||
return FCDAnimated::Clone(document, oldAngle, newValues);
|
||||
}
|
||||
|
||||
FCDAnimatedMatrix::FCDAnimatedMatrix(FCDocument* document, FMMatrix44* value, int32 _arrayElement) : FCDAnimated(document, 16)
|
||||
{
|
||||
arrayElement = _arrayElement;
|
||||
|
||||
#define MX_V(a,b) values[b*4+a] = (&(*value)[a][b])
|
||||
MX_V(0,0); MX_V(1,0); MX_V(2,0); MX_V(3,0);
|
||||
MX_V(0,1); MX_V(1,1); MX_V(2,1); MX_V(3,1);
|
||||
MX_V(0,2); MX_V(1,2); MX_V(2,2); MX_V(3,2);
|
||||
MX_V(0,3); MX_V(1,3); MX_V(2,3); MX_V(3,3);
|
||||
#undef MX_V
|
||||
|
||||
#define MX_V(a,b) qualifiers[b*4+a] = ("(" #a ")(" #b ")");
|
||||
MX_V(0,0); MX_V(0,1); MX_V(0,2); MX_V(0,3);
|
||||
MX_V(1,0); MX_V(1,1); MX_V(1,2); MX_V(1,3);
|
||||
MX_V(2,0); MX_V(2,1); MX_V(2,2); MX_V(2,3);
|
||||
MX_V(3,0); MX_V(3,1); MX_V(3,2); MX_V(3,3);
|
||||
#undef MX_V
|
||||
}
|
||||
|
||||
FCDAnimatedMatrix* FCDAnimatedMatrix::Create(FCDocument* document, FMMatrix44* value, int32 arrayElement)
|
||||
{
|
||||
FCDAnimatedMatrix* animated = new FCDAnimatedMatrix(document, value, arrayElement);
|
||||
if (!animated->Link(NULL)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
FCDAnimatedMatrix* FCDAnimatedMatrix::Create(FCDocument* document, xmlNode* node, FMMatrix44* value, int32 arrayElement)
|
||||
{
|
||||
FCDAnimatedMatrix* animated = new FCDAnimatedMatrix(document, value, arrayElement);
|
||||
if (!animated->Link(node)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
|
||||
FCDAnimated* FCDAnimatedMatrix::Clone(FCDocument* document, const FMMatrix44* oldMx, FMMatrix44* newMx)
|
||||
{
|
||||
FloatPtrList newValues;
|
||||
|
||||
#define MX_V(a,b) newValues.push_back(&(*newMx)[a][b]);
|
||||
MX_V(0,0); MX_V(0,1); MX_V(0,2); MX_V(0,3);
|
||||
MX_V(1,0); MX_V(1,1); MX_V(1,2); MX_V(1,3);
|
||||
MX_V(2,0); MX_V(2,1); MX_V(2,2); MX_V(2,3);
|
||||
MX_V(3,0); MX_V(3,1); MX_V(3,2); MX_V(3,3);
|
||||
#undef MX_V
|
||||
|
||||
return FCDAnimated::Clone(document, &(*oldMx)[0][0], newValues);
|
||||
}
|
||||
|
||||
FCDAnimatedCustom::FCDAnimatedCustom(FCDocument* document) : FCDAnimated(document, 1)
|
||||
{
|
||||
dummy = 0.0f;
|
||||
}
|
||||
|
||||
bool FCDAnimatedCustom::Link(xmlNode* node)
|
||||
{
|
||||
bool linked = false;
|
||||
|
||||
// Retrieve the list of the channels pointing to this node
|
||||
FUDaeParser::CalculateNodeTargetPointer(node, pointer);
|
||||
FCDAnimationChannelList channels;
|
||||
GetDocument()->FindAnimationChannels(pointer, channels);
|
||||
|
||||
// Extract all the qualifiers needed to hold these channels
|
||||
for (FCDAnimationChannelList::iterator itC = channels.begin(); itC != channels.end(); ++itC)
|
||||
{
|
||||
FCDAnimationChannel* channel = *itC;
|
||||
const FCDAnimationCurveList& channelCurves = channel->GetCurves();
|
||||
if (channelCurves.empty()) continue;
|
||||
|
||||
// Retrieve the channel's qualifier
|
||||
string qualifier = channel->GetTargetQualifier();
|
||||
if (qualifier.empty())
|
||||
{
|
||||
// Implies one channel holding multiple curves
|
||||
qualifiers.clear();
|
||||
qualifiers.resize(channels.size());
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
qualifiers.push_back(qualifier);
|
||||
}
|
||||
}
|
||||
|
||||
// Link the curves and check if this animated value is used as a driver
|
||||
values.resize(qualifiers.size());
|
||||
curves.resize(values.size());
|
||||
for (size_t i = 0; i < qualifiers.size(); ++i) { values[i] = &dummy; curves[i] = NULL; }
|
||||
linked |= ProcessChannels(channels);
|
||||
linked |= GetDocument()->LinkDriver(this);
|
||||
|
||||
if (linked)
|
||||
{
|
||||
// Register this animated value with the document
|
||||
GetDocument()->RegisterAnimatedValue(this);
|
||||
}
|
||||
return linked;
|
||||
}
|
||||
|
||||
FCDAnimatedCustom* FCDAnimatedCustom::Create(FCDocument* document)
|
||||
{
|
||||
FCDAnimatedCustom* animated = new FCDAnimatedCustom(document);
|
||||
if (!animated->Link(NULL)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
FCDAnimatedCustom* FCDAnimatedCustom::Create(FCDocument* document, xmlNode* node)
|
||||
{
|
||||
FCDAnimatedCustom* animated = new FCDAnimatedCustom(document);
|
||||
if (!animated->Link(node)) SAFE_DELETE(animated);
|
||||
return animated;
|
||||
}
|
||||
488
Extras/FCollada/FCDocument/FCDAnimated.h
Normal file
488
Extras/FCollada/FCDocument/FCDAnimated.h
Normal file
@@ -0,0 +1,488 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDAnimated.h
|
||||
This file contains the FCDAnimated class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_ANIMATED_H_
|
||||
#define _FCD_ANIMATED_H_
|
||||
|
||||
#include "FCDocument/FCDObject.h"
|
||||
|
||||
class FCDocument;
|
||||
class FCDAnimated;
|
||||
class FCDAnimationCurve;
|
||||
class FCDAnimationChannel;
|
||||
class FCDAnimationMultiCurve;
|
||||
|
||||
typedef vector<float*> FloatPtrList; /**< A dynamically-sized array of floating-point value pointers. */
|
||||
typedef vector<FCDAnimationCurve*> FCDAnimationCurveList; /**< A dynamically-sized array of animation curves. */
|
||||
typedef vector<FCDAnimationChannel*> FCDAnimationChannelList; /**< A dynamically-sized array of animation channels. */
|
||||
typedef vector<FCDAnimated*> FCDAnimatedList; /**< A dynamically-sized array of animated values. */
|
||||
|
||||
/**
|
||||
An animated element.
|
||||
An animated element encapsulates a set of floating-point values that are
|
||||
marked as animated.
|
||||
|
||||
For this purpose, an animated element holds a list of floating-point values,
|
||||
their animation curves and their COLLADA qualifiers for the generation of
|
||||
COLLADA targets. For animated list elements, an animated element holds an array index.
|
||||
|
||||
There are many classes built on top of this class. They represent
|
||||
the different element types that may be animated, such as 3D points,
|
||||
colors and matrices.
|
||||
|
||||
@ingroup FCDocument
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDAnimated : public FCDObject
|
||||
{
|
||||
protected:
|
||||
/** The list of value pointers. */
|
||||
FloatPtrList values;
|
||||
|
||||
/** The list of target qualifiers.
|
||||
There is always one qualifier for one value pointer. */
|
||||
StringList qualifiers;
|
||||
|
||||
/** The list of animation curves.
|
||||
There is always one curve for one value pointer, although
|
||||
that curve may be the NULL pointer to indicate a non-animated value. */
|
||||
FCDAnimationCurveList curves;
|
||||
|
||||
/** The array index for animated element that belong
|
||||
to a list of animated elements. This value may be -1
|
||||
to indicate that the element does not belong to a list.
|
||||
Otherwise, the index should always be unsigned. */
|
||||
int32 arrayElement;
|
||||
|
||||
/** [INTERNAL] The target pointer prefix. */
|
||||
string pointer;
|
||||
|
||||
public:
|
||||
/** Constructor.
|
||||
In most cases, it is preferable to create objects of the up-classes.
|
||||
@param document The COLLADA document that owns this animated element.
|
||||
@param valueCount The number of values inside the animated element. */
|
||||
FCDAnimated(FCDocument* document, size_t valueCount);
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~FCDAnimated();
|
||||
|
||||
/** Retrieves the number of values contained within this animated element.
|
||||
@return The number of values. */
|
||||
inline size_t GetValueCount() const { return values.size(); }
|
||||
|
||||
/** Retrieves the animation curve affecting the value of an animated element.
|
||||
@param index The value index.
|
||||
@return The curve affecting the value at the given index. This pointer will
|
||||
be NULL if the index is out-of-bounds or if the value is not animated. */
|
||||
inline FCDAnimationCurve* GetCurve(size_t index) { FUAssert(index < GetValueCount(), return NULL); return curves.at(index); }
|
||||
inline const FCDAnimationCurve* GetCurve(size_t index) const { FUAssert(index < GetValueCount(), return NULL); return curves.at(index); } /**< See above. */
|
||||
|
||||
/** Retrieves the list of the curves affecting the values of an animated element.
|
||||
This list may contain the NULL pointer, where a value is not animated.
|
||||
@return The list of animation curves. */
|
||||
inline FCDAnimationCurveList& GetCurves() { return curves; }
|
||||
inline const FCDAnimationCurveList& GetCurves() const { return curves; } /**< See above. */
|
||||
|
||||
/** Assigns a curve to a value of the animated element.
|
||||
The previously assigned curve will be deleted.
|
||||
@param index The value index.
|
||||
@param curve The new curve that will affect the value at the given index.
|
||||
@return Whether the curve was successfully assigned. Will return false if
|
||||
the index is out-of-bounds. */
|
||||
bool SetCurve(size_t index, FCDAnimationCurve* curve);
|
||||
|
||||
/** Removes the curve affecting a value of the animated element.
|
||||
@param index The value index.
|
||||
@return Whether a curve was successfully removed. Will return false
|
||||
if there was no curve to release or the index is out-of-bounds. */
|
||||
bool RemoveCurve(size_t index);
|
||||
|
||||
/** Retrieves the value of an animated element.
|
||||
@param index The value index.
|
||||
@return The value at the given index. This pointer will
|
||||
be NULL if the index is out-of-boudns. */
|
||||
inline float* GetValue(size_t index) { FUAssert(index < GetValueCount(), return NULL); return values.at(index); }
|
||||
inline const float* GetValue(size_t index) const { FUAssert(index < GetValueCount(), return NULL); return values.at(index); } /**< See above. */
|
||||
|
||||
/** Retrieves the qualifier of the value of an animated element.
|
||||
@param index The value index.
|
||||
@return The qualifier for the value. The value returned will be an
|
||||
empty string when the index is out-of-bounds. */
|
||||
inline const string& GetQualifier(size_t index) const;
|
||||
|
||||
/** Retrieves an animated value given a valid qualifier.
|
||||
@param qualifier A valid qualifier.
|
||||
@return The animated value for this qualifier. This pointer will be
|
||||
NULL if the given qualifier is not used within this animated element. */
|
||||
float* FindValue(const string& qualifier);
|
||||
const float* FindValue(const string& qualifier) const; /**< See above. */
|
||||
|
||||
/** Retrieves an animation curve given a valid qualifier.
|
||||
@param qualifier A valid qualifier.
|
||||
@return The animation curve for this qualifier. This pointer will be
|
||||
NULL if the given qualifier is not used within this animated element
|
||||
or if the value for the given qualifier is not animated. */
|
||||
inline FCDAnimationCurve* FindCurve(const char* qualifier) { return GetCurve(FindQualifier(qualifier)); }
|
||||
inline FCDAnimationCurve* FindCurve(const string& qualifier) { return FindCurve(qualifier.c_str()); } /**< See above. */
|
||||
inline const FCDAnimationCurve* FindCurve(const char* qualifier) const { return GetCurve(FindQualifier(qualifier)); } /**< See above. */
|
||||
inline const FCDAnimationCurve* FindCurve(const string& qualifier) const { return FindCurve(qualifier.c_str()); } /**< See above. */
|
||||
|
||||
/** Retrieves an animation curve given a value pointer.
|
||||
@param value A value pointer contained within the animated element.
|
||||
@return The animation curve for this qualifier. This pointer will be
|
||||
NULL if the value pointer is not contained by this animated element
|
||||
or if the value is not animated. */
|
||||
inline FCDAnimationCurve* FindCurve(const float* value) { return GetCurve(FindValue(value)); }
|
||||
inline const FCDAnimationCurve* FindCurve(const float* value) const { return GetCurve(FindValue(value)); } /**< See above. */
|
||||
|
||||
/** Retrieves the value index for a given qualifier.
|
||||
@param qualifier A valid qualifier.
|
||||
@return The value index. This value will be -1 to indicate that the
|
||||
qualifier does not belong to this animated element. */
|
||||
size_t FindQualifier(const char* qualifier) const;
|
||||
inline size_t FindQualifier(const string& qualifier) const { return FindQualifier(qualifier.c_str()); } /**< See above. */
|
||||
|
||||
/** Retrieves the value index for a given value pointer.
|
||||
@param value A value pointer contained within the animated element.
|
||||
@return The value index. This value will be -1 to indicate that the
|
||||
value pointer is not contained by this animated element. */
|
||||
size_t FindValue(const float* value) const;
|
||||
|
||||
/** Retrieves the array index for an animated element.
|
||||
This value is used only for animated elements that belong
|
||||
to a list of animated elements within the COLLADA document.
|
||||
@return The array index. This value will be -1 to indicate that
|
||||
the animated element does not belong to a list. */
|
||||
inline int32 GetArrayElement() const { return arrayElement; }
|
||||
|
||||
/** Sets the array index for an animated element.
|
||||
This value is used only for animated elements that belong
|
||||
to a list of animated elements within the COLLADA document.
|
||||
@param index The array index. This value should be -1 to indicate that
|
||||
the animated element does not belong to a list. */
|
||||
inline void SetArrayElement(int32 index) { arrayElement = index; }
|
||||
|
||||
/** Retrieves whether this animated element has any animation curves
|
||||
affecting its values.
|
||||
@return Whether any curves affect this animated element. */
|
||||
bool HasCurve() const;
|
||||
|
||||
/** Creates one multi-dimensional animation curve from this animated element.
|
||||
This function is useful is your application does not handle animations
|
||||
per-values, but instead needs one animation per-element.
|
||||
@return The multi-dimensional animation curve. */
|
||||
FCDAnimationMultiCurve* CreateMultiCurve() const;
|
||||
|
||||
/** Creates one multi-dimensional animation curve from a list of animated element.
|
||||
This function is useful is your application does not handle animations
|
||||
per-values. For example, we use this function is ColladaMax for animated scale values,
|
||||
where one scale value is two rotations for the scale rotation pivot and one
|
||||
3D point for the scale factors.
|
||||
@param toMerge The list of animated elements to merge
|
||||
@return The multi-dimensional animation curve. */
|
||||
static FCDAnimationMultiCurve* CreateMultiCurve(const FCDAnimatedList& toMerge);
|
||||
|
||||
/** Evaluates the animated element at a given time.
|
||||
This function directly and <b>permanently</b> modifies the values
|
||||
of the animated element according to the curves affecting them.
|
||||
@param time The evaluation time. */
|
||||
void Evaluate(float time);
|
||||
|
||||
/** [INTERNAL] Clones an animated element.
|
||||
@param document The COLLADA document that owns the cloned animated element.
|
||||
@param animatedValue One animated value contained within the original animated element.
|
||||
@param newAnimatedValues The list of value pointers to be contained by the cloned animated element.
|
||||
@return The cloned animated element. */
|
||||
static FCDAnimated* Clone(FCDocument* document, const float* animatedValue, FloatPtrList& newAnimatedValues);
|
||||
|
||||
/** [INTERNAL] Clones an animated element.
|
||||
@param document The COLLADA document that owns the cloned animated element.
|
||||
@return The cloned animated element. */
|
||||
FCDAnimated* Clone(FCDocument* document);
|
||||
|
||||
/** [INTERNAL] Retrieves the target pointer that prefixes the
|
||||
fully-qualified target for the element.
|
||||
@return The target pointer prefix. */
|
||||
const string& GetTargetPointer() const { return pointer; }
|
||||
|
||||
/** [INTERNAL] Links this animated element with a given XML tree node.
|
||||
This function is solely used within the import of a COLLADA document.
|
||||
The floating-point values held within the XML tree node will be linked
|
||||
with the list of floating-point value pointers held by the animated entity.
|
||||
@param node The XML tree node.
|
||||
@return Whether there was any linkage done. */
|
||||
bool Link(xmlNode* node);
|
||||
|
||||
/** [INTERNAL] Links the animated element with the imported animation curves.
|
||||
This compares the animation channel targets with the animated element target
|
||||
and qualifiers to assign curves unto the value pointers.
|
||||
@param channels A list of animation channels with the correct target pointer.
|
||||
@return Whether any animation curves were assigned to the animation element. */
|
||||
bool ProcessChannels(FCDAnimationChannelList& channels);
|
||||
};
|
||||
|
||||
/** A COLLADA animated single floating-point value element.
|
||||
Use this animated element class for all generic-purpose single floating-point values.
|
||||
For angles, use the FCDAnimatedAngle class.
|
||||
@ingroup FCDocument */
|
||||
class FCOLLADA_EXPORT FCDAnimatedFloat : public FCDAnimated
|
||||
{
|
||||
private:
|
||||
// Don't build directly, use the Create function instead
|
||||
FCDAnimatedFloat(FCDocument* document, float* value, int32 arrayElement);
|
||||
|
||||
public:
|
||||
/** Creates a new animated element.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param value The value pointer for the single floating-point value.
|
||||
@param arrayElement The optional array index for animated element
|
||||
that belong to an animated element list.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedFloat* Create(FCDocument* document, float* value, int32 arrayElement=-1);
|
||||
|
||||
/** [INTERNAL] Creates a new animated element.
|
||||
This function is used during the import of a COLLADA document.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param node The XML tree node that contains the animated values.
|
||||
@param value The value pointer for the single floating-point value.
|
||||
@param arrayElement The optional array index for animated element
|
||||
that belong to an animated element list.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedFloat* Create(FCDocument* document, xmlNode* node, float* value, int32 arrayElement=-1);
|
||||
|
||||
/** [INTERNAL] Clones an animated element.
|
||||
@param document The COLLADA document that owns the cloned animated element.
|
||||
@param oldValue The single floating-point value pointer contained within the original animated element.
|
||||
@param newValue The single floating-point value pointer for the cloned animated element.
|
||||
@return The cloned animated value. */
|
||||
static FCDAnimated* Clone(FCDocument* document, const float* oldValue, float* newValue);
|
||||
};
|
||||
|
||||
/** A COLLADA animated 3D vector element.
|
||||
@ingroup FCDocument */
|
||||
class FCOLLADA_EXPORT FCDAnimatedPoint3 : public FCDAnimated
|
||||
{
|
||||
private:
|
||||
// Don't build directly, use the Create function instead
|
||||
FCDAnimatedPoint3(FCDocument* document, FMVector3* value, int32 arrayElement);
|
||||
|
||||
public:
|
||||
/** Creates a new animated element.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param value The value pointer for the 3D vector.
|
||||
@param arrayElement The optional array index for animated element
|
||||
that belong to an animated element list.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedPoint3* Create(FCDocument* document, FMVector3* value, int32 arrayElement=-1);
|
||||
|
||||
/** [INTERNAL] Creates a new animated element.
|
||||
This function is used during the import of a COLLADA document.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param node The XML tree node that contains the animated values.
|
||||
@param value The value pointer for the 3D vector.
|
||||
@param arrayElement The optional array index for animated element
|
||||
that belong to an animated element list.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedPoint3* Create(FCDocument* document, xmlNode* node, FMVector3* value, int32 arrayElement=-1);
|
||||
|
||||
/** [INTERNAL] Clones an animated element.
|
||||
@param document The COLLADA document that owns the cloned animated element.
|
||||
@param oldValue The 3D vector contained within the original animated element.
|
||||
@param newValue The 3D vector for the cloned animated element.
|
||||
@return The cloned animated value. */
|
||||
static FCDAnimated* Clone(FCDocument* document, const FMVector3* oldValue, FMVector3* newValue);
|
||||
};
|
||||
|
||||
/** A COLLADA animated RGB color element.
|
||||
@ingroup FCDocument */
|
||||
class FCOLLADA_EXPORT FCDAnimatedColor : public FCDAnimated
|
||||
{
|
||||
private:
|
||||
// Don't build directly, use the Create function instead
|
||||
FCDAnimatedColor(FCDocument* document, FMVector3* value, int32 arrayElement);
|
||||
|
||||
public:
|
||||
/** Creates a new animated element.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param value The value pointer for the RGB color.
|
||||
@param arrayElement The optional array index for animated element
|
||||
that belong to an animated element list.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedColor* Create(FCDocument* document, FMVector3* value, int32 arrayElement=-1);
|
||||
|
||||
/** [INTERNAL] Creates a new animated element.
|
||||
This function is used during the import of a COLLADA document.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param node The XML tree node that contains the animated values.
|
||||
@param value The value pointer for the RGB color.
|
||||
@param arrayElement The optional array index for animated element
|
||||
that belong to an animated element list.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedColor* Create(FCDocument* document, xmlNode* node, FMVector3* value, int32 arrayElement=-1);
|
||||
|
||||
/** [INTERNAL] Clones an animated element.
|
||||
@param document The COLLADA document that owns the cloned animated element.
|
||||
@param oldValue The RGB color contained within the original animated element.
|
||||
@param newValue The RGB color for the cloned animated element.
|
||||
@return The cloned animated value. */
|
||||
static FCDAnimated* Clone(FCDocument* document, const FMVector3* oldValue, FMVector3* newValue);
|
||||
};
|
||||
|
||||
/** A COLLADA floating-point value that represents an angle.
|
||||
@ingroup FCDocument */
|
||||
class FCOLLADA_EXPORT FCDAnimatedAngle : public FCDAnimated
|
||||
{
|
||||
private:
|
||||
// Don't build directly, use the Create function instead
|
||||
FCDAnimatedAngle(FCDocument* document, float* value, int32 arrayElement);
|
||||
|
||||
public:
|
||||
/** Creates a new animated element.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param value The value pointer for the angle.
|
||||
@param arrayElement The optional array index for animated element
|
||||
that belong to an animated element list.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedAngle* Create(FCDocument* document, float* value, int32 arrayElement=-1);
|
||||
|
||||
/** [INTERNAL] Creates a new animated element.
|
||||
This function is used during the import of a COLLADA document.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param node The XML tree node that contains the animated values.
|
||||
@param value The value pointer for the angle.
|
||||
@param arrayElement The optional array index for animated element
|
||||
that belong to an animated element list.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedAngle* Create(FCDocument* document, xmlNode* node, float* value, int32 arrayElement=-1);
|
||||
|
||||
/** [INTERNAL] Clones an animated element.
|
||||
@param document The COLLADA document that owns the cloned animated element.
|
||||
@param oldValue The angle value pointer contained within the original animated element.
|
||||
@param newValue The angle value pointer for the cloned animated element.
|
||||
@return The cloned animated value. */
|
||||
static FCDAnimated* Clone(FCDocument* document, const float* oldValue, float* newValue);
|
||||
};
|
||||
|
||||
/** A COLLADA animated angle-axis.
|
||||
Used for rotations, takes in a 3D vector for the axis and
|
||||
a single floating-point value for the angle.
|
||||
@ingroup FCDocument */
|
||||
class FCOLLADA_EXPORT FCDAnimatedAngleAxis : public FCDAnimated
|
||||
{
|
||||
private:
|
||||
// Don't build directly, use the Create function instead
|
||||
FCDAnimatedAngleAxis(FCDocument* document, FMVector3* axis, float* angle, int32 arrayElement);
|
||||
|
||||
public:
|
||||
/** Creates a new animated element.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param value The value pointer for the axis.
|
||||
@param angle The value pointer for the angle.
|
||||
@param arrayElement The optional array index for animated element
|
||||
that belong to an animated element list.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedAngleAxis* Create(FCDocument* document, FMVector3* value, float* angle, int32 arrayElement=-1);
|
||||
|
||||
/** [INTERNAL] Creates a new animated element.
|
||||
This function is used during the import of a COLLADA document.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param node The XML tree node that contains the animated values.
|
||||
@param axis The value pointer for the axis.
|
||||
@param angle The value pointer for the angle.
|
||||
@param arrayElement The optional array index for animated element
|
||||
that belong to an animated element list.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedAngleAxis* Create(FCDocument* document, xmlNode* node, FMVector3* axis, float* angle, int32 arrayElement=-1);
|
||||
|
||||
/** [INTERNAL] Clones an animated element.
|
||||
@param document The COLLADA document that owns the cloned animated element.
|
||||
@param oldAngle The angle value pointer contained within the original animated element.
|
||||
@param newAxis The axis value pointer for the cloned animated element.
|
||||
@param newAngle The angle value pointer for the cloned animated element.
|
||||
@return The cloned animated value. */
|
||||
static FCDAnimated* Clone(FCDocument* document, const float* oldAngle, FMVector3* newAxis, float* newAngle);
|
||||
};
|
||||
|
||||
/** A COLLADA animated matrix.
|
||||
Used for animated transforms, takes in a 16 floating-point values.
|
||||
@ingroup FCDocument */
|
||||
class FCOLLADA_EXPORT FCDAnimatedMatrix : public FCDAnimated
|
||||
{
|
||||
private:
|
||||
// Don't build directly, use the Create function instead
|
||||
FCDAnimatedMatrix(FCDocument* document, FMMatrix44* value, int32 arrayElement);
|
||||
|
||||
public:
|
||||
/** Creates a new animated element.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param value The value pointer for the matrix.
|
||||
@param arrayElement The optional array index for animated element
|
||||
that belong to an animated element list.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedMatrix* Create(FCDocument* document, FMMatrix44* value, int32 arrayElement=-1);
|
||||
|
||||
/** [INTERNAL] Creates a new animated element.
|
||||
This function is used during the import of a COLLADA document.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param node The XML tree node that contains the animated values.
|
||||
@param value The value pointer for the matrix.
|
||||
@param arrayElement The optional array index for animated element
|
||||
that belong to an animated element list.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedMatrix* Create(FCDocument* document, xmlNode* node, FMMatrix44* value, int32 arrayElement=-1);
|
||||
|
||||
/** [INTERNAL] Clones an animated element.
|
||||
@param document The COLLADA document that owns the cloned animated element.
|
||||
@param oldMx The matrix value pointer contained within the original animated element.
|
||||
@param newMx The matrix value pointer for the cloned animated element.
|
||||
@return The cloned animated value. */
|
||||
static FCDAnimated* Clone(FCDocument* document, const FMMatrix44* oldMx, FMMatrix44* newMx);
|
||||
};
|
||||
|
||||
/** A COLLADA custom animated value.
|
||||
Used for animated extra elements. A single value is used multiple times to hold
|
||||
as many value pointers are necessary to hold the animation curves.
|
||||
@ingroup FCDocument */
|
||||
class FCOLLADA_EXPORT FCDAnimatedCustom : public FCDAnimated
|
||||
{
|
||||
private:
|
||||
float dummy;
|
||||
|
||||
// Don't build directly, use the Create function instead
|
||||
FCDAnimatedCustom(FCDocument* document);
|
||||
|
||||
bool Link(xmlNode* node);
|
||||
|
||||
public:
|
||||
/** Creates a new animated element.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedCustom* Create(FCDocument* document);
|
||||
|
||||
/** [INTERNAL] Creates a new animated element.
|
||||
This function is used during the import of a COLLADA document.
|
||||
@param document The COLLADA document that owns the animated element.
|
||||
@param node The XML tree node that contains the animated values.
|
||||
@return The new animated element. */
|
||||
static FCDAnimatedCustom* Create(FCDocument* document, xmlNode* node);
|
||||
|
||||
/** Retrieves the floating-point value used for all the value pointers.
|
||||
@return The dummy floating-point value. */
|
||||
const float& GetDummy() const { return dummy; }
|
||||
};
|
||||
|
||||
#endif // _FCD_ANIMATED_H_
|
||||
|
||||
224
Extras/FCollada/FCDocument/FCDAnimation.cpp
Normal file
224
Extras/FCollada/FCDocument/FCDAnimation.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDAnimation.h"
|
||||
#include "FCDocument/FCDAnimationChannel.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
using namespace FUDaeParser;
|
||||
|
||||
FCDAnimation::FCDAnimation(FCDocument* document) : FCDEntity(document, "Animation")
|
||||
{
|
||||
}
|
||||
|
||||
FCDAnimation::~FCDAnimation()
|
||||
{
|
||||
CLEAR_POINTER_VECTOR(channels);
|
||||
CLEAR_POINTER_VECTOR(children);
|
||||
childNodes.clear();
|
||||
}
|
||||
|
||||
// Creates a new animation entity sub-tree contained within this animation entity tree.
|
||||
FCDAnimation* FCDAnimation::AddChild()
|
||||
{
|
||||
FCDAnimation* animation = new FCDAnimation(GetDocument());
|
||||
children.push_back(animation);
|
||||
return animation;
|
||||
}
|
||||
|
||||
// Releases an animation entity sub-tree contained by this animation entity tree.
|
||||
void FCDAnimation::ReleaseChild(FCDAnimation* animation)
|
||||
{
|
||||
FCDAnimationList::iterator itA = std::find(children.begin(), children.end(), animation);
|
||||
if (itA != children.end())
|
||||
{
|
||||
delete *itA;
|
||||
children.erase(itA);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a new animation channel to this animation entity.
|
||||
FCDAnimationChannel* FCDAnimation::AddChannel()
|
||||
{
|
||||
FCDAnimationChannel* channel = new FCDAnimationChannel(GetDocument(), this);
|
||||
channels.push_back(channel);
|
||||
return channel;
|
||||
}
|
||||
|
||||
// Releases an animation channel contained within this animation entity.
|
||||
void FCDAnimation::ReleaseChannel(FCDAnimationChannel* channel)
|
||||
{
|
||||
FCDAnimationChannelList::iterator itC = std::find(channels.begin(), channels.end(), channel);
|
||||
if (itC != channels.end())
|
||||
{
|
||||
delete *itC;
|
||||
channels.erase(itC);
|
||||
}
|
||||
}
|
||||
|
||||
// Optimization: Look for the xml child node with the given id
|
||||
xmlNode* FCDAnimation::FindChildById(const string& _id)
|
||||
{
|
||||
FUCrc32::crc32 id = FUCrc32::CRC32(_id.c_str() + ((_id[0] == '#') ? 1 : 0));
|
||||
for (FUXmlNodeIdPairList::iterator it = childNodes.begin(); it != childNodes.end(); ++it)
|
||||
{
|
||||
if ((*it).id == id) return (*it).node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Look for an animation children with the given COLLADA Id.
|
||||
FCDEntity* FCDAnimation::FindDaeId(const string& daeId)
|
||||
{
|
||||
if (GetDaeId() == daeId) return this;
|
||||
|
||||
for (FCDAnimationList::iterator it = children.begin(); it != children.end(); ++it)
|
||||
{
|
||||
FCDEntity* found = (*it)->FindDaeId(daeId);
|
||||
if (found != NULL) return found;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Retrieve all the curves created under this animation element, in the animation tree
|
||||
void FCDAnimation::GetCurves(FCDAnimationCurveList& curves)
|
||||
{
|
||||
// Retrieve the curves for this animation tree element
|
||||
for (FCDAnimationChannelList::iterator it = channels.begin(); it != channels.end(); ++it)
|
||||
{
|
||||
const FCDAnimationCurveList& channelCurves = (*it)->GetCurves();
|
||||
for (FCDAnimationCurveList::const_iterator itC = channelCurves.begin(); itC != channelCurves.end(); ++itC)
|
||||
{
|
||||
curves.push_back(*itC);
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the curves for the animation nodes under this one in the animation tree
|
||||
for (FCDAnimationList::iterator it = children.begin(); it != children.end(); ++it)
|
||||
{
|
||||
(*it)->GetCurves(curves);
|
||||
}
|
||||
}
|
||||
|
||||
FUStatus FCDAnimation::Link()
|
||||
{
|
||||
FUStatus status;
|
||||
|
||||
// Link the child nodes and check the curves for their drivers
|
||||
for (FCDAnimationChannelList::iterator it = channels.begin(); it != channels.end(); ++it)
|
||||
{
|
||||
status.AppendStatus((*it)->CheckDriver());
|
||||
}
|
||||
for (FCDAnimationList::iterator it = children.begin(); it != children.end(); ++it)
|
||||
{
|
||||
status.AppendStatus((*it)->Link());
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Check for animation curves that need this animated as a driver
|
||||
bool FCDAnimation::LinkDriver(FCDAnimated* animated)
|
||||
{
|
||||
bool driver = false;
|
||||
|
||||
// Link the child curves and child nodes
|
||||
for (FCDAnimationChannelList::iterator it = channels.begin(); it != channels.end(); ++it)
|
||||
{
|
||||
driver |= (*it)->LinkDriver(animated);
|
||||
}
|
||||
for (FCDAnimationList::iterator it = children.begin(); it != children.end(); ++it)
|
||||
{
|
||||
driver |= (*it)->LinkDriver(animated);
|
||||
}
|
||||
|
||||
return driver;
|
||||
}
|
||||
|
||||
// Load a Collada animation node from the XML document
|
||||
FUStatus FCDAnimation::LoadFromXML(xmlNode* node)
|
||||
{
|
||||
FUStatus status = FCDEntity::LoadFromXML(node);
|
||||
if (!status) return status;
|
||||
if (!IsEquivalent(node->name, DAE_ANIMATION_ELEMENT))
|
||||
{
|
||||
return status.Warning(FS("Animation library contains unknown element."), node->line);
|
||||
}
|
||||
|
||||
// Optimization: Grab all the IDs of the child nodes, in CRC format.
|
||||
ReadChildrenIds(node, childNodes);
|
||||
|
||||
// Parse all the inner <channel> elements
|
||||
xmlNodeList channelNodes;
|
||||
FindChildrenByType(node, DAE_CHANNEL_ELEMENT, channelNodes);
|
||||
channels.reserve(channelNodes.size());
|
||||
for (xmlNodeList::iterator itC = channelNodes.begin(); itC != channelNodes.end(); ++itC)
|
||||
{
|
||||
// Parse each <channel> element individually
|
||||
// They each handle reading the <sampler> and <source> elements
|
||||
FCDAnimationChannel* channel = AddChannel();
|
||||
status.AppendStatus(channel->LoadFromXML(*itC));
|
||||
if (!status)
|
||||
{
|
||||
ReleaseChannel(channel);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse all the hierarchical <animation> elements
|
||||
xmlNodeList animationNodes;
|
||||
FindChildrenByType(node, DAE_ANIMATION_ELEMENT, animationNodes);
|
||||
for (xmlNodeList::iterator itA = animationNodes.begin(); itA != animationNodes.end(); ++itA)
|
||||
{
|
||||
FCDAnimation* animation = AddChild();
|
||||
animation->LoadFromXML(*itA);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Search for an animation channel for the given XML pointer in this animation node
|
||||
void FCDAnimation::FindAnimationChannels(const string& pointer, vector<FCDAnimationChannel*>& targetChannels)
|
||||
{
|
||||
// Look for channels locally
|
||||
for (FCDAnimationChannelList::iterator itChannel = channels.begin(); itChannel != channels.end(); ++itChannel)
|
||||
{
|
||||
if ((*itChannel)->GetTargetPointer() == pointer)
|
||||
{
|
||||
targetChannels.push_back(*itChannel);
|
||||
}
|
||||
}
|
||||
|
||||
// Look for channel(s) within the child animations
|
||||
for (FCDAnimationList::iterator it = children.begin(); it != children.end(); ++it)
|
||||
{
|
||||
(*it)->FindAnimationChannels(pointer, targetChannels);
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the COLLADA animations to the document
|
||||
xmlNode* FCDAnimation::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* animationNode = WriteToEntityXML(parentNode, DAE_ANIMATION_ELEMENT);
|
||||
|
||||
// Write out the local channels
|
||||
for (FCDAnimationChannelList::const_iterator itChannel = channels.begin(); itChannel != channels.end(); ++itChannel)
|
||||
{
|
||||
(*itChannel)->WriteToXML(animationNode);
|
||||
}
|
||||
|
||||
// Write out the child animations
|
||||
for (FCDAnimationList::const_iterator it = children.begin(); it != children.end(); ++it)
|
||||
{
|
||||
(*it)->WriteToXML(animationNode);
|
||||
}
|
||||
|
||||
FCDEntity::WriteToExtraXML(animationNode);
|
||||
return animationNode;
|
||||
}
|
||||
163
Extras/FCollada/FCDocument/FCDAnimation.h
Normal file
163
Extras/FCollada/FCDocument/FCDAnimation.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDAnimation.h
|
||||
This file contains the FCDAnimation class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_ANIMATION_H_
|
||||
#define _FCD_ANIMATION_H_
|
||||
|
||||
#include "FUtils/FUXmlNodeIdPair.h"
|
||||
#include "FCDocument/FCDEntity.h"
|
||||
|
||||
class FCDocument;
|
||||
class FCDAnimated;
|
||||
class FCDAnimation;
|
||||
class FCDAnimationChannel;
|
||||
class FCDAnimationCurve;
|
||||
|
||||
typedef vector<FCDAnimation*> FCDAnimationList; /**< A dynamically-sized array of animation entities. */
|
||||
typedef vector<FCDAnimationChannel*> FCDAnimationChannelList; /**< A dynamically-sized array of animation channels. */
|
||||
typedef vector<FCDAnimationCurve*> FCDAnimationCurveList; /**< A dynamically-sized array of animation curves. */
|
||||
|
||||
/**
|
||||
A COLLADA animation entity.
|
||||
An animation entity contains a list of child animation entities,
|
||||
in order to form a tree of animation entities.
|
||||
It also hold a list of animation channels, which hold the information
|
||||
to generate animation curves.
|
||||
|
||||
In other words, the animation entity is a structural class
|
||||
used to group animation channels hierarchically.
|
||||
|
||||
@ingroup FCDocument
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDAnimation : public FCDEntity
|
||||
{
|
||||
private:
|
||||
FCDAnimationChannelList channels;
|
||||
FUXmlNodeIdPairList childNodes;
|
||||
FCDAnimationList children;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDLibrary::AddEntity function
|
||||
or the AddChild function, depending on the
|
||||
hierarchical level of the animation entity.
|
||||
@param document The COLLADA document that owns the animation entity. */
|
||||
FCDAnimation(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDLibrary::ReleaseEntity function
|
||||
or the ReleaseChild function, depending on the
|
||||
hierarchical level of the animation entity.*/
|
||||
virtual ~FCDAnimation();
|
||||
|
||||
/** Retrieves the entity class type.
|
||||
This function is a part of the FCDEntity interface.
|
||||
@return The entity class type: ANIMATION. */
|
||||
virtual Type GetType() const { return ANIMATION; }
|
||||
|
||||
/** Retrieves the entity with the given COLLADA id.
|
||||
This function will look through the local sub-tree of animations
|
||||
for the given COLLADA id.
|
||||
@param daeId A COLLADA id.
|
||||
@return The animation entity that matches the COLLADA id. This pointer
|
||||
will be NULL if there are no animation entities that matches the COLLADA id. */
|
||||
virtual FCDEntity* FindDaeId(const string& daeId);
|
||||
|
||||
/** Retrieves the number of animation entity sub-trees contained
|
||||
by this animation entity tree.
|
||||
@return The number of animation entity sub-trees. */
|
||||
inline size_t GetChildCount() const { return children.size(); }
|
||||
|
||||
/** Retrieves an animation entity sub-tree contained by this
|
||||
animation entity tree.
|
||||
@param index The index of the sub-tree.
|
||||
@return The animation entity sub-tree at the given index. This pointer will
|
||||
be NULL if the index is out-of-bounds. */
|
||||
inline FCDAnimation* GetChild(size_t index) { FUAssert(index < GetChildCount(), return NULL); return children.at(index); }
|
||||
inline const FCDAnimation* GetChild(size_t index) const { FUAssert(index < GetChildCount(), return NULL); return children.at(index); } /**< See above. */
|
||||
|
||||
/** Creates a new animation entity sub-tree contained within this animation entity tree.
|
||||
@return The new animation sub-tree. */
|
||||
inline FCDAnimation* AddChild();
|
||||
|
||||
/** Releases an animation entity sub-tree contained by this animation entity tree.
|
||||
@param animation The animation entity the release. */
|
||||
inline void ReleaseChild(FCDAnimation* animation);
|
||||
|
||||
/** Retrieves the animation channels that target the given COLLADA target pointer.
|
||||
@param pointer A COLLADA target pointer.
|
||||
@param targetChannels A list of animation channels to fill in.
|
||||
This list is not cleared. */
|
||||
void FindAnimationChannels(const string& pointer, FCDAnimationChannelList& targetChannels);
|
||||
|
||||
/** Retrieves the number of animation channels at this level within the animation tree.
|
||||
@return The number of animation channels. */
|
||||
size_t GetChannelCount() const { return channels.size(); }
|
||||
|
||||
/** Retrieves an animation channel contained by this animation entity.
|
||||
@param index The index of the channel.
|
||||
@return The channel at the given index. This pointer will be NULL
|
||||
if the index is out-of-bounds. */
|
||||
FCDAnimationChannel* GetChannel(size_t index) { FUAssert(index < GetChannelCount(), return NULL); return channels.at(index); }
|
||||
const FCDAnimationChannel* GetChannel(size_t index) const { FUAssert(index < GetChannelCount(), return NULL); return channels.at(index); } /**< See above. */
|
||||
|
||||
/** Adds a new animation channel to this animation entity.
|
||||
@return The new animation channel. */
|
||||
FCDAnimationChannel* AddChannel();
|
||||
|
||||
/** Releases an animation channel contained within this animation entity.
|
||||
@param channel The animation channel to release. */
|
||||
void ReleaseChannel(FCDAnimationChannel* channel);
|
||||
|
||||
/** Retrieves all the curves created in the subtree of this animation element.
|
||||
@param curves A list of animation curves to fill in.
|
||||
This list is not cleared. */
|
||||
void GetCurves(FCDAnimationCurveList& curves);
|
||||
|
||||
/** [INTERNAL] Links the animation sub-tree with the other entities within the document.
|
||||
This function is used at the end of the import of a document to verify that all the
|
||||
necessary drivers were found.
|
||||
@return The status of the linkage. */
|
||||
FUStatus Link();
|
||||
|
||||
/** [INTERNAL] Reads in the animation entity from a given COLLADA XML tree node.
|
||||
@param animationNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the animation. */
|
||||
virtual FUStatus LoadFromXML(xmlNode* animationNode);
|
||||
|
||||
/** [INTERNAL] Writes out the \<animation\> element to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the animation tree.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
|
||||
/** [INTERNAL] Retrieves the child source or sampler.
|
||||
This function should only be used by the FCDAnimationChannel class
|
||||
during the import of a COLLADA document.
|
||||
@param id The COLLADA id of a sampler or a source.
|
||||
@return The XML node tree for the sampler or the source. This pointer
|
||||
will be NULL if there are no child nodes for the given id. */
|
||||
xmlNode* FindChildById(const string& id);
|
||||
|
||||
/** [INTERNAL] Links a possible driver with the animation curves contained
|
||||
within the subtree of this animation element.
|
||||
This function is used during the import of a COLLADA document.
|
||||
@param animated The driver animated value.
|
||||
@return Whether any linkage was done. */
|
||||
bool LinkDriver(FCDAnimated* animated);
|
||||
};
|
||||
|
||||
#endif // _FCD_ANIMATION_H_
|
||||
292
Extras/FCollada/FCDocument/FCDAnimationChannel.cpp
Normal file
292
Extras/FCollada/FCDocument/FCDAnimationChannel.cpp
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDAnimated.h"
|
||||
#include "FCDocument/FCDAnimation.h"
|
||||
#include "FCDocument/FCDAnimationChannel.h"
|
||||
#include "FCDocument/FCDAnimationCurve.h"
|
||||
#include "FCDocument/FCDAnimationMultiCurve.h"
|
||||
#include "FUtils/FUDaeEnum.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
#include "FUtils/FUStringConversion.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDAnimationChannel::FCDAnimationChannel(FCDocument* document, FCDAnimation* _parent) : FCDObject(document, "FCDAnimationChannel")
|
||||
{
|
||||
parent = _parent;
|
||||
}
|
||||
|
||||
FCDAnimationChannel::~FCDAnimationChannel()
|
||||
{
|
||||
CLEAR_POINTER_VECTOR(curves);
|
||||
parent = NULL;
|
||||
}
|
||||
|
||||
FCDAnimationCurve* FCDAnimationChannel::AddCurve()
|
||||
{
|
||||
FCDAnimationCurve* curve = new FCDAnimationCurve(GetDocument(), this);
|
||||
curves.push_back(curve);
|
||||
return curve;
|
||||
}
|
||||
|
||||
void FCDAnimationChannel::ReleaseCurve(FCDAnimationCurve* curve)
|
||||
{
|
||||
FCDAnimationCurveList::iterator itC = std::find(curves.begin(), curves.end(), curve);
|
||||
if (itC != curves.end())
|
||||
{
|
||||
// TODO: IMPLEMENT THIS. NEED RTTI and memory management. In other words, I need time!!! :(.
|
||||
// delete *itC;
|
||||
curves.erase(itC);
|
||||
}
|
||||
}
|
||||
|
||||
// Consider this animated as the curve's driver
|
||||
bool FCDAnimationChannel::LinkDriver(FCDAnimated* animated)
|
||||
{
|
||||
bool driver = !driverPointer.empty();
|
||||
driver = driver && animated->GetTargetPointer() == driverPointer;
|
||||
if (driver && driverQualifier >= 0 && (uint32) driverQualifier < animated->GetValueCount())
|
||||
{
|
||||
// Retrieve the value pointer for the driver
|
||||
for (FCDAnimationCurveList::iterator itC = curves.begin(); itC != curves.end(); ++itC)
|
||||
{
|
||||
(*itC)->SetDriver(animated->GetValue((uint32) driverQualifier));
|
||||
}
|
||||
}
|
||||
return driver;
|
||||
}
|
||||
FUStatus FCDAnimationChannel::CheckDriver()
|
||||
{
|
||||
FUStatus status;
|
||||
if (!driverPointer.empty() && !curves.empty() && curves.front()->GetDriver() == NULL)
|
||||
{
|
||||
status.Fail(FS("Unable to find animation curve driver: ") + TO_FSTRING(driverPointer) + FS(" for animation: ") + TO_FSTRING(parent->GetDaeId()));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Load a Collada animation channel from the XML document
|
||||
FUStatus FCDAnimationChannel::LoadFromXML(xmlNode* channelNode)
|
||||
{
|
||||
FUStatus status;
|
||||
|
||||
// Read the channel-specific ID
|
||||
string daeId = ReadNodeId(channelNode);
|
||||
string samplerId = ReadNodeSource(channelNode);
|
||||
ReadNodeTargetProperty(channelNode, targetPointer, targetQualifier);
|
||||
|
||||
xmlNode* samplerNode = parent->FindChildById(samplerId);
|
||||
if (samplerNode == NULL || !IsEquivalent(samplerNode->name, DAE_SAMPLER_ELEMENT))
|
||||
{
|
||||
return status.Fail(FS("Unable to find sampler node for channel node: ") + TO_FSTRING(daeId), channelNode->line);
|
||||
}
|
||||
|
||||
// Find and process the sources
|
||||
xmlNode* inputSource = NULL,* outputSource = NULL,* inTangentSource = NULL,* outTangentSource = NULL;
|
||||
xmlNode* outTangentWeightSource = NULL,* inTangentWeightSource = NULL,* interpolationSource = NULL;
|
||||
xmlNodeList samplerInputNodes;
|
||||
FindChildrenByType(samplerNode, DAE_INPUT_ELEMENT, samplerInputNodes);
|
||||
for (size_t i = 0; i < samplerInputNodes.size(); ++i) // Don't use iterator here because we are possibly appending source nodes in the loop
|
||||
{
|
||||
xmlNode* inputNode = samplerInputNodes[i];
|
||||
string sourceId = ReadNodeSource(inputNode);
|
||||
xmlNode* sourceNode = parent->FindChildById(sourceId);
|
||||
string sourceSemantic = ReadNodeSemantic(inputNode);
|
||||
|
||||
if (sourceSemantic == DAE_INPUT_ANIMATION_INPUT) inputSource = sourceNode;
|
||||
else if (sourceSemantic == DAE_OUTPUT_ANIMATION_INPUT) outputSource = sourceNode;
|
||||
else if (sourceSemantic == DAE_INTANGENT_ANIMATION_INPUT) inTangentSource = sourceNode;
|
||||
else if (sourceSemantic == DAE_OUTTANGENT_ANIMATION_INPUT) outTangentSource = sourceNode;
|
||||
else if (sourceSemantic == DAEMAYA_INTANGENTWEIGHT_ANIMATION_INPUT) inTangentWeightSource = sourceNode;
|
||||
else if (sourceSemantic == DAEMAYA_OUTTANGENTWEIGHT_ANIMATION_INPUT) outTangentWeightSource = sourceNode;
|
||||
else if (sourceSemantic == DAE_INTERPOLATION_ANIMATION_INPUT) interpolationSource = sourceNode;
|
||||
}
|
||||
if (inputSource == NULL || outputSource == NULL)
|
||||
{
|
||||
return status.Fail(FS("Missing INPUT or OUTPUT sources in animation channel: ") + TO_FSTRING(parent->GetDaeId()), samplerNode->line);
|
||||
}
|
||||
|
||||
// Calculate the number of curves that in contained by this channel
|
||||
xmlNode* outputAccessor = FindTechniqueAccessor(outputSource);
|
||||
string accessorStrideString = ReadNodeProperty(outputAccessor, DAE_STRIDE_ATTRIBUTE);
|
||||
uint32 curveCount = FUStringConversion::ToUInt32(accessorStrideString);
|
||||
if (curveCount == 0) curveCount = 1;
|
||||
|
||||
// Create the animation curves
|
||||
curves.reserve(curveCount);
|
||||
for (uint32 i = 0; i < curveCount; ++i) AddCurve();
|
||||
|
||||
// Read in the animation curves
|
||||
// The input keys are shared by all the curves
|
||||
ReadSource(inputSource, curves.front()->GetKeys());
|
||||
for (uint32 i = 1; i < curveCount; ++i) curves[i]->GetKeys() = curves.front()->GetKeys();
|
||||
|
||||
// Read in the interleaved outputs and tangents as floats
|
||||
#define READ_SOURCE_INTERLEAVED(sourceNode, curveArrayPtr) \
|
||||
if (sourceNode != NULL) { \
|
||||
vector<FloatList*> arrays(curveCount); \
|
||||
for (uint32 i = 0; i < curveCount; ++i) { \
|
||||
arrays[i] = &(curves[i]->curveArrayPtr()); } \
|
||||
ReadSourceInterleaved(sourceNode, arrays); \
|
||||
}
|
||||
|
||||
READ_SOURCE_INTERLEAVED(outputSource, GetKeyValues)
|
||||
READ_SOURCE_INTERLEAVED(inTangentSource, GetInTangents)
|
||||
READ_SOURCE_INTERLEAVED(outTangentSource, GetOutTangents)
|
||||
READ_SOURCE_INTERLEAVED(inTangentWeightSource, GetInTangentWeights)
|
||||
READ_SOURCE_INTERLEAVED(outTangentWeightSource, GetOutTangentWeights)
|
||||
#undef READ_SOURCE_INTERLEAVED
|
||||
|
||||
// Read in the interleaved interpolation values, parsing the tokens directly
|
||||
if (interpolationSource != NULL)
|
||||
{
|
||||
vector<UInt32List*> arrays(curveCount);
|
||||
for (uint32 i = 0; i < curveCount; ++i) arrays[i] = &(curves[i]->GetInterpolations());
|
||||
ReadSourceInterpolationInterleaved(interpolationSource, arrays);
|
||||
}
|
||||
|
||||
// Read in the pre/post-infinity type
|
||||
xmlNodeList mayaParameterNodes; StringList mayaParameterNames;
|
||||
xmlNode* mayaTechnique = FindTechnique(inputSource, DAEMAYA_MAYA_PROFILE);
|
||||
FindParameters(mayaTechnique, mayaParameterNames, mayaParameterNodes);
|
||||
size_t parameterCount = mayaParameterNodes.size();
|
||||
for (size_t i = 0; i < parameterCount; ++i)
|
||||
{
|
||||
xmlNode* parameterNode = mayaParameterNodes[i];
|
||||
const string& paramName = mayaParameterNames[i];
|
||||
const char* content = ReadNodeContentDirect(parameterNode);
|
||||
|
||||
if (paramName == DAEMAYA_PREINFINITY_PARAMETER || paramName == DAEMAYA_PREINFINITY_PARAMETER1_3)
|
||||
{
|
||||
for (FCDAnimationCurveList::iterator itC = curves.begin(); itC != curves.end(); ++itC)
|
||||
{
|
||||
(*itC)->SetPreInfinity(FUDaeInfinity::FromString(content));
|
||||
}
|
||||
}
|
||||
else if (paramName == DAEMAYA_POSTINFINITY_PARAMETER || paramName == DAEMAYA_POSTINFINITY_PARAMETER1_3)
|
||||
{
|
||||
for (FCDAnimationCurveList::iterator itC = curves.begin(); itC != curves.end(); ++itC)
|
||||
{
|
||||
(*itC)->SetPostInfinity(FUDaeInfinity::FromString(content));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Look for driven-key input target
|
||||
if (paramName == DAE_INPUT_ELEMENT)
|
||||
{
|
||||
string semantic = ReadNodeSemantic(parameterNode);
|
||||
if (semantic == DAEMAYA_DRIVER_INPUT)
|
||||
{
|
||||
string fullDriverTarget = ReadNodeSource(parameterNode);
|
||||
const char* driverTarget = FUDaeParser::SkipPound(fullDriverTarget);
|
||||
if (driverTarget != NULL)
|
||||
{
|
||||
string driverQualifierValue;
|
||||
FUDaeParser::SplitTarget(driverTarget, driverPointer, driverQualifierValue);
|
||||
driverQualifier = FUDaeParser::ReadTargetMatrixElement(driverQualifierValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ready the curves for usage/evaluation.
|
||||
for (uint32 i = 0; i < curveCount; ++i) curves[i]->Ready();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Write out the animation curves for an animation channel to a COLLADA document
|
||||
void FCDAnimationChannel::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
string baseId = CleanId(targetPointer);
|
||||
|
||||
// Check for curve merging
|
||||
uint32 realCurveCount = 0;
|
||||
FCDAnimationCurve* masterCurve = NULL;
|
||||
bool mergeCurves = true;
|
||||
for (FCDAnimationCurveList::const_iterator itC = curves.begin(); itC != curves.end(); ++itC)
|
||||
{
|
||||
FCDAnimationCurve* curve = (*itC);
|
||||
if ((*itC) != NULL)
|
||||
{
|
||||
++realCurveCount;
|
||||
if (masterCurve == NULL)
|
||||
{
|
||||
masterCurve = curve;
|
||||
if (masterCurve->GetDriver() != NULL) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check preliminary information, before verifying the individual keys: key count, infinity types and such..
|
||||
const FloatList& masterKeys = masterCurve->GetKeys();
|
||||
const FloatList& curveKeys = curve->GetKeys();
|
||||
size_t keyCount = masterKeys.size();
|
||||
mergeCurves &= curveKeys.size() == keyCount && curve->GetPostInfinity() == masterCurve->GetPostInfinity() && curve->GetPreInfinity() == masterCurve->GetPreInfinity();
|
||||
for (size_t k = 0; k < keyCount && mergeCurves; ++k)
|
||||
{
|
||||
mergeCurves = curveKeys[k] == masterKeys[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mergeCurves && realCurveCount > 1)
|
||||
{
|
||||
// HACK: Will need to merge the channel and animated classes.
|
||||
FloatList defaultValues(curves.size(), 0.0f);
|
||||
|
||||
// Merge and export the curves
|
||||
FCDAnimationMultiCurve* multiCurve = FCDAnimationMultiCurve::MergeCurves(curves, defaultValues);
|
||||
multiCurve->WriteSourceToXML(parentNode, baseId);
|
||||
multiCurve->WriteSamplerToXML(parentNode, baseId);
|
||||
multiCurve->WriteChannelToXML(parentNode, baseId, targetPointer);
|
||||
SAFE_DELETE(multiCurve);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Interlace the curve's sources, samplers and channels
|
||||
// Generate new ids for each of the curve's data sources, to avoid collision in special cases
|
||||
size_t curveCount = curves.size();
|
||||
StringList ids; ids.resize(curves.size());
|
||||
FUSStringBuilder curveId;
|
||||
for (size_t c = 0; c < curveCount; ++c)
|
||||
{
|
||||
if (curves[c] != NULL)
|
||||
{
|
||||
// Generate a valid id for this curve
|
||||
curveId.set(baseId);
|
||||
if (curves[c]->GetTargetElement() >= 0)
|
||||
{
|
||||
curveId.append('_'); curveId.append(curves[c]->GetTargetElement()); curveId.append('_');
|
||||
}
|
||||
curveId.append(curves[c]->GetTargetQualifier());
|
||||
ids[c] = CleanId(curveId.ToCharPtr());
|
||||
|
||||
// Write out the curve's sources
|
||||
curves[c]->WriteSourceToXML(parentNode, ids[c]);
|
||||
}
|
||||
}
|
||||
for (size_t c = 0; c < curveCount; ++c)
|
||||
{
|
||||
if (curves[c] != NULL) curves[c]->WriteSamplerToXML(parentNode, ids[c]);
|
||||
}
|
||||
for (size_t c = 0; c < curveCount; ++c)
|
||||
{
|
||||
if (curves[c] != NULL) curves[c]->WriteChannelToXML(parentNode, ids[c], targetPointer.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
134
Extras/FCollada/FCDocument/FCDAnimationChannel.h
Normal file
134
Extras/FCollada/FCDocument/FCDAnimationChannel.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDAnimationChannel.h
|
||||
This file contains the FCDAnimationChannel class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_ANIMATION_CHANNEL_H_
|
||||
#define _FCD_ANIMATION_CHANNEL_H_
|
||||
|
||||
#include "FCDocument/FCDObject.h"
|
||||
|
||||
class FCDocument;
|
||||
class FCDAnimated;
|
||||
class FCDAnimation;
|
||||
class FCDAnimationCurve;
|
||||
|
||||
/** A dynamically-sized array of animation curves. */
|
||||
typedef vector<FCDAnimationCurve*> FCDAnimationCurveList;
|
||||
|
||||
/**
|
||||
A COLLADA animation channel.
|
||||
Each animation channel holds the animation curves for one animatable element,
|
||||
such as a single floating-point value, a 3D vector or a matrix.
|
||||
|
||||
@see FCDAnimated
|
||||
@ingroup FCDocument
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDAnimationChannel : public FCDObject
|
||||
{
|
||||
private:
|
||||
FCDAnimation* parent;
|
||||
|
||||
// Channel target
|
||||
string targetPointer;
|
||||
string targetQualifier;
|
||||
|
||||
// Maya-specific: the driver for this/these curves
|
||||
string driverPointer;
|
||||
int32 driverQualifier;
|
||||
|
||||
FCDAnimationCurveList curves;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, call the FCDAnimation::AddChannel function.
|
||||
@param document The COLLADA document that owns the animation channel.
|
||||
@param parent The animation sub-tree that contains the animation channel. */
|
||||
FCDAnimationChannel(FCDocument* document, FCDAnimation* parent);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, call the FCDAnimation::ReleaseChannel function. */
|
||||
virtual ~FCDAnimationChannel();
|
||||
|
||||
/** Retrieves the animation sub-tree that contains the animation channel.
|
||||
@return The parent animation sub-tree. */
|
||||
FCDAnimation* GetParent() { return parent; }
|
||||
const FCDAnimation* GetParent() const { return parent; } /**< See above. */
|
||||
|
||||
/** Retrieves the list of animation curves contained within the channel.
|
||||
@return The list of animation curves. */
|
||||
const FCDAnimationCurveList& GetCurves() const { return curves; }
|
||||
|
||||
/** Retrieves the number of animation curves contained within the channel.
|
||||
@return The number of animation curves. */
|
||||
size_t GetCurveCount() const { return curves.size(); }
|
||||
|
||||
/** Retrieves an animation curve contained within the channel.
|
||||
@param index The index of the animation curve.
|
||||
@return The animation curve at the given index. This pointer will be NULL
|
||||
if the index is out-of-bounds. */
|
||||
FCDAnimationCurve* GetCurve(size_t index) { FUAssert(index < GetCurveCount(), return NULL); return curves.at(index); }
|
||||
const FCDAnimationCurve* GetCurve(size_t index) const { FUAssert(index < GetCurveCount(), return NULL); return curves.at(index); } /**< See above. */
|
||||
|
||||
/** Adds a new animation curve to this animation channel.
|
||||
@return The new animation curve. */
|
||||
FCDAnimationCurve* AddCurve();
|
||||
|
||||
/** Releases an animation curve contained within this channel.
|
||||
@todo This function is not yet implemented, as it requires
|
||||
a lot more memory management than FCollada currently does.
|
||||
@param curve The animation curve to release. */
|
||||
void ReleaseCurve(FCDAnimationCurve* curve);
|
||||
|
||||
/** [INTERNAL] Retrieves the target pointer prefix for this animation channel.
|
||||
This function is used during the import of a COLLADA document to match the
|
||||
target pointer prefixes with the animated elements.
|
||||
@return The target pointer prefix. */
|
||||
const string& GetTargetPointer() const { return targetPointer; }
|
||||
|
||||
/** [INTERNAL] Retrieves the target qualifier for this animation channel.
|
||||
This function is used during the import of a COLLADA document.
|
||||
Where there is a target qualifier, there should be only one curve contained by the channel.
|
||||
@return The target qualifier. This value may be the empty string if the channel
|
||||
targets all the values targeted by the target pointer prefix. */
|
||||
const string& GetTargetQualifier() const { return targetQualifier; }
|
||||
|
||||
/** [INTERNAL] Enforces the tarrget pointer prefix for the animation channel.
|
||||
This function is used during the export of a COLLADA document.
|
||||
@param p The new target pointer prefix. */
|
||||
void SetTargetPointer(const string& p) { targetPointer = p; }
|
||||
|
||||
/** [INTERNAL] Considers the given animated element as the driver for this animation channel.
|
||||
@param animated An animated element.
|
||||
@return Whether the animated element is in fact the driver for the animation channel. */
|
||||
bool LinkDriver(FCDAnimated* animated);
|
||||
|
||||
/** [INTERNAL] Verifies that if a driver is used by this channel, then it was found during
|
||||
the import of the animated elements.
|
||||
@return The status of the verification. */
|
||||
FUStatus CheckDriver();
|
||||
|
||||
/** [INTERNAL] Reads in the animation channel from a given COLLADA XML tree node.
|
||||
@param channelNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the animation channel. */
|
||||
FUStatus LoadFromXML(xmlNode* channelNode);
|
||||
|
||||
/** [INTERNAL] Writes out the animation channel to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the animation channel.
|
||||
@return The created element XML tree node. */
|
||||
void WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
#endif // _FCD_ANIMATION_CHANNEL_H_
|
||||
139
Extras/FCollada/FCDocument/FCDAnimationClip.cpp
Normal file
139
Extras/FCollada/FCDocument/FCDAnimationClip.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDAnimation.h"
|
||||
#include "FCDocument/FCDAnimationChannel.h"
|
||||
#include "FCDocument/FCDAnimationClip.h"
|
||||
#include "FCDocument/FCDAnimationCurve.h"
|
||||
#include "FCDocument/FCDAnimated.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDAnimationClip::FCDAnimationClip(FCDocument* document) : FCDEntity(document, "AnimationClip")
|
||||
{
|
||||
start = end = 0.0f;
|
||||
}
|
||||
|
||||
FCDAnimationClip::~FCDAnimationClip()
|
||||
{
|
||||
curves.clear();
|
||||
}
|
||||
|
||||
FCDAnimationClip* FCDAnimationClip::Clone()
|
||||
{
|
||||
FCDAnimationClip* clone = new FCDAnimationClip(GetDocument());
|
||||
FCDEntity::Clone(clone);
|
||||
|
||||
for(FCDAnimationCurveList::iterator it = curves.begin(); it != curves.end(); ++it)
|
||||
{
|
||||
curves.push_back((*it)->Clone());
|
||||
}
|
||||
|
||||
clone->start = start;
|
||||
clone->end = end;
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
FUStatus FCDAnimationClip::LoadFromXML(xmlNode* clipNode)
|
||||
{
|
||||
FUStatus status = FCDEntity::LoadFromXML(clipNode);
|
||||
if (!status) return status;
|
||||
if (!IsEquivalent(clipNode->name, DAE_ANIMCLIP_ELEMENT))
|
||||
{
|
||||
return status.Warning(FS("Unknown element in animation clip library."), clipNode->line);
|
||||
}
|
||||
|
||||
// Read in and verify the clip's time/input bounds
|
||||
start = FUStringConversion::ToFloat(ReadNodeProperty(clipNode, DAE_START_ATTRIBUTE));
|
||||
end = FUStringConversion::ToFloat(ReadNodeProperty(clipNode, DAE_END_ATTRIBUTE));
|
||||
if (end - start < FLT_TOLERANCE)
|
||||
{
|
||||
status.Warning(FS("Invalid start/end pair for animation clip: ") + TO_FSTRING(GetDaeId()), clipNode->line);
|
||||
}
|
||||
|
||||
// Read in the <input> elements and segment the corresponding animation curves
|
||||
xmlNodeList inputNodes;
|
||||
FindChildrenByType(clipNode, DAE_INSTANCE_ANIMATION_ELEMENT, inputNodes);
|
||||
for (xmlNodeList::iterator itI = inputNodes.begin(); itI != inputNodes.end(); ++itI)
|
||||
{
|
||||
xmlNode* inputNode = (*itI);
|
||||
|
||||
// Retrieve the animation for this input
|
||||
FUUri animationId = ReadNodeUrl(inputNode);
|
||||
if (animationId.suffix.empty() || !animationId.prefix.empty())
|
||||
{
|
||||
return status.Fail(FS("Invalid animation instantiation for animation clip: ") + TO_FSTRING(GetDaeId()), inputNode->line);
|
||||
}
|
||||
FCDAnimation* animation = GetDocument()->FindAnimation(animationId.suffix);
|
||||
if (animation == NULL) continue;
|
||||
|
||||
// Retrieve all the curves created under this animation node
|
||||
FCDAnimationCurveList animationCurves;
|
||||
animation->GetCurves(animationCurves);
|
||||
if (animationCurves.empty())
|
||||
{
|
||||
status.Warning(FS("No curves instantiated by animation '") + TO_FSTRING(animationId.suffix) + FS("' for animation clip: ") + TO_FSTRING(GetDaeId()), inputNode->line);
|
||||
}
|
||||
|
||||
for (FCDAnimationCurveList::iterator itC = animationCurves.begin(); itC != animationCurves.end(); ++itC)
|
||||
{
|
||||
// Keep only newly listed curves
|
||||
FCDAnimationCurve* curve = *itC;
|
||||
FCDAnimationCurveList::iterator itF = std::find(curves.begin(), curves.end(), curve);
|
||||
if (itF == curves.end()) continue;
|
||||
|
||||
curve->RegisterAnimationClip(this);
|
||||
curves.push_back(curve);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for an empty clip
|
||||
if (curves.empty())
|
||||
{
|
||||
status.Warning(FS("Empty animation clip :") + TO_FSTRING(GetDaeId()), clipNode->line);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Write out the COLLADA animations to the document
|
||||
xmlNode* FCDAnimationClip::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
// Create the <clip> element and write out its start/end information.
|
||||
xmlNode* clipNode = FCDEntity::WriteToEntityXML(parentNode, DAE_ANIMCLIP_ELEMENT);
|
||||
AddAttribute(clipNode, DAE_START_ATTRIBUTE, start);
|
||||
AddAttribute(clipNode, DAE_END_ATTRIBUTE, end);
|
||||
|
||||
// Build a list of the animations to instantiate
|
||||
// from the list of curves for this clip
|
||||
typedef vector<const FCDAnimation*> FCDAnimationConstList;
|
||||
FCDAnimationConstList animations;
|
||||
for (FCDAnimationCurveList::const_iterator itC = curves.begin(); itC != curves.end(); ++itC)
|
||||
{
|
||||
const FCDAnimationChannel* channel = (*itC)->GetParent();
|
||||
if (channel == NULL) continue;
|
||||
const FCDAnimation* animation = channel->GetParent();
|
||||
if (std::find(animations.begin(), animations.end(), animation) == animations.end())
|
||||
{
|
||||
animations.push_back(animation);
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate all the animations
|
||||
for (FCDAnimationConstList::iterator itA = animations.begin(); itA != animations.end(); ++itA)
|
||||
{
|
||||
xmlNode* instanceNode = AddChild(clipNode, DAE_INSTANCE_ANIMATION_ELEMENT);
|
||||
AddAttribute(instanceNode, DAE_URL_ATTRIBUTE, string("#") + (*itA)->GetDaeId());
|
||||
}
|
||||
|
||||
FCDEntity::WriteToExtraXML(clipNode);
|
||||
return clipNode;
|
||||
}
|
||||
|
||||
46
Extras/FCollada/FCDocument/FCDAnimationClip.h
Normal file
46
Extras/FCollada/FCDocument/FCDAnimationClip.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#ifndef _FCD_ANIMATION_CLIP_H_
|
||||
#define _FCD_ANIMATION_CLIP_H_
|
||||
|
||||
class FCDocument;
|
||||
class FCDAnimationCurve;
|
||||
|
||||
typedef vector<FCDAnimationCurve*> FCDAnimationCurveList;
|
||||
|
||||
#include "FCDocument/FCDEntity.h"
|
||||
#include "FCDocument/FCDObject.h"
|
||||
|
||||
class FCOLLADA_EXPORT FCDAnimationClip : public FCDEntity
|
||||
{
|
||||
private:
|
||||
FCDAnimationCurveList curves;
|
||||
float start, end;
|
||||
|
||||
public:
|
||||
FCDAnimationClip(FCDocument* document);
|
||||
virtual ~FCDAnimationClip();
|
||||
|
||||
FCDAnimationClip* Clone();
|
||||
|
||||
// FCDEntity overrides
|
||||
virtual Type GetType() const { return ANIMATION_CLIP; }
|
||||
|
||||
// Accessors
|
||||
FCDAnimationCurveList& GetClipCurves() { return curves; }
|
||||
const FCDAnimationCurveList& GetClipCurves() const { return curves; }
|
||||
float GetStart() const { return start; }
|
||||
float GetEnd() const { return end; }
|
||||
|
||||
// Load a Collada animation node from the XML document
|
||||
virtual FUStatus LoadFromXML(xmlNode* clipNode);
|
||||
|
||||
// Write out the COLLADA animations to the document
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
#endif // _FCD_ANIMATION_CLIP_H_
|
||||
|
||||
295
Extras/FCollada/FCDocument/FCDAnimationCurve.cpp
Normal file
295
Extras/FCollada/FCDocument/FCDAnimationCurve.cpp
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDAnimationCurve.h"
|
||||
#include "FCDocument/FCDAnimationClip.h"
|
||||
#include "FUtils/FUDaeEnum.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDAnimationCurve::FCDAnimationCurve(FCDocument* document, FCDAnimationChannel* _parent)
|
||||
: FCDObject(document, "FCDAnimationCurve"),
|
||||
parent(_parent),
|
||||
targetElement(-1),
|
||||
preInfinity(FUDaeInfinity::CONSTANT),
|
||||
postInfinity(FUDaeInfinity::CONSTANT),
|
||||
inputDriver(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
FCDAnimationCurve::~FCDAnimationCurve()
|
||||
{
|
||||
inputDriver = NULL;
|
||||
parent = NULL;
|
||||
clips.clear();
|
||||
}
|
||||
|
||||
FCDAnimationCurve* FCDAnimationCurve::Clone()
|
||||
{
|
||||
FCDAnimationCurve* clone = new FCDAnimationCurve(GetDocument(), parent);
|
||||
|
||||
clone->SetTargetElement(targetElement);
|
||||
string q;
|
||||
q.assign(targetQualifier);
|
||||
clone->SetTargetQualifier(q);
|
||||
|
||||
clone->keys = keys;
|
||||
clone->keyValues = keyValues;
|
||||
clone->inTangents = inTangents;
|
||||
clone->outTangents = outTangents;
|
||||
clone->inTangentWeights = inTangentWeights;
|
||||
clone->outTangentWeights = outTangentWeights;
|
||||
clone->isWeightedCurve = isWeightedCurve;
|
||||
clone->preInfinity = preInfinity;
|
||||
clone->postInfinity = postInfinity;
|
||||
|
||||
clone->inputDriver = inputDriver;
|
||||
|
||||
clone->SetDriverPointer(driverPointer);
|
||||
|
||||
clone->interpolations = interpolations;
|
||||
|
||||
// Animation clips that depend on this curve
|
||||
for(FCDAnimationClipList::iterator it = clips.begin(); it != clips.end(); ++it)
|
||||
{
|
||||
clone->clips.push_back((*it)->Clone());
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Prepare a curve for evaluation
|
||||
void FCDAnimationCurve::Ready()
|
||||
{
|
||||
if (keys.empty()) return;
|
||||
|
||||
if (inTangents.empty() || outTangents.empty())
|
||||
{
|
||||
// Calculate the bezier tangents
|
||||
inTangents.resize(keys.size(), 0.0f);
|
||||
outTangents.resize(keys.size(), 0.0f);
|
||||
|
||||
if (keys.size() > 1)
|
||||
{
|
||||
for (size_t i = 0; i < keys.size(); ++i)
|
||||
{
|
||||
float previousKeySpan = (i > 0) ? keys[i] - keys[i - 1] : keys[i + 1] - keys[i];
|
||||
float nextKeySpan = (i < keys.size() - 1) ? keys[i + 1] - keys[i] : previousKeySpan;
|
||||
float currentKeyValue = keyValues[i];
|
||||
float previousKeyValue = (i > 0) ? keyValues[i - 1] : currentKeyValue;
|
||||
float nextKeyValue = (i < keys.size() - 1) ? keyValues[i + 1] : currentKeyValue;
|
||||
float slope = (nextKeyValue - previousKeyValue) / (nextKeySpan + previousKeySpan);
|
||||
inTangents[i] = previousKeySpan / 3.0f * slope;
|
||||
outTangents[i] = nextKeySpan / 3.0f * slope;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interpolations.empty())
|
||||
{
|
||||
// Fill in the array with the default interpolation type
|
||||
interpolations.resize(keys.size(), FUDaeInterpolation::DEFAULT);
|
||||
}
|
||||
|
||||
isWeightedCurve = !inTangentWeights.empty() && !outTangentWeights.empty();
|
||||
}
|
||||
|
||||
// Main workhorse for the animation system:
|
||||
// Evaluates the curve for a given input
|
||||
float FCDAnimationCurve::Evaluate(float input) const
|
||||
{
|
||||
if (keys.size() == 1) return keyValues.front();
|
||||
|
||||
float outputStart = keyValues.front();
|
||||
float outputEnd = keyValues.back();
|
||||
float inputStart = keys.front();
|
||||
float inputEnd = keys.back();
|
||||
float inputSpan = inputEnd - inputStart;
|
||||
|
||||
// Account for pre-infinity mode
|
||||
float outputOffset = 0.0f;
|
||||
if (input <= inputStart)
|
||||
{
|
||||
switch (preInfinity)
|
||||
{
|
||||
case FUDaeInfinity::CONSTANT: return outputStart;
|
||||
case FUDaeInfinity::LINEAR: return outputStart + (input - inputStart) * (keyValues[1] - outputStart) / (keys[1] - inputStart);
|
||||
case FUDaeInfinity::CYCLE: { float cycleCount = ceilf((inputStart - input) / inputSpan); input += cycleCount * inputSpan; break; }
|
||||
case FUDaeInfinity::CYCLE_RELATIVE: { float cycleCount = ceilf((inputStart - input) / inputSpan); input += cycleCount * inputSpan; outputOffset -= cycleCount * (outputEnd - outputStart); break; }
|
||||
case FUDaeInfinity::OSCILLATE: { float cycleCount = ceilf((inputStart - input) / (2.0f * inputSpan)); input += cycleCount * 2.0f * inputSpan; input = inputEnd - fabsf(input - inputEnd); break; }
|
||||
case FUDaeInfinity::UNKNOWN: default: return outputStart;
|
||||
}
|
||||
}
|
||||
|
||||
// Account for post-infinity mode
|
||||
else if (input >= inputEnd)
|
||||
{
|
||||
switch (postInfinity)
|
||||
{
|
||||
case FUDaeInfinity::CONSTANT: return outputEnd;
|
||||
case FUDaeInfinity::LINEAR: return outputEnd + (input - inputEnd) * (keyValues[keys.size() - 2] - outputEnd) / (keys[keys.size() - 2] - inputEnd);
|
||||
case FUDaeInfinity::CYCLE: { float cycleCount = ceilf((input - inputEnd) / inputSpan); input -= cycleCount * inputSpan; break; }
|
||||
case FUDaeInfinity::CYCLE_RELATIVE: { float cycleCount = ceilf((input - inputEnd) / inputSpan); input -= cycleCount * inputSpan; outputOffset += cycleCount * (outputEnd - outputStart); break; }
|
||||
case FUDaeInfinity::OSCILLATE: { float cycleCount = ceilf((input - inputEnd) / (2.0f * inputSpan)); input -= cycleCount * 2.0f * inputSpan; input = inputStart + fabsf(input - inputStart); break; }
|
||||
case FUDaeInfinity::UNKNOWN: default: return outputEnd;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the current interval
|
||||
uint32 index = 0;
|
||||
FloatList::const_iterator it;
|
||||
for (it = keys.begin(); it != keys.end(); ++it, ++index)
|
||||
{
|
||||
if ((*it) > input) break;
|
||||
}
|
||||
|
||||
// Get the keys and values for this interval
|
||||
float endKey = *it;
|
||||
float startKey = *(it - 1);
|
||||
float endValue = keyValues[index];
|
||||
float startValue = keyValues[index - 1];
|
||||
float output;
|
||||
|
||||
// Interpolate the output.
|
||||
// Similar code is found in FCDAnimationMultiCurve.cpp. If you update this, update the other one too.
|
||||
uint32 interpolation = interpolations.empty() ? ((uint32) FUDaeInterpolation::DEFAULT) : interpolations[index];
|
||||
switch (FUDaeInterpolation::Interpolation(interpolation))
|
||||
{
|
||||
case FUDaeInterpolation::LINEAR:
|
||||
output = (input - startKey) / (endKey - startKey) * (endValue - startValue) + startValue;
|
||||
break;
|
||||
|
||||
case FUDaeInterpolation::BEZIER: {
|
||||
float t = (input - startKey) / (endKey - startKey);
|
||||
float bValue = startValue + outTangents[index - 1];
|
||||
float cValue = endValue - inTangents[index];
|
||||
float ti = 1.0f - t;
|
||||
output = startValue * ti * ti * ti + 3.0f * bValue * ti * ti * t + 3.0f * cValue * ti * t * t + endValue * t * t * t;
|
||||
break; }
|
||||
|
||||
case FUDaeInterpolation::STEP:
|
||||
case FUDaeInterpolation::UNKNOWN:
|
||||
default:
|
||||
output = startValue;
|
||||
break;
|
||||
}
|
||||
|
||||
return outputOffset + output;
|
||||
}
|
||||
|
||||
// Apply a conversion function on the key values and tangents
|
||||
void FCDAnimationCurve::ConvertValues(FCDConversionFunction valueConversion, FCDConversionFunction tangentConversion)
|
||||
{
|
||||
size_t keyCount = keys.size();
|
||||
if (valueConversion != NULL)
|
||||
{
|
||||
for (size_t k = 0; k < keyCount; k++)
|
||||
{
|
||||
keyValues[k] = (*valueConversion)(keyValues[k]);
|
||||
}
|
||||
}
|
||||
if (tangentConversion != NULL)
|
||||
{
|
||||
for (size_t k = 0; k < keyCount; k++)
|
||||
{
|
||||
inTangents[k] = (*tangentConversion)(inTangents[k]);
|
||||
outTangents[k] = (*tangentConversion)(outTangents[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply a conversion function on the key times and tangent weights
|
||||
void FCDAnimationCurve::ConvertInputs(FCDConversionFunction timeConversion, FCDConversionFunction tangentWeightConversion)
|
||||
{
|
||||
size_t keyCount = keys.size();
|
||||
if (timeConversion != NULL)
|
||||
{
|
||||
for (size_t k = 0; k < keyCount; k++)
|
||||
{
|
||||
keys[k] = (*timeConversion)(keys[k]);
|
||||
}
|
||||
}
|
||||
if (tangentWeightConversion != NULL)
|
||||
{
|
||||
for (size_t k = 0; k < keyCount; k++)
|
||||
{
|
||||
inTangentWeights[k] = (*tangentWeightConversion)(inTangentWeights[k]);
|
||||
outTangentWeights[k] = (*tangentWeightConversion)(outTangentWeights[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the specific animation elements to the COLLADA xml tree node
|
||||
void FCDAnimationCurve::WriteSourceToXML(xmlNode* parentNode, const string& baseId) const
|
||||
{
|
||||
const char* parameter = targetQualifier.c_str();
|
||||
if (*parameter == '.') ++parameter;
|
||||
|
||||
xmlNode* sourceNode = AddSourceFloat(parentNode, baseId + "-input", keys, "TIME");
|
||||
AddSourceFloat(parentNode, baseId + "-output", keyValues, parameter);
|
||||
AddSourceFloat(parentNode, baseId + "-intangents", inTangents, parameter);
|
||||
AddSourceFloat(parentNode, baseId + "-outtangents", outTangents, parameter);
|
||||
if (isWeightedCurve && !inTangentWeights.empty())
|
||||
{
|
||||
AddSourceFloat(parentNode, baseId + "-intangents_weights", inTangents, parameter);
|
||||
AddSourceFloat(parentNode, baseId + "-outtangents_weights", outTangents, parameter);
|
||||
}
|
||||
AddSourceInterpolation(parentNode, baseId + "-interpolations", *(FUDaeInterpolationList*)&interpolations);
|
||||
|
||||
// Export the infinity parameters
|
||||
xmlNode* mayaTechnique = AddTechniqueChild(sourceNode, DAEMAYA_MAYA_PROFILE);
|
||||
string infinityType = FUDaeInfinity::ToString(preInfinity);
|
||||
AddChild(mayaTechnique, DAEMAYA_PREINFINITY_PARAMETER, infinityType);
|
||||
infinityType = FUDaeInfinity::ToString(postInfinity);
|
||||
AddChild(mayaTechnique, DAEMAYA_POSTINFINITY_PARAMETER, infinityType);
|
||||
}
|
||||
|
||||
xmlNode* FCDAnimationCurve::WriteSamplerToXML(xmlNode* parentNode, const string& baseId) const
|
||||
{
|
||||
xmlNode* samplerNode = AddChild(parentNode, DAE_SAMPLER_ELEMENT);
|
||||
AddAttribute(samplerNode, DAE_ID_ATTRIBUTE, baseId + "-sampler");
|
||||
|
||||
// Add the sampler inputs
|
||||
AddInput(samplerNode, baseId + "-input", DAE_INPUT_ANIMATION_INPUT);
|
||||
AddInput(samplerNode, baseId + "-output", DAE_OUTPUT_ANIMATION_INPUT);
|
||||
AddInput(samplerNode, baseId + "-intangents", DAE_INTANGENT_ANIMATION_INPUT);
|
||||
AddInput(samplerNode, baseId + "-outtangents", DAE_OUTTANGENT_ANIMATION_INPUT);
|
||||
if (isWeightedCurve && !inTangentWeights.empty())
|
||||
{
|
||||
AddInput(samplerNode, baseId + "-intangents_weights", DAEMAYA_INTANGENTWEIGHT_ANIMATION_INPUT);
|
||||
AddInput(samplerNode, baseId + "-outtangents_weights", DAEMAYA_OUTTANGENTWEIGHT_ANIMATION_INPUT);
|
||||
}
|
||||
AddInput(samplerNode, baseId + "-interpolations", DAE_INTERPOLATION_ANIMATION_INPUT);
|
||||
|
||||
// Add the driver input
|
||||
if (inputDriver != NULL)
|
||||
{
|
||||
AddInput(samplerNode, driverPointer, DAEMAYA_DRIVER_INPUT);
|
||||
}
|
||||
|
||||
return samplerNode;
|
||||
}
|
||||
|
||||
xmlNode* FCDAnimationCurve::WriteChannelToXML(xmlNode* parentNode, const string& baseId, const char* targetPointer) const
|
||||
{
|
||||
xmlNode* channelNode = AddChild(parentNode, DAE_CHANNEL_ELEMENT);
|
||||
AddAttribute(channelNode, DAE_SOURCE_ATTRIBUTE, baseId + "-sampler");
|
||||
|
||||
// Generate and export the channel target
|
||||
globalSBuilder.set(targetPointer);
|
||||
if (targetElement >= 0)
|
||||
{
|
||||
globalSBuilder.append('('); globalSBuilder.append(targetElement); globalSBuilder.append(')');
|
||||
}
|
||||
globalSBuilder.append(targetQualifier);
|
||||
AddAttribute(channelNode, DAE_TARGET_ATTRIBUTE, globalSBuilder);
|
||||
return channelNode;
|
||||
}
|
||||
262
Extras/FCollada/FCDocument/FCDAnimationCurve.h
Normal file
262
Extras/FCollada/FCDocument/FCDAnimationCurve.h
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDAnimationCurve.h
|
||||
This file contains the FCDAnimationCurve class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_ANIMATION_CURVE_H_
|
||||
#define _FCD_ANIMATION_CURVE_H_
|
||||
|
||||
#include "FUtils/FUDaeEnum.h"
|
||||
#include "FCDocument/FCDObject.h"
|
||||
|
||||
class FCDAnimationClip;
|
||||
class FCDAnimationChannel;
|
||||
|
||||
typedef vector<FCDAnimationClip*> FCDAnimationClipList; /**< A dynamically-sized array of animation clips. */
|
||||
typedef float (*FCDConversionFunction)(float v); /**< A simple conversion function. */
|
||||
|
||||
/**
|
||||
A COLLADA single-dimensional animation curve.
|
||||
An animation curve holds the keyframes necessary
|
||||
to animate an animatable floating-point value.
|
||||
|
||||
There are multiple interpolation mechanisms supported by COLLADA.
|
||||
FCollada supports the CONSTANT, LINEAR and BEZIER interpolations.
|
||||
|
||||
@see FUDaeInterpolation FUDaeInfinity
|
||||
@ingroup FCDocument
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDAnimationCurve : public FCDObject
|
||||
{
|
||||
private:
|
||||
FCDAnimationChannel* parent;
|
||||
|
||||
// Targeting information
|
||||
int32 targetElement;
|
||||
string targetQualifier;
|
||||
|
||||
// Input information
|
||||
FloatList keys, keyValues;
|
||||
FloatList inTangents, outTangents;
|
||||
FloatList inTangentWeights, outTangentWeights;
|
||||
bool isWeightedCurve;
|
||||
FUDaeInfinity::Infinity preInfinity;
|
||||
FUDaeInfinity::Infinity postInfinity;
|
||||
|
||||
// Driver information
|
||||
const float* inputDriver;
|
||||
string driverPointer;
|
||||
|
||||
// The interpolation values follow the FUDaeInterpolation enum (FUDaeEnum.h)
|
||||
UInt32List interpolations;
|
||||
|
||||
// Animation clips that depend on this curve
|
||||
FCDAnimationClipList clips;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDAnimationChannel::AddCurve function.
|
||||
You should also attach the new curve to an animated
|
||||
element using the FCDAnimated::SetCurve function.
|
||||
@param document The COLLADA document that owns the animation curve.
|
||||
@param parent The animation channel that contains the curve. */
|
||||
FCDAnimationCurve(FCDocument* document, FCDAnimationChannel* parent);
|
||||
|
||||
/** Destructor: do not release directly.
|
||||
Instead, use the FCDAnimationChannel::ReleaseCurve function. */
|
||||
virtual ~FCDAnimationCurve();
|
||||
|
||||
/** Retrieves the animation channel that contains this animation curve.
|
||||
@return The parent animation channel. */
|
||||
inline FCDAnimationChannel* GetParent() { return parent; }
|
||||
inline const FCDAnimationChannel* GetParent() const { return parent; } /**< See above. */
|
||||
|
||||
/** Retrieves the list of key inputs for the animation curve.
|
||||
@return The list of key inputs. */
|
||||
inline FloatList& GetKeys() { return keys; }
|
||||
inline const FloatList& GetKeys() const { return keys; } /**< See above. */
|
||||
|
||||
/** Retrieves the list of key outputs for the animation curve.
|
||||
@return The list of key outputs. */
|
||||
inline FloatList& GetKeyValues() { return keyValues; }
|
||||
inline const FloatList& GetKeyValues() const { return keyValues; } /**< See above. */
|
||||
|
||||
/** Retrieves the list of interpolation type for the segments of the animation curve.
|
||||
There is always one interpolation type for each key in the curve. The interpolation type
|
||||
of a segment of the curve is set at the key at which begins the segment.
|
||||
@see FUDaeInterpolation
|
||||
@return The list of interpolation types. */
|
||||
inline UInt32List& GetInterpolations() { return interpolations; }
|
||||
inline const UInt32List& GetInterpolations() const { return interpolations; } /**< See above. */
|
||||
|
||||
/** Retrieves the list of key in-tangent values for the animation curve.
|
||||
This list has data only for curves that include segments with the bezier interpolation.
|
||||
@return The list of in-tangent values. */
|
||||
inline FloatList& GetInTangents() { return inTangents; }
|
||||
inline const FloatList& GetInTangents() const { return inTangents; } /**< See above. */
|
||||
|
||||
/** Retrieves the list of key out-tangent values for the animation curve.
|
||||
This list has data only for curves that include segments with the bezier interpolation.
|
||||
@return The list of out-tangent values. */
|
||||
inline FloatList& GetOutTangents() { return outTangents; }
|
||||
inline const FloatList& GetOutTangents() const { return outTangents; } /**< See above. */
|
||||
|
||||
/** Retrieves the list of key in-tangent weights for the animation curve.
|
||||
This list has data only for curves that are weighted
|
||||
and include segments with the bezier interpolation.
|
||||
@see IsWeightedCurve
|
||||
@return The list of in-tangent weights. */
|
||||
inline FloatList& GetInTangentWeights() { return inTangentWeights; }
|
||||
inline const FloatList& GetInTangentWeights() const { return inTangentWeights; } /**< See above. */
|
||||
|
||||
/** Retrieves the list of key out-tangent weights for the animation curve.
|
||||
This list has data only for curves that are weighted
|
||||
and include segments with the bezier interpolation.
|
||||
@see IsWeightedCurve
|
||||
@return The list of out-tangent weights. */
|
||||
inline FloatList& GetOutTangentWeights() { return outTangentWeights; }
|
||||
inline const FloatList& GetOutTangentWeights() const { return outTangentWeights; } /**< See above. */
|
||||
|
||||
/** Retrieves whether this curve has weighted tangents. Tangent weights
|
||||
give you access to 2D tangents by providing the length of the tangent.
|
||||
@return Whether this curve has weighted tangents. */
|
||||
inline bool IsWeightedCurve() const { return isWeightedCurve; }
|
||||
|
||||
/** Sets whether this curve has weighted tangents. Tangent weights
|
||||
give you access to 2D tangents by providing the length of the tangent.
|
||||
@param _isWeightedCurve Whether this curve has weighted tangents. */
|
||||
inline void SetWeightedCurveFlag(bool _isWeightedCurve) { isWeightedCurve = _isWeightedCurve; }
|
||||
|
||||
/** Retrieves the type of behavior for the curve if the input value is
|
||||
outside the input interval defined by the curve keys and less than any key input value.
|
||||
@see FUDaeInfinity
|
||||
@return The pre-infinity behavior of the curve. */
|
||||
inline FUDaeInfinity::Infinity GetPreInfinity() const { return preInfinity; }
|
||||
|
||||
/** Sets the behavior of the curve if the input value is
|
||||
outside the input interval defined by the curve keys and less than any key input value.
|
||||
@see FUDaeInfinity
|
||||
@param infinity The pre-infinity behavior of the curve. */
|
||||
inline void SetPreInfinity(FUDaeInfinity::Infinity infinity) { preInfinity = infinity; }
|
||||
|
||||
/** Retrieves the type of behavior for the curve if the input value is
|
||||
outside the input interval defined by the curve keys and greater than any key input value.
|
||||
@see FUDaeInfinity
|
||||
@return The post-infinity behavior of the curve. */
|
||||
inline FUDaeInfinity::Infinity GetPostInfinity() const { return postInfinity; }
|
||||
|
||||
/** Sets the behavior of the curve if the input value is
|
||||
outside the input interval defined by the curve keys and greater than any key input value.
|
||||
@see FUDaeInfinity
|
||||
@param infinity The post-infinity behavior of the curve. */
|
||||
inline void SetPostInfinity(FUDaeInfinity::Infinity infinity) { postInfinity = infinity; }
|
||||
|
||||
/** Retrieves the value pointer that drives this animation curve.
|
||||
@return The driver value pointer. This pointer will be NULL to indicate
|
||||
that time drives the animation curve. */
|
||||
inline const float* GetDriver() const { return inputDriver; }
|
||||
|
||||
/** Sets the value pointer that drives the animation curve.
|
||||
@param driver The driver value pointer. Set this pointer to NULL
|
||||
to indicate that time drives the animation curve. */
|
||||
inline void SetDriver(const float* driver) { inputDriver = driver; }
|
||||
|
||||
/** Retrieves the list of animation clips that use this animation curve.
|
||||
@return The list of animation clips. */
|
||||
inline FCDAnimationClipList& GetClips() { return clips; }
|
||||
inline const FCDAnimationClipList& GetClips() const { return clips; } /**< See above. */
|
||||
|
||||
/** Readies this curve for evaluation.
|
||||
This will create the tangents and the tangent weights, if necessary. */
|
||||
void Ready();
|
||||
|
||||
/** Clones the animation curve.
|
||||
@return The cloned animation curve. */
|
||||
FCDAnimationCurve* Clone();
|
||||
|
||||
/** Applies a conversion function to the keys output values of the animation curve.
|
||||
@param valueConversion The conversion function to use on the key outputs.
|
||||
@param tangentConversion The conversion function to use on the key tangents. */
|
||||
void ConvertValues(FCDConversionFunction valueConversion, FCDConversionFunction tangentConversion);
|
||||
|
||||
/** Applies a conversion function to the keys input values of the animation curve.
|
||||
@param timeConversion The conversion function to use on the key inputs.
|
||||
@param tangentWeightConversion The conversion function to use on the key tangent weights. */
|
||||
void ConvertInputs(FCDConversionFunction timeConversion, FCDConversionFunction tangentWeightConversion);
|
||||
|
||||
/** Evaluates the animation curve.
|
||||
@param input An input value.
|
||||
@return The sampled value of the curve at the given input value. */
|
||||
float Evaluate(float input) const;
|
||||
|
||||
/** [INTERNAL] Adds an animation clip to the list of animation clips that use this curve.
|
||||
@param clip An animation clip. */
|
||||
inline void RegisterAnimationClip(FCDAnimationClip* clip) { clips.push_back(clip); }
|
||||
|
||||
/** [INTERNAL] Writes out the data sources necessary to import the animation curve
|
||||
to a given XML tree node.
|
||||
@param parentNode The XML tree node in which to create the data sources.
|
||||
@param baseId A COLLADA Id prefix to use when generating the source ids. */
|
||||
void WriteSourceToXML(xmlNode* parentNode, const string& baseId) const;
|
||||
|
||||
/** [INTERNAL] Writes out the sampler that puts together the data sources
|
||||
and generates a sampling function.
|
||||
@param parentNode The XML tree node in which to create the sampler.
|
||||
@param baseId The COLLADA id prefix used when generating the source ids.
|
||||
This prefix is also used to generate the sampler COLLADA id.
|
||||
@return The created XML tree node. */
|
||||
xmlNode* WriteSamplerToXML(xmlNode* parentNode, const string& baseId) const;
|
||||
|
||||
/** [INTERNAL] Writes out the animation channel that attaches the sampling function
|
||||
to the animatable value.
|
||||
@param parentNode The XML tree node in which to create the sampler.
|
||||
@param baseId The COLLADA Id prefix used when generating the source ids
|
||||
and the sampler id.
|
||||
@param targetPointer The target pointer prefix for the targeted animated element.
|
||||
@return The created XML tree node. */
|
||||
xmlNode* WriteChannelToXML(xmlNode* parentNode, const string& baseId, const char* targetPointer) const;
|
||||
|
||||
/** [INTERNAL] Retrieves the target element suffix for the curve.
|
||||
This will be -1 if the animated element does not belong to an
|
||||
animated element list.
|
||||
@return The target element suffix. */
|
||||
inline int32 GetTargetElement() const { return targetElement; }
|
||||
|
||||
/** [INTERNAL] Retrieves the target qualifier for the curve.
|
||||
This will be the empty string if that the curve affects
|
||||
a one-dimensional animated element.
|
||||
@return The target qualifier. */
|
||||
inline const string& GetTargetQualifier() const { return targetQualifier; }
|
||||
|
||||
/** [INTERNAL] Sets the target element suffix for the curve.
|
||||
@param e The target element suffix. Set to value to -1
|
||||
if the animated element does not belong to an animated element list. */
|
||||
inline void SetTargetElement(int32 e) { targetElement = e; }
|
||||
|
||||
/** [INTERNAL] Sets the target qualifier for the curve.
|
||||
@param q The target qualifier. You may sets this string to the empty string
|
||||
only if that the curve affects a one-dimensional animated element. */
|
||||
inline void SetTargetQualifier(const string& q) { targetQualifier = q; }
|
||||
|
||||
/** [INTERNAL] Retrieves the target pointer prefix of the driver.
|
||||
@return The driver's target pointer prefix. */
|
||||
inline const string& GetDriverPointer() const { return driverPointer; }
|
||||
|
||||
/** [INTERNAL] Sets the target pointer prefix of the driver.
|
||||
@param p The driver's target pointer prefix. Set this string to the
|
||||
empty string if the input of the animation curve is the time. */
|
||||
inline void SetDriverPointer(const string& p) { driverPointer = p; }
|
||||
};
|
||||
|
||||
#endif // _FCD_ANIMATION_CURVE_H_
|
||||
378
Extras/FCollada/FCDocument/FCDAnimationMultiCurve.cpp
Normal file
378
Extras/FCollada/FCDocument/FCDAnimationMultiCurve.cpp
Normal file
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDAnimationCurve.h"
|
||||
#include "FCDocument/FCDAnimationMultiCurve.h"
|
||||
#include "FUtils/FUDaeEnum.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
#define SMALL_DELTA 0.001f
|
||||
|
||||
FCDAnimationMultiCurve::FCDAnimationMultiCurve(FCDocument* document, uint32 _dimension) : FCDObject(document, "FCDAnimationMultiCurve")
|
||||
{
|
||||
dimension = _dimension;
|
||||
if (dimension == 0) dimension = 1;
|
||||
|
||||
// Prepare the target information
|
||||
targetElement = -1;
|
||||
targetQualifiers = new string[dimension];
|
||||
|
||||
// Allocate the key values and tangents to the wanted dimension
|
||||
keyValues = new FloatList[dimension];
|
||||
inTangents = new FloatList[dimension];
|
||||
outTangents = new FloatList[dimension];
|
||||
}
|
||||
|
||||
FCDAnimationMultiCurve::~FCDAnimationMultiCurve()
|
||||
{
|
||||
SAFE_DELETE_ARRAY(targetQualifiers);
|
||||
SAFE_DELETE_ARRAY(keyValues);
|
||||
SAFE_DELETE_ARRAY(inTangents);
|
||||
SAFE_DELETE_ARRAY(outTangents);
|
||||
}
|
||||
|
||||
// Samples all the curves for a given input
|
||||
void FCDAnimationMultiCurve::Evaluate(float input, float* output) const
|
||||
{
|
||||
// Single key curves imply a constant value
|
||||
if (keys.size() == 1)
|
||||
{
|
||||
for (uint32 i = 0; i < dimension; ++i) output[i] = keyValues[i].front();
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the current interval
|
||||
uint32 index = 0;
|
||||
FloatList::const_iterator it;
|
||||
for (it = keys.begin(); it != keys.end(); ++it, ++index)
|
||||
{
|
||||
if ((*it) > input) break;
|
||||
}
|
||||
|
||||
if (it == keys.end())
|
||||
{
|
||||
// We're sampling after the curve, return the last values
|
||||
for (uint32 i = 0; i < dimension; ++i) output[i] = keyValues[i].back();
|
||||
return;
|
||||
}
|
||||
else if (it == keys.begin())
|
||||
{
|
||||
// We're sampling before the curve, return the first values
|
||||
for (uint32 i = 0; i < dimension; ++i) output[i] = keyValues[i].front();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the keys and values for this interval
|
||||
float endKey = *it;
|
||||
float startKey = *(it - 1);
|
||||
|
||||
// Interpolate the outputs.
|
||||
// Similar code is found in FCDAnimationCurve.cpp. If you update this, update the other one too.
|
||||
uint32 interpolation = interpolations.empty() ? ((uint32) FUDaeInterpolation::DEFAULT) : interpolations[index];
|
||||
switch (FUDaeInterpolation::Interpolation(interpolation))
|
||||
{
|
||||
case FUDaeInterpolation::LINEAR: {
|
||||
for (uint32 i = 0; i < dimension; ++i)
|
||||
{
|
||||
float startValue = keyValues[i][index - 1];
|
||||
float endValue = keyValues[i][index];
|
||||
output[i] = (input - startKey) / (endKey - startKey) * (endValue - startValue) + startValue;
|
||||
}
|
||||
break; }
|
||||
|
||||
case FUDaeInterpolation::BEZIER: {
|
||||
for (uint32 i = 0; i < dimension; ++i)
|
||||
{
|
||||
float startValue = keyValues[i][index - 1];
|
||||
float endValue = keyValues[i][index];
|
||||
|
||||
float t = (input - startKey) / (endKey - startKey);
|
||||
float bValue = startValue + outTangents[i][index - 1];
|
||||
float cValue = endValue - inTangents[i][index];
|
||||
float ti = 1.0f - t;
|
||||
|
||||
output[i] = startValue * ti * ti * ti + 3.0f * bValue * ti * ti * t + 3.0f * cValue * ti * t * t + endValue * t * t * t;
|
||||
}
|
||||
break; }
|
||||
|
||||
case FUDaeInterpolation::UNKNOWN:
|
||||
case FUDaeInterpolation::STEP:
|
||||
default: {
|
||||
for (uint32 i = 0; i < dimension; ++i)
|
||||
{
|
||||
output[i] = keyValues[i][index - 1];
|
||||
}
|
||||
break; }
|
||||
}
|
||||
}
|
||||
|
||||
FCDAnimationMultiCurve* FCDAnimationMultiCurve::MergeCurves(const vector<FCDAnimationCurve*>& _toMerge, const FloatList& defaultValues)
|
||||
{
|
||||
vector<const FCDAnimationCurve*> toMerge(_toMerge.size());
|
||||
for (vector<FCDAnimationCurve*>::const_iterator itC = _toMerge.begin(); itC != _toMerge.end(); ++itC)
|
||||
{
|
||||
toMerge.push_back(*itC);
|
||||
}
|
||||
return MergeCurves(toMerge, defaultValues);
|
||||
}
|
||||
|
||||
// Non-standard constructor used to merge together animation curves
|
||||
FCDAnimationMultiCurve* FCDAnimationMultiCurve::MergeCurves(const vector<const FCDAnimationCurve*>& toMerge, const FloatList& defaultValues)
|
||||
{
|
||||
size_t dimension = toMerge.size();
|
||||
if (dimension == 0) return NULL;
|
||||
|
||||
// Look for the document pointer
|
||||
FCDocument* document = NULL;
|
||||
int32 targetElement = -1;
|
||||
for (size_t i = 0; i < dimension; ++i)
|
||||
{
|
||||
if (toMerge[i] != NULL)
|
||||
{
|
||||
document = toMerge[i]->GetDocument();
|
||||
targetElement = toMerge[i]->GetTargetElement();
|
||||
}
|
||||
}
|
||||
if (document == NULL) return NULL;
|
||||
|
||||
// Allocate the output multiCurve.
|
||||
FCDAnimationMultiCurve* multiCurve = new FCDAnimationMultiCurve(document, (uint32) dimension);
|
||||
multiCurve->targetElement = targetElement;
|
||||
|
||||
// Grab all the animation curve data element right away, to spare me some typing.
|
||||
FloatList& keys = multiCurve->GetKeys();
|
||||
FloatList* values = multiCurve->GetKeyValues();
|
||||
FloatList* inTangents = multiCurve->GetInTangents();
|
||||
FloatList* outTangents = multiCurve->GetOutTangents();
|
||||
UInt32List& interpolations = multiCurve->GetInterpolations();
|
||||
|
||||
// Calculate the merged input keys
|
||||
for (size_t i = 0; i < dimension; ++i)
|
||||
{
|
||||
const FCDAnimationCurve* curve = toMerge[i];
|
||||
if (curve == NULL) continue;
|
||||
|
||||
const FloatList& curveKeys = curve->GetKeys();
|
||||
|
||||
// Merge each curve's keys, which should already be sorted, into the multi-curve's
|
||||
size_t multiCurveKeyCount = keys.size(), m = 0;
|
||||
size_t curveKeyCount = curveKeys.size(), c = 0;
|
||||
while (m < multiCurveKeyCount && c < curveKeyCount)
|
||||
{
|
||||
if (IsEquivalent(keys[m], curveKeys[c])) { ++c; ++m; }
|
||||
else if (keys[m] < curveKeys[c]) { ++m; }
|
||||
else { keys.insert(keys.begin() + m, curveKeys[c++]); }
|
||||
}
|
||||
if (c < curveKeyCount) keys.insert(keys.end(), curveKeys.begin() + c, curveKeys.end());
|
||||
}
|
||||
size_t keyCount = keys.size();
|
||||
|
||||
// Start with the unknown interpolation everywhere
|
||||
interpolations.resize(keyCount);
|
||||
for (UInt32List::iterator it = interpolations.begin(); it != interpolations.end(); ++it)
|
||||
{
|
||||
(*it) = (uint32) FUDaeInterpolation::UNKNOWN;
|
||||
}
|
||||
|
||||
// Merge the curves one by one into the multi-curve
|
||||
for (size_t i = 0; i < dimension; ++i)
|
||||
{
|
||||
// Pre-allocate the value and tangent data arrays
|
||||
values[i].resize(keyCount);
|
||||
inTangents[i].resize(keyCount);
|
||||
outTangents[i].resize(keyCount);
|
||||
|
||||
const FCDAnimationCurve* curve = toMerge[i];
|
||||
if (curve == NULL)
|
||||
{
|
||||
// No curve, set the default value on all the keys
|
||||
float defaultValue = (i < defaultValues.size()) ? defaultValues[i] : 0.0f;
|
||||
for (size_t k = 0; k < keyCount; ++k)
|
||||
{
|
||||
values[i][k] = defaultValue;
|
||||
inTangents[i][k] = 0.0f;
|
||||
outTangents[i][k] = 0.0f;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
multiCurve->targetQualifiers[i] = curve->GetTargetQualifier();
|
||||
|
||||
// Does the curve have per-key interpolations?
|
||||
bool hasDefaultInterpolation = curve->GetInterpolations().empty();
|
||||
|
||||
// Merge in this curve's values, sampling when the multi-curve's key is not present in the curve.
|
||||
const FloatList& curveKeys = curve->GetKeys();
|
||||
size_t curveKeyCount = curveKeys.size();
|
||||
bool sampleNextInTangent = false;
|
||||
for (size_t k = 0, c = 0; k < keyCount; ++k)
|
||||
{
|
||||
uint32 interpolation;
|
||||
if (c >= curveKeyCount || !IsEquivalent(keys[k], curveKeys[c]))
|
||||
{
|
||||
// Sample the curve
|
||||
float value = values[i][k] = curve->Evaluate(keys[k]);
|
||||
|
||||
// Calculate the in-tangent and the previous key's out-tangent
|
||||
float span = ((k > 0) ? (keys[k] - keys[k - 1]) : (keys[k + 1] - keys[k])) / 3.0f;
|
||||
inTangents[i][k] = value - curve->Evaluate(keys[k] - SMALL_DELTA) / SMALL_DELTA * span;
|
||||
if (k > 0) outTangents[i][k-1] = curve->Evaluate(keys[k - 1] + SMALL_DELTA) / SMALL_DELTA * span - values[i][k-1];
|
||||
|
||||
// Calculate the out-tangent and force the sampling of the next key's in-tangent
|
||||
span = (c < curveKeyCount - 1) ? (keys[k + 1] - keys[k]) / 3.0f : span;
|
||||
outTangents[i][k] = curve->Evaluate(keys[k] + SMALL_DELTA) / SMALL_DELTA * span - value;
|
||||
interpolation = FUDaeInterpolation::BEZIER;
|
||||
sampleNextInTangent = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keys match, grab the values directly
|
||||
values[i][k] = curve->GetKeyValues()[c];
|
||||
outTangents[i][k] = curve->GetOutTangents()[c];
|
||||
interpolation = hasDefaultInterpolation ? ((uint32) FUDaeInterpolation::DEFAULT) : curve->GetInterpolations()[c];
|
||||
|
||||
// Sampling the previous key would require that we sample the inTangent
|
||||
if (!sampleNextInTangent) inTangents[i][k] = curve->GetInTangents()[c];
|
||||
else
|
||||
{
|
||||
float span = (keys[k] - keys[k - 1]) / 3.0f;
|
||||
inTangents[i][k] = values[i][k] - curve->Evaluate(keys[k] - SMALL_DELTA) / SMALL_DELTA * span;
|
||||
}
|
||||
++c;
|
||||
}
|
||||
|
||||
// Merge the interpolation values, where bezier wins whenever interpolation values differ
|
||||
uint32& oldInterpolation = interpolations[k];
|
||||
if (oldInterpolation == FUDaeInterpolation::UNKNOWN) oldInterpolation = interpolation;
|
||||
else if (oldInterpolation != interpolation) oldInterpolation = FUDaeInterpolation::BEZIER;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset any unknown interpolation left
|
||||
for (UInt32List::iterator it = interpolations.begin(); it != interpolations.end(); ++it)
|
||||
{
|
||||
if ((*it) == (uint32) FUDaeInterpolation::UNKNOWN) (*it) = FUDaeInterpolation::DEFAULT;
|
||||
}
|
||||
|
||||
return multiCurve;
|
||||
}
|
||||
|
||||
// Collapse this multi-dimensional curve into a one-dimensional curve, given a collapsing function
|
||||
FCDAnimationCurve* FCDAnimationMultiCurve::Collapse(FCDCollapsingFunction collapse) const
|
||||
{
|
||||
size_t keyCount = keys.size();
|
||||
if (keyCount == 0 || dimension == 0) return NULL;
|
||||
if (collapse == NULL) collapse = Average;
|
||||
|
||||
// Create the output one-dimensional curve and retrieve its data list
|
||||
FCDAnimationCurve* out = new FCDAnimationCurve(GetDocument(), NULL);
|
||||
out->SetTargetElement(targetElement);
|
||||
FloatList& outKeys = out->GetKeys();
|
||||
FloatList& outKeyValues = out->GetKeyValues();
|
||||
FloatList& outInTangents = out->GetInTangents();
|
||||
FloatList& outOutTangents = out->GetOutTangents();
|
||||
UInt32List& outInterpolations = out->GetInterpolations();
|
||||
|
||||
// Pre-allocate the output arrays
|
||||
outKeys.resize(keyCount);
|
||||
outKeyValues.resize(keyCount);
|
||||
outInTangents.resize(keyCount);
|
||||
outOutTangents.resize(keyCount);
|
||||
outInterpolations.resize(keyCount);
|
||||
|
||||
// Copy the key data over, collapsing the values
|
||||
float* buffer = new float[dimension];
|
||||
for (size_t i = 0; i < keyCount; ++i)
|
||||
{
|
||||
outKeys[i] = keys[i];
|
||||
outInterpolations[i] = interpolations[i];
|
||||
|
||||
// Collapse the values and the tangents
|
||||
# define COLLAPSE(outArray, inArray) \
|
||||
for (uint32 j = 0; j < dimension; ++j) buffer[j] = inArray[j][i]; \
|
||||
outArray[i] = (*collapse)(buffer, dimension)
|
||||
|
||||
COLLAPSE(outKeyValues, keyValues);
|
||||
COLLAPSE(outInTangents, inTangents);
|
||||
COLLAPSE(outOutTangents, outTangents);
|
||||
# undef COLLAPSE
|
||||
}
|
||||
SAFE_DELETE_ARRAY(buffer);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Write out the specific animation elements to the COLLADA xml tree node
|
||||
void FCDAnimationMultiCurve::WriteSourceToXML(xmlNode* parentNode, const string& baseId)
|
||||
{
|
||||
if (keys.empty() || dimension == 0 || keyValues[0].empty()) return;
|
||||
|
||||
// Generate the list of the parameters
|
||||
typedef const char* pchar;
|
||||
pchar* parameters = new pchar[dimension];
|
||||
for (size_t i = 0; i < dimension; ++i)
|
||||
{
|
||||
parameters[i] = targetQualifiers[i].c_str();
|
||||
if (*(parameters[i]) == '.') ++(parameters[i]);
|
||||
}
|
||||
|
||||
// Export the key times
|
||||
AddSourceFloat(parentNode, baseId + "-input", keys, "TIME");
|
||||
|
||||
// Interlace the key values and tangents for the export
|
||||
size_t valueCount = keyValues[0].size();
|
||||
FloatList sourceData; sourceData.reserve(dimension * valueCount);
|
||||
for (size_t v = 0; v < valueCount; ++v) for (uint32 n = 0; n < dimension; ++n) sourceData.push_back(keyValues[n].at(v));
|
||||
AddSourceFloat(parentNode, baseId + "-output", sourceData, dimension, parameters);
|
||||
|
||||
sourceData.clear();
|
||||
for (size_t v = 0; v < valueCount; ++v) for (uint32 n = 0; n < dimension; ++n) sourceData.push_back(inTangents[n].at(v));
|
||||
AddSourceFloat(parentNode, baseId + "-intangents", sourceData, dimension, parameters);
|
||||
|
||||
sourceData.clear();
|
||||
for (size_t v = 0; v < valueCount; ++v) for (uint32 n = 0; n < dimension; ++n) sourceData.push_back(outTangents[n].at(v));
|
||||
AddSourceFloat(parentNode, baseId + "-outtangents", sourceData, dimension, parameters);
|
||||
|
||||
// Weights not yet supported on multi-curve
|
||||
|
||||
AddSourceInterpolation(parentNode, baseId + "-interpolations", *(FUDaeInterpolationList*)&interpolations);
|
||||
}
|
||||
|
||||
xmlNode* FCDAnimationMultiCurve::WriteSamplerToXML(xmlNode* parentNode, const string& baseId)
|
||||
{
|
||||
xmlNode* samplerNode = AddChild(parentNode, DAE_SAMPLER_ELEMENT);
|
||||
AddAttribute(samplerNode, DAE_ID_ATTRIBUTE, baseId + "-sampler");
|
||||
|
||||
// Add the sampler inputs
|
||||
AddInput(samplerNode, baseId + "-input", DAE_INPUT_ANIMATION_INPUT);
|
||||
AddInput(samplerNode, baseId + "-output", DAE_OUTPUT_ANIMATION_INPUT);
|
||||
AddInput(samplerNode, baseId + "-intangents", DAE_INTANGENT_ANIMATION_INPUT);
|
||||
AddInput(samplerNode, baseId + "-outtangents", DAE_OUTTANGENT_ANIMATION_INPUT);
|
||||
AddInput(samplerNode, baseId + "-interpolations", DAE_INTERPOLATION_ANIMATION_INPUT);
|
||||
return samplerNode;
|
||||
}
|
||||
|
||||
xmlNode* FCDAnimationMultiCurve::WriteChannelToXML(xmlNode* parentNode, const string& baseId, const string& pointer)
|
||||
{
|
||||
xmlNode* channelNode = AddChild(parentNode, DAE_CHANNEL_ELEMENT);
|
||||
AddAttribute(channelNode, DAE_SOURCE_ATTRIBUTE, baseId + "-sampler");
|
||||
|
||||
// Generate and export the full target [no qualifiers]
|
||||
globalSBuilder.set(pointer);
|
||||
if (targetElement >= 0)
|
||||
{
|
||||
globalSBuilder.append('('); globalSBuilder.append(targetElement); globalSBuilder.append(')');
|
||||
}
|
||||
AddAttribute(channelNode, DAE_TARGET_ATTRIBUTE, globalSBuilder);
|
||||
return channelNode;
|
||||
}
|
||||
179
Extras/FCollada/FCDocument/FCDAnimationMultiCurve.h
Normal file
179
Extras/FCollada/FCDocument/FCDAnimationMultiCurve.h
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDAnimationMultiCurve.h
|
||||
This file contains the FCDAnimationMultiCurve class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_ANIMATION_MULTI_CURVE_H_
|
||||
#define _FCD_ANIMATION_MULTI_CURVE_H_
|
||||
|
||||
class FCDocument;
|
||||
|
||||
#include "FCDocument/FCDObject.h"
|
||||
|
||||
typedef float (*FCDConversionFunction)(float v); /**< A simple conversion function. */
|
||||
typedef float (*FCDCollapsingFunction)(float* values, uint32 count); /**< A collapsing function. It converts multiple floating-point values into one floating-point value. */
|
||||
|
||||
/**
|
||||
A COLLADA multi-dimensional animation curve.
|
||||
|
||||
This is a utility class that is used to convert multiple
|
||||
animation curves into one animation curve that has multiple
|
||||
dimensions, but only one list of key inputs.
|
||||
|
||||
FCollada will never create a multi-dimensional animation curve
|
||||
during the import of a COLLADA document.
|
||||
|
||||
@ingroup FCDocument
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDAnimationMultiCurve : public FCDObject
|
||||
{
|
||||
private:
|
||||
// The number of merged curves
|
||||
uint32 dimension;
|
||||
|
||||
// Target information
|
||||
int32 targetElement;
|
||||
string* targetQualifiers;
|
||||
|
||||
// Input information
|
||||
FloatList keys,* keyValues;
|
||||
FloatList* inTangents,* outTangents;
|
||||
|
||||
// The interpolation values follow the FUDaeInterpolation enum (FUDaeEnum.h)
|
||||
UInt32List interpolations;
|
||||
|
||||
public:
|
||||
/** Constructor.
|
||||
The number of dimensions will not change in the lifetime of a
|
||||
multi-dimensional curve.
|
||||
@param document The COLLADA document that owns the animation curve.
|
||||
@param dimension The number of dimensions for the animation curve. */
|
||||
FCDAnimationMultiCurve(FCDocument* document, uint32 dimension);
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~FCDAnimationMultiCurve();
|
||||
|
||||
/** Merges multiple single-dimensional animation curves into one
|
||||
multi-dimensional animation curve.
|
||||
For each NULL element found within the 'toMerge' list, the corresponding
|
||||
default value is used. If there are not enough default values provided, zero is assumed.
|
||||
The number of dimensions for the output animation curve is taken as the size of the 'toMerge' list.
|
||||
@param toMerge The list of single-dimensional animation curves to merge. This list may
|
||||
contain NULL elements, as explained above.
|
||||
@param defaultValues The list of default values to use when a NULL element is encountered.
|
||||
Default values should be provided even for the elements that are not NULL. */
|
||||
static FCDAnimationMultiCurve* MergeCurves(const vector<FCDAnimationCurve*>& toMerge, const FloatList& defaultValues);
|
||||
static FCDAnimationMultiCurve* MergeCurves(const vector<const FCDAnimationCurve*>& toMerge, const FloatList& defaultValues); /**< See above. */
|
||||
|
||||
/** Retrieves the number of dimensions for the curve.
|
||||
@return The number of dimensions for the curve. */
|
||||
inline uint32 GetDimension() const { return dimension; }
|
||||
|
||||
/** Retrieves the list of key inputs for the animation curve.
|
||||
@return The list of key inputs. */
|
||||
inline FloatList& GetKeys() { return keys; }
|
||||
inline const FloatList& GetKeys() const { return keys; } /**< See above. */
|
||||
|
||||
/** Retrieves the lists of key outputs for the animation curve.
|
||||
There is one separate list of key outputs for each dimension of the curve.
|
||||
@return The lists of key outputs. */
|
||||
inline FloatList* GetKeyValues() { return keyValues; }
|
||||
inline const FloatList* GetKeyValues() const { return keyValues; } /**< See above. */
|
||||
|
||||
/** Retrieves the lists of key in-tangent values for the animation curve.
|
||||
These lists have data only if the curve includes segments with the bezier interpolation.
|
||||
There is one separate list of key in-tangent values for each dimension of the curve.
|
||||
@return The lists of in-tangent values. */
|
||||
inline FloatList* GetInTangents() { return inTangents; }
|
||||
inline const FloatList* GetInTangents() const { return inTangents; } /**< See above. */
|
||||
|
||||
/** Retrieves the lists of key out-tangent values for the animation curve.
|
||||
These lists have data only if the curve includes segments with the bezier interpolation.
|
||||
There is one separate list of key out-tangent values for each dimension of the curve.
|
||||
@return The lists of out-tangent values. */
|
||||
inline FloatList* GetOutTangents() { return outTangents; }
|
||||
inline const FloatList* GetOutTangents() const { return outTangents; } /**< See above. */
|
||||
|
||||
/** Retrieves the list of interpolation type for the segments of the animation curve.
|
||||
There is always one interpolation type for each key in the curve. The interpolation type
|
||||
of a segment of the curve is set at the key at which begins the segment.
|
||||
@see FUDaeInterpolation
|
||||
@return The list of interpolation types. */
|
||||
inline UInt32List& GetInterpolations() { return interpolations; }
|
||||
inline const UInt32List& GetInterpolations() const { return interpolations; } /**< See above. */
|
||||
|
||||
/** Evaluates the animation curve.
|
||||
@param input An input value.
|
||||
@param output An array of floating-point values to fill in with the sampled values. */
|
||||
void Evaluate(float input, float* output) const;
|
||||
|
||||
/** Collapses this multi-dimensional curve into a one-dimensional curve.
|
||||
@param collapse The function to use to collapse multiple floating-point
|
||||
values into one. Set this to NULL to use the default collapsing
|
||||
function, which averages all the values.
|
||||
@see Average TakeFirst */
|
||||
FCDAnimationCurve* Collapse(FCDCollapsingFunction collapse=NULL) const;
|
||||
|
||||
/** [INTERNAL] Writes out the data sources necessary to import the animation curve
|
||||
to a given XML tree node.
|
||||
@param parentNode The XML tree node in which to create the data sources.
|
||||
@param baseId A COLLADA Id prefix to use when generating the source ids. */
|
||||
void WriteSourceToXML(xmlNode* parentNode, const string& baseId);
|
||||
|
||||
/** [INTERNAL] Writes out the sampler that puts together the data sources
|
||||
and generates a sampling function.
|
||||
@param parentNode The XML tree node in which to create the sampler.
|
||||
@param baseId The COLLADA id prefix used when generating the source ids.
|
||||
This prefix is also used to generate the sampler COLLADA id.
|
||||
@return The created XML tree node. */
|
||||
xmlNode* WriteSamplerToXML(xmlNode* parentNode, const string& baseId);
|
||||
|
||||
/** [INTERNAL] Writes out the animation channel that attaches the sampling function
|
||||
to the animatable value.
|
||||
@param parentNode The XML tree node in which to create the sampler.
|
||||
@param baseId The COLLADA Id prefix used when generating the source ids
|
||||
and the sampler id.
|
||||
@param pointer The target pointer prefix for the targeted animated element.
|
||||
@return The created XML tree node. */
|
||||
xmlNode* WriteChannelToXML(xmlNode* parentNode, const string& baseId, const string& pointer);
|
||||
|
||||
/** [INTERNAL] Retrieves the target element suffix for the curve.
|
||||
This will be -1 if the animated element does not belong to an
|
||||
animated element list.
|
||||
@return The target element suffix. */
|
||||
inline int32 GetTargetElement() const { return targetElement; }
|
||||
|
||||
/** [INTERNAL] Sets the target element suffix for the curve.
|
||||
@param e The target element suffix. Set to value to -1
|
||||
if the animated element does not belong to an animated element list. */
|
||||
inline void SetTargetElement(int32 e) { targetElement = e; }
|
||||
};
|
||||
|
||||
/**
|
||||
Retrieves the first floating-point value of a list of floating-point values.
|
||||
This is a typical conversion function.
|
||||
@param values The list of floating-point values.
|
||||
@param count The number of values within the given list.
|
||||
*/
|
||||
inline float TakeFirst(float* values, uint32 count) { return (count > 0) ? *values : 0.0f; }
|
||||
|
||||
/**
|
||||
Retrieves the average value of a list of floating-point values.
|
||||
This is a typical conversion function.
|
||||
@param values The list of floating-point values.
|
||||
@param count The number of values within the given list.
|
||||
*/
|
||||
inline float Average(float* values, uint32 count) { float v = 0.0f; for (uint32 i = 0; i < count; ++i) v += values[i]; v /= float(count); return v; }
|
||||
|
||||
#endif // _FCD_ANIMATION_MULTI_CURVE_H_
|
||||
207
Extras/FCollada/FCDocument/FCDAsset.cpp
Normal file
207
Extras/FCollada/FCDocument/FCDAsset.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FUtils/FUDateTime.h"
|
||||
#include "FCDocument/FCDAsset.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDAsset::FCDAsset(FCDocument* document) : FCDObject(document, "FCDAsset")
|
||||
{
|
||||
unitConversionFactor = 1.0f;
|
||||
unitName = FC("meter");
|
||||
upAxis = FMVector3::YAxis;
|
||||
creationDateTime = modifiedDateTime = FUDateTime::GetNow();
|
||||
}
|
||||
|
||||
FCDAsset::~FCDAsset()
|
||||
{
|
||||
while(!contributors.empty())
|
||||
{
|
||||
SAFE_DELETE(contributors.back());
|
||||
contributors.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
// Insert a new contributor within the list
|
||||
FCDAssetContributor* FCDAsset::AddContributor()
|
||||
{
|
||||
FCDAssetContributor* contributor = new FCDAssetContributor(GetDocument());
|
||||
contributors.push_back(contributor);
|
||||
return contributor;
|
||||
}
|
||||
|
||||
// Read in the <asset> element from a COLLADA xml document
|
||||
FUStatus FCDAsset::LoadFromXML(xmlNode* assetNode)
|
||||
{
|
||||
FUStatus status;
|
||||
bool isPreCollada1_4 = false;
|
||||
for (xmlNode* child = assetNode->children; child != NULL; child = child->next)
|
||||
{
|
||||
if (child->type != XML_ELEMENT_NODE) continue;
|
||||
|
||||
const char* content = ReadNodeContentDirect(child);
|
||||
if (IsEquivalent(child->name, DAE_CONTRIBUTOR_ASSET_ELEMENT))
|
||||
{
|
||||
FCDAssetContributor* contributor = new FCDAssetContributor(GetDocument());
|
||||
contributors.push_back(contributor);
|
||||
status.AppendStatus(contributor->LoadFromXML(child, false));
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_CREATED_ASSET_PARAMETER))
|
||||
{
|
||||
FUStringConversion::ToDateTime(content, creationDateTime);
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_KEYWORDS_ASSET_PARAMETER))
|
||||
{
|
||||
keywords = TO_FSTRING(content);
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_MODIFIED_ASSET_PARAMETER))
|
||||
{
|
||||
FUStringConversion::ToDateTime(content, modifiedDateTime );
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_REVISION_ASSET_PARAMETER))
|
||||
{
|
||||
revision = TO_FSTRING(content);
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_SUBJECT_ASSET_PARAMETER))
|
||||
{
|
||||
subject = TO_FSTRING(content);
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_TITLE_ASSET_PARAMETER))
|
||||
{
|
||||
title = TO_FSTRING(content);
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_UNITS_ASSET_PARAMETER))
|
||||
{
|
||||
unitName = TO_FSTRING(ReadNodeName(child));
|
||||
unitConversionFactor = FUStringConversion::ToFloat(ReadNodeProperty(child, DAE_METERS_ATTRIBUTE));
|
||||
if (unitName.empty()) unitName = FC("UNKNOWN");
|
||||
if (IsEquivalent(unitConversionFactor, 0.0f) || unitConversionFactor < 0.0f) unitConversionFactor = 1.0f;
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_UPAXIS_ASSET_PARAMETER))
|
||||
{
|
||||
if (IsEquivalent(content, DAE_X_UP)) upAxis = FMVector3::XAxis;
|
||||
else if (IsEquivalent(content, DAE_Y_UP)) upAxis = FMVector3::YAxis;
|
||||
else if (IsEquivalent(content, DAE_Z_UP)) upAxis = FMVector3::ZAxis;
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_AUTHOR_ASSET_PARAMETER) || IsEquivalent(child->name, DAE_AUTHORINGTOOL_ASSET_PARAMETER)
|
||||
|| IsEquivalent(child->name, DAE_COMMENTS_ASSET_PARAMETER) || IsEquivalent(child->name, DAE_SOURCEDATA_ASSET_PARAMETER)
|
||||
|| IsEquivalent(child->name, DAE_COPYRIGHT_ASSET_PARAMETER))
|
||||
{
|
||||
isPreCollada1_4 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
status.Warning(FS("Unknown <asset> child element: ") + TO_FSTRING((const char*) child->name), child->line);
|
||||
}
|
||||
}
|
||||
|
||||
// COLLADA 1.3 Backward Compatibility: Look for the contributor information within the <asset> element
|
||||
if (isPreCollada1_4)
|
||||
{
|
||||
FCDAssetContributor* contributor = new FCDAssetContributor(GetDocument());
|
||||
contributor->LoadFromXML(assetNode, true);
|
||||
if (!contributor->IsEmpty()) contributors.push_back(contributor);
|
||||
else SAFE_DELETE(contributor);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Write out the <asset> element to a COLLADA xml node tree
|
||||
xmlNode* FCDAsset::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* assetNode = AddChild(parentNode, DAE_ASSET_ELEMENT);
|
||||
|
||||
// Update the 'last modified time'
|
||||
FCDAsset* hackedAsset = const_cast<FCDAsset*>(this);
|
||||
hackedAsset->modifiedDateTime = FUDateTime::GetNow();
|
||||
|
||||
// Write out the contributors first.
|
||||
for (FCDAssetContributorList::const_iterator itC = contributors.begin(); itC != contributors.end(); ++itC)
|
||||
{
|
||||
(*itC)->WriteToXML(assetNode);
|
||||
}
|
||||
|
||||
// Write out the parameters, one by one and in the correct order.
|
||||
AddChild(assetNode, DAE_CREATED_ASSET_PARAMETER, FUStringConversion::ToString(creationDateTime));
|
||||
if (!keywords.empty()) AddChild(assetNode, DAE_KEYWORDS_ASSET_PARAMETER, keywords);
|
||||
AddChild(assetNode, DAE_MODIFIED_ASSET_PARAMETER, FUStringConversion::ToString(modifiedDateTime));
|
||||
if (!revision.empty()) AddChild(assetNode, DAE_REVISION_ASSET_PARAMETER, revision);
|
||||
if (!subject.empty()) AddChild(assetNode, DAE_SUBJECT_ASSET_PARAMETER, subject);
|
||||
if (!title.empty()) AddChild(assetNode, DAE_TITLE_ASSET_PARAMETER, title);
|
||||
|
||||
// Finally: <unit> and <up_axis>
|
||||
xmlNode* unitNode = AddChild(assetNode, DAE_UNITS_ASSET_PARAMETER);
|
||||
AddAttribute(unitNode, DAE_METERS_ATTRIBUTE, unitConversionFactor);
|
||||
AddAttribute(unitNode, DAE_NAME_ATTRIBUTE, unitName);
|
||||
AddChild(assetNode, DAE_UPAXIS_ASSET_PARAMETER, FUStringConversion::ToString(subject));
|
||||
return assetNode;
|
||||
}
|
||||
|
||||
FCDAssetContributor::FCDAssetContributor(FCDocument* document) : FCDObject(document, "FCDAssetContributor") {}
|
||||
FCDAssetContributor::~FCDAssetContributor() {}
|
||||
|
||||
// Returns whether this contributor element contain any valid data
|
||||
bool FCDAssetContributor::IsEmpty() const
|
||||
{
|
||||
return author.empty() && authoringTool.empty() && comments.empty() && copyright.empty() && sourceData.empty();
|
||||
}
|
||||
|
||||
// Read in the <asset><contributor> element from a COLLADA xml document
|
||||
FUStatus FCDAssetContributor::LoadFromXML(xmlNode* contributorNode, bool isPreCollada1_4)
|
||||
{
|
||||
FUStatus status;
|
||||
for (xmlNode* child = contributorNode->children; child != NULL; child = child->next)
|
||||
{
|
||||
if (child->type != XML_ELEMENT_NODE) continue;
|
||||
|
||||
const char* content = ReadNodeContentDirect(child);
|
||||
if (IsEquivalent(child->name, DAE_AUTHOR_ASSET_PARAMETER))
|
||||
{
|
||||
author = TO_FSTRING(content);
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_AUTHORINGTOOL_ASSET_PARAMETER))
|
||||
{
|
||||
authoringTool = TO_FSTRING(content);
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_COMMENTS_ASSET_PARAMETER))
|
||||
{
|
||||
comments = TO_FSTRING(content);
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_COPYRIGHT_ASSET_PARAMETER))
|
||||
{
|
||||
copyright = TO_FSTRING(content);
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_SOURCEDATA_ASSET_PARAMETER))
|
||||
{
|
||||
sourceData = TO_FSTRING(content);
|
||||
}
|
||||
else if (!isPreCollada1_4)
|
||||
{
|
||||
status.Warning(FS("Unknown <asset><contributor> child element: ") + TO_FSTRING((const char*) child->name), child->line);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Write out the <asset><contributor> element to a COLLADA xml node tree
|
||||
xmlNode* FCDAssetContributor::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* contributorNode = NULL;
|
||||
if (!IsEmpty())
|
||||
{
|
||||
contributorNode = AddChild(parentNode, DAE_CONTRIBUTOR_ASSET_ELEMENT);
|
||||
if (!author.empty()) AddChild(contributorNode, DAE_AUTHOR_ASSET_PARAMETER, author);
|
||||
if (!authoringTool.empty()) AddChild(contributorNode, DAE_AUTHORINGTOOL_ASSET_PARAMETER, authoringTool);
|
||||
if (!comments.empty()) AddChild(contributorNode, DAE_COMMENTS_ASSET_PARAMETER, comments);
|
||||
if (!copyright.empty()) AddChild(contributorNode, DAE_COPYRIGHT_ASSET_PARAMETER, copyright);
|
||||
if (!sourceData.empty()) AddChild(contributorNode, DAE_SOURCEDATA_ASSET_PARAMETER, sourceData);
|
||||
}
|
||||
return contributorNode;
|
||||
}
|
||||
109
Extras/FCollada/FCDocument/FCDAsset.h
Normal file
109
Extras/FCollada/FCDocument/FCDAsset.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#ifndef _FCD_ASSET_H_
|
||||
#define _FCD_ASSET_H_
|
||||
|
||||
#include "FCDocument/FCDObject.h"
|
||||
#include "FUtils/FUDateTime.h"
|
||||
|
||||
class FCDAssetContributor;
|
||||
|
||||
typedef vector<FCDAssetContributor*> FCDAssetContributorList;
|
||||
|
||||
class FCOLLADA_EXPORT FCDAsset : public FCDObject
|
||||
{
|
||||
FCDAssetContributorList contributors;
|
||||
FUDateTime creationDateTime;
|
||||
FUDateTime modifiedDateTime;
|
||||
fstring keywords;
|
||||
fstring revision;
|
||||
fstring subject;
|
||||
fstring title;
|
||||
FMVector3 upAxis;
|
||||
|
||||
// <unit>
|
||||
fstring unitName;
|
||||
float unitConversionFactor;
|
||||
|
||||
public:
|
||||
FCDAsset(FCDocument* document);
|
||||
virtual ~FCDAsset();
|
||||
|
||||
// Direct contributor list access
|
||||
inline FCDAssetContributorList& GetContributors() { return contributors; }
|
||||
inline const FCDAssetContributorList& GetContributors() const { return contributors; }
|
||||
inline size_t GetContributorCount() const { return contributors.size(); }
|
||||
inline FCDAssetContributor* GetContributor(size_t index) { return index < contributors.size() ? contributors[index] : NULL; }
|
||||
inline const FCDAssetContributor* GetContributor(size_t index) const { return index < contributors.size() ? contributors[index] : NULL; }
|
||||
FCDAssetContributor* AddContributor();
|
||||
|
||||
// Direct accessors
|
||||
inline const FUDateTime& GetCreationDateTime() const { return creationDateTime; }
|
||||
inline const FUDateTime& GetModifiedDateTime() const { return modifiedDateTime; }
|
||||
inline const fstring& GetKeywords() const { return keywords; }
|
||||
inline const fstring& GetRevision() const { return revision; }
|
||||
inline const fstring& GetSubject() const { return subject; }
|
||||
inline const fstring& GetTitle() const { return title; }
|
||||
inline const FMVector3& GetUpAxis() const { return upAxis; }
|
||||
inline const fstring& GetUnitName() const { return unitName; }
|
||||
inline float GetUnitConversionFactor() const { return unitConversionFactor; }
|
||||
|
||||
// Direct mutators
|
||||
inline void SetKeywords(const fstring& _keywords) { keywords = _keywords; }
|
||||
inline void SetRevision(const fstring& _revision) { revision = _revision; }
|
||||
inline void SetSubject(const fstring& _subject) { subject = _subject; }
|
||||
inline void SetTitle(const fstring& _title) { title = _title; }
|
||||
inline void SetUpAxis(const FMVector3& _upAxis) { upAxis = _upAxis; }
|
||||
inline void SetUnitName(const fstring& _unitName) { unitName = _unitName; }
|
||||
inline void SetUnitConversionFactor(float factor) { unitConversionFactor = factor; }
|
||||
|
||||
// Read in the <asset> element from a COLLADA xml document
|
||||
FUStatus LoadFromXML(xmlNode* assetNode);
|
||||
|
||||
// Write out the <asset> element to a COLLADA xml node tree
|
||||
// Calling this function will update the 'last modified' timestamp.
|
||||
xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
// Encapsulates the <asset><contributor> element
|
||||
class FCOLLADA_EXPORT FCDAssetContributor : public FCDObject
|
||||
{
|
||||
private:
|
||||
fstring author;
|
||||
fstring authoringTool;
|
||||
fstring comments;
|
||||
fstring copyright;
|
||||
fstring sourceData;
|
||||
|
||||
public:
|
||||
FCDAssetContributor(FCDocument* document);
|
||||
virtual ~FCDAssetContributor();
|
||||
|
||||
// Direct accessors
|
||||
inline const fstring& GetAuthor() const { return author; }
|
||||
inline const fstring& GetAuthoringTool() const { return authoringTool; }
|
||||
inline const fstring& GetComments() const { return comments; }
|
||||
inline const fstring& GetCopyright() const { return copyright; }
|
||||
inline const fstring& GetSourceData() const { return sourceData; }
|
||||
|
||||
// Direct mutators
|
||||
inline void SetAuthor(const fstring& _author) { author = _author; }
|
||||
inline void SetAuthoringTool(const fstring& _authoringTool) { authoringTool = _authoringTool; }
|
||||
inline void SetComments(const fstring& _comments) { comments = _comments; }
|
||||
inline void SetCopyright(const fstring& _copyright) { copyright = _copyright; }
|
||||
inline void SetSourceData(const fstring& _sourceData) { sourceData = _sourceData; }
|
||||
|
||||
// Returns whether this contributor element contain any valid data
|
||||
bool IsEmpty() const;
|
||||
|
||||
// Read in the <asset><contributor> element from a COLLADA xml document
|
||||
FUStatus LoadFromXML(xmlNode* contributorNode, bool isPreCollada1_4=false);
|
||||
|
||||
// Write out the <asset><contributor> element to a COLLADA xml node tree
|
||||
xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
#endif // _FCD_ASSET_H_
|
||||
268
Extras/FCollada/FCDocument/FCDCamera.cpp
Normal file
268
Extras/FCollada/FCDocument/FCDCamera.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDCamera.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDAnimated.h"
|
||||
#include "FCDocument/FCDSceneNode.h"
|
||||
#include "FUtils/FUStringConversion.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDCamera::FCDCamera(FCDocument* document) : FCDTargetedEntity(document, "Camera")
|
||||
{
|
||||
isPerspective = true;
|
||||
isOrthographic = false;
|
||||
viewY = viewX = 60.0f;
|
||||
hasAperture = hasHorizontalView = hasVerticalView = false;
|
||||
nearZ = 1.0f;
|
||||
farZ = 1000.0f;
|
||||
aspectRatio = 1.0f;
|
||||
horizontalAperture = verticalAperture = lensSqueeze = 1.0f;
|
||||
}
|
||||
|
||||
FCDCamera::~FCDCamera()
|
||||
{
|
||||
}
|
||||
|
||||
void FCDCamera::SetFovX(float _viewX)
|
||||
{
|
||||
viewX = _viewX;
|
||||
if (hasVerticalView && !IsEquivalent(viewX, 0.0f)) aspectRatio = viewY / viewX;
|
||||
hasHorizontalView = true;
|
||||
}
|
||||
|
||||
void FCDCamera::SetFovY(float _viewY)
|
||||
{
|
||||
viewY = _viewY;
|
||||
if (hasHorizontalView && !IsEquivalent(viewX, 0.0f)) aspectRatio = viewY / viewX;
|
||||
hasVerticalView = true;
|
||||
}
|
||||
|
||||
void FCDCamera::SetAspectRatio(float _aspectRatio)
|
||||
{
|
||||
aspectRatio = _aspectRatio;
|
||||
}
|
||||
|
||||
// Load this camera from the given COLLADA document's node
|
||||
FUStatus FCDCamera::LoadFromXML(xmlNode* cameraNode)
|
||||
{
|
||||
FUStatus status = FCDEntity::LoadFromXML(cameraNode);
|
||||
if (!status) return status;
|
||||
if (!IsEquivalent(cameraNode->name, DAE_CAMERA_ELEMENT))
|
||||
{
|
||||
return status.Warning(FS("Camera library contains unknown element."), cameraNode->line);
|
||||
}
|
||||
|
||||
// COLLADA 1.3: Grab the techniques and their <optics><program> children
|
||||
xmlNode* commonTechniqueNode1_3 = FindTechnique(cameraNode, DAE_COMMON_PROFILE);
|
||||
xmlNode* commonOpticsNode1_3 = FindChildByType(commonTechniqueNode1_3, DAE_OPTICS_ELEMENT);
|
||||
xmlNode* commonProgramNode1_3 = FindChildByType(commonOpticsNode1_3, DAE_PROGRAM_ELEMENT);
|
||||
xmlNode* maxTechniqueNode1_3 = FindTechnique(cameraNode, DAEMAX_MAX_PROFILE);
|
||||
xmlNode* maxOpticsNode1_3 = FindChildByType(maxTechniqueNode1_3, DAE_OPTICS_ELEMENT);
|
||||
xmlNode* maxProgramNode1_3 = FindChildByType(maxOpticsNode1_3, DAE_PROGRAM_ELEMENT);
|
||||
xmlNode* mayaTechniqueNode = FindTechnique(cameraNode, DAEMAYA_MAYA_PROFILE);
|
||||
xmlNode* mayaOpticsNode = FindChildByType(mayaTechniqueNode, DAE_OPTICS_ELEMENT);
|
||||
xmlNode* mayaProgramNode = FindChildByType(mayaOpticsNode, DAE_PROGRAM_ELEMENT);
|
||||
bool isCollada1_3 = commonTechniqueNode1_3 != NULL;
|
||||
|
||||
// COLLADA 1.4: Grab the <optics> element's techniques
|
||||
xmlNode* opticsNode = FindChildByType(cameraNode, DAE_OPTICS_ELEMENT);
|
||||
xmlNode* commonTechniqueNode = FindChildByType(opticsNode, DAE_TECHNIQUE_COMMON_ELEMENT);
|
||||
xmlNode* maxTechniqueNode = FindTechnique(opticsNode, DAEMAX_MAX_PROFILE);
|
||||
xmlNode* cameraContainerNode = (isCollada1_3) ? ((maxProgramNode1_3 != NULL) ? maxProgramNode1_3 : commonProgramNode1_3) : NULL;
|
||||
if (mayaProgramNode == NULL) mayaProgramNode = FindTechnique(opticsNode, DAEMAYA_MAYA_PROFILE);
|
||||
|
||||
// Figure out the camera type
|
||||
if (isCollada1_3)
|
||||
{
|
||||
FUUri programType = ReadNodeUrl(maxProgramNode1_3);
|
||||
if (programType.prefix.empty()) programType = ReadNodeUrl(commonProgramNode1_3);
|
||||
if (programType.prefix.empty())
|
||||
{
|
||||
return status.Fail(FS("No standard program type for camera: ") + TO_FSTRING(GetDaeId()), cameraNode->line);
|
||||
}
|
||||
string cameraType = TO_STRING(programType.prefix);
|
||||
isOrthographic = cameraType == DAE_ORTHOGRAPHIC_CAMERA_TYPE;
|
||||
isPerspective = cameraType == DAE_PERSPECTIVE_CAMERA_TYPE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Retrieve the <perspective> or <orthographic> element
|
||||
cameraContainerNode = FindChildByType(commonTechniqueNode, DAE_CAMERA_ORTHO_ELEMENT);
|
||||
isOrthographic = cameraContainerNode != NULL;
|
||||
if (!isOrthographic)
|
||||
{
|
||||
cameraContainerNode = FindChildByType(commonTechniqueNode, DAE_CAMERA_PERSP_ELEMENT);
|
||||
isPerspective = cameraContainerNode != NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
isPerspective = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the necessary camera structures
|
||||
if (cameraContainerNode == NULL)
|
||||
{
|
||||
return status.Fail(FS("Cannot find parameter root node for camera: ") + TO_FSTRING(GetDaeId()), cameraNode->line);
|
||||
}
|
||||
if (!(isPerspective ^ isOrthographic))
|
||||
{
|
||||
return status.Fail(FS("Unknown program type for camera: ") + TO_FSTRING(GetDaeId()), cameraContainerNode->line);
|
||||
}
|
||||
|
||||
// Setup the camera according to the type and its parameters
|
||||
// Retrieve all the camera parameters
|
||||
StringList parameterNames;
|
||||
xmlNodeList parameterNodes;
|
||||
FindParameters(cameraContainerNode, parameterNames, parameterNodes);
|
||||
FindParameters(maxTechniqueNode, parameterNames, parameterNodes);
|
||||
FindParameters(mayaProgramNode, parameterNames, parameterNodes);
|
||||
|
||||
#define CAM_PARAMETER(colladaParam, memberFunction, animatedMember) \
|
||||
if (parameterName == colladaParam) { \
|
||||
memberFunction(FUStringConversion::ToFloat(parameterValue)); \
|
||||
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &animatedMember); } else
|
||||
|
||||
size_t parameterCount = parameterNodes.size();
|
||||
for (size_t i = 0; i < parameterCount; ++i)
|
||||
{
|
||||
xmlNode* parameterNode = parameterNodes[i];
|
||||
const string& parameterName = parameterNames[i];
|
||||
const char* parameterValue = ReadNodeContentDirect(parameterNode);
|
||||
|
||||
// Process the camera parameters
|
||||
CAM_PARAMETER(DAE_ZNEAR_CAMERA_PARAMETER, SetNearZ, nearZ)
|
||||
CAM_PARAMETER(DAE_ZFAR_CAMERA_PARAMETER, SetFarZ, farZ)
|
||||
CAM_PARAMETER(DAE_XFOV_CAMERA_PARAMETER, SetFovX, viewX)
|
||||
CAM_PARAMETER(DAE_YFOV_CAMERA_PARAMETER, SetFovY, viewY)
|
||||
CAM_PARAMETER(DAE_XMAG_CAMERA_PARAMETER, SetMagX, viewX)
|
||||
CAM_PARAMETER(DAE_YMAG_CAMERA_PARAMETER, SetMagY, viewY)
|
||||
CAM_PARAMETER(DAE_ASPECT_CAMERA_PARAMETER, SetAspectRatio, aspectRatio)
|
||||
CAM_PARAMETER(DAEMAYA_VAPERTURE_PARAMETER, SetVerticalAperture, verticalAperture)
|
||||
CAM_PARAMETER(DAEMAYA_HAPERTURE_PARAMETER, SetHorizontalAperture, horizontalAperture)
|
||||
CAM_PARAMETER(DAEMAYA_LENSSQUEEZE_PARAMETER, SetLensSqueeze, lensSqueeze)
|
||||
if (parameterName == DAEMAX_TARGET_CAMERA_PARAMETER)
|
||||
SetTargetId(parameterValue);
|
||||
else
|
||||
|
||||
// COLLADA 1.3 backward compatibility
|
||||
CAM_PARAMETER(DAE_ZNEAR_CAMERA_PARAMETER1_3, SetNearZ, nearZ)
|
||||
CAM_PARAMETER(DAE_ZFAR_CAMERA_PARAMETER1_3, SetFarZ, farZ)
|
||||
CAM_PARAMETER(DAE_XFOV_CAMERA_PARAMETER1_3, SetFovX, viewX)
|
||||
CAM_PARAMETER(DAE_YFOV_CAMERA_PARAMETER1_3, SetFovY, viewY)
|
||||
CAM_PARAMETER(DAE_RIGHT_CAMERA_PARAMETER1_3, SetMagX, viewX)
|
||||
CAM_PARAMETER(DAE_TOP_CAMERA_PARAMETER1_3, SetMagY, viewY)
|
||||
CAM_PARAMETER(DAEMAYA_VAPERTURE_PARAMETER1_3, SetVerticalAperture, verticalAperture)
|
||||
CAM_PARAMETER(DAEMAYA_HAPERTURE_PARAMETER1_3, SetHorizontalAperture, horizontalAperture)
|
||||
CAM_PARAMETER(DAEMAYA_LENSSQUEEZE_PARAMETER1_3, SetLensSqueeze, lensSqueeze)
|
||||
if (parameterName == DAE_LEFT_CAMERA_PARAMETER1_3) {} // Don't process
|
||||
else if (parameterName == DAE_BOTTOM_CAMERA_PARAMETER1_3) {} // Don't process
|
||||
|
||||
// Max-specific parameter: target
|
||||
else if (parameterName == DAEMAX_TARGET_CAMERA_PARAMETER
|
||||
|| parameterName == DAEMAX_TARGET_CAMERA_PARAMETER1_3)
|
||||
{
|
||||
SetTargetId(parameterValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
status.Warning(FS("Unknown parameter for camera: ") + TO_FSTRING(GetDaeId()), parameterNode->line);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Write out this camera to the COLLADA XML document
|
||||
xmlNode* FCDCamera::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
// Create the base camera node
|
||||
xmlNode* cameraNode = WriteToEntityXML(parentNode, DAE_CAMERA_ELEMENT);
|
||||
xmlNode* opticsNode = AddChild(cameraNode, DAE_OPTICS_ELEMENT);
|
||||
xmlNode* baseNode = AddChild(opticsNode, DAE_TECHNIQUE_COMMON_ELEMENT);
|
||||
const char* baseNodeName;
|
||||
if (isPerspective) baseNodeName = DAE_CAMERA_PERSP_ELEMENT;
|
||||
else if (isOrthographic) baseNodeName = DAE_CAMERA_ORTHO_ELEMENT;
|
||||
else baseNodeName = DAEERR_UNKNOWN_ELEMENT;
|
||||
baseNode = AddChild(baseNode, baseNodeName);
|
||||
|
||||
// Write out the basic camera parameters
|
||||
if (isPerspective)
|
||||
{
|
||||
if (hasHorizontalView)
|
||||
{
|
||||
xmlNode* viewNode = AddChild(baseNode, DAE_XFOV_CAMERA_PARAMETER, viewX);
|
||||
GetDocument()->WriteAnimatedValueToXML(&viewX, viewNode, "horizontal_fov");
|
||||
}
|
||||
if (!hasHorizontalView || hasVerticalView)
|
||||
{
|
||||
xmlNode* viewNode = AddChild(baseNode, DAE_YFOV_CAMERA_PARAMETER, viewY);
|
||||
GetDocument()->WriteAnimatedValueToXML(&viewY, viewNode, "vertical_fov");
|
||||
}
|
||||
if (!hasHorizontalView || !hasVerticalView)
|
||||
{
|
||||
xmlNode* aspectNode = AddChild(baseNode, DAE_ASPECT_CAMERA_PARAMETER, aspectRatio);
|
||||
GetDocument()->WriteAnimatedValueToXML(&aspectRatio, aspectNode, "aspect_ratio");
|
||||
}
|
||||
}
|
||||
if (isOrthographic)
|
||||
{
|
||||
if (hasHorizontalView)
|
||||
{
|
||||
xmlNode* viewNode = AddChild(baseNode, DAE_XMAG_CAMERA_PARAMETER, viewX);
|
||||
GetDocument()->WriteAnimatedValueToXML(&viewX, viewNode, "horizontal_zoom");
|
||||
}
|
||||
if (!hasHorizontalView || hasVerticalView)
|
||||
{
|
||||
xmlNode* viewNode = AddChild(baseNode, DAE_YMAG_CAMERA_PARAMETER, viewY);
|
||||
GetDocument()->WriteAnimatedValueToXML(&viewY, viewNode, "vertical_zoom");
|
||||
}
|
||||
if (!hasHorizontalView || !hasVerticalView)
|
||||
{
|
||||
xmlNode* aspectNode = AddChild(baseNode, DAE_ASPECT_CAMERA_PARAMETER, aspectRatio);
|
||||
GetDocument()->WriteAnimatedValueToXML(&aspectRatio, aspectNode, "aspect_ratio");
|
||||
}
|
||||
}
|
||||
|
||||
// Near/Far clip plane distance
|
||||
xmlNode* clipNode = AddChild(baseNode, DAE_ZNEAR_CAMERA_PARAMETER, nearZ);
|
||||
GetDocument()->WriteAnimatedValueToXML(&nearZ, clipNode, "near_clip");
|
||||
clipNode = AddChild(baseNode, DAE_ZFAR_CAMERA_PARAMETER, farZ);
|
||||
GetDocument()->WriteAnimatedValueToXML(&farZ, clipNode, "near_clip");
|
||||
|
||||
// Add the application-specific technique/parameters
|
||||
// Maya has extra aperture information
|
||||
if (hasAperture)
|
||||
{
|
||||
xmlNode* techniqueMayaNode = AddTechniqueChild(opticsNode, DAEMAYA_MAYA_PROFILE);
|
||||
xmlNode* apertureNode = AddChild(techniqueMayaNode, DAEMAYA_VAPERTURE_PARAMETER, verticalAperture);
|
||||
GetDocument()->WriteAnimatedValueToXML(&verticalAperture, apertureNode, "vertical_aperture");
|
||||
apertureNode = AddChild(techniqueMayaNode, DAEMAYA_HAPERTURE_PARAMETER, horizontalAperture);
|
||||
GetDocument()->WriteAnimatedValueToXML(&horizontalAperture, apertureNode, "horizontal_aperture");
|
||||
apertureNode = AddChild(techniqueMayaNode, DAEMAYA_LENSSQUEEZE_PARAMETER, lensSqueeze);
|
||||
GetDocument()->WriteAnimatedValueToXML(&lensSqueeze, apertureNode, "lens_squeeze");
|
||||
}
|
||||
|
||||
// Max has target information
|
||||
if (GetTargetNode() != NULL)
|
||||
{
|
||||
xmlNode* techniqueMaxNode = AddTechniqueChild(opticsNode, DAEMAX_MAX_PROFILE);
|
||||
AddChild(techniqueMaxNode, DAEMAX_TARGET_CAMERA_PARAMETER, GetTargetNode()->GetDaeId());
|
||||
}
|
||||
|
||||
FCDEntity::WriteToExtraXML(cameraNode);
|
||||
return cameraNode;
|
||||
}
|
||||
255
Extras/FCollada/FCDocument/FCDCamera.h
Normal file
255
Extras/FCollada/FCDocument/FCDCamera.h
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDCamera.h
|
||||
This file contains the FCDCamera class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_CAMERA_H_
|
||||
#define _FCD_CAMERA_H_
|
||||
|
||||
#include "FCDocument/FCDTargetedEntity.h"
|
||||
|
||||
class FCDocument;
|
||||
class FCDSceneNode;
|
||||
|
||||
/**
|
||||
A COLLADA camera.
|
||||
Based on the FCDTargetedEntity class to support aimed cameras.
|
||||
COLLADA defines two types of cameras: perspective and orthographic.
|
||||
Both types are fully handled by this class.
|
||||
|
||||
A COLLADA perspective camera defines two of the three following parameters: horizontal field of view,
|
||||
vertical field of view and aspect ratio. The missing parameter can be calculated using the following formulae:
|
||||
aspect ratio = vertical field of view / horizontal field of view. The vertical and horizontal field
|
||||
of view are in degrees.
|
||||
|
||||
A COLLADA orthographic camera defines two of the three following parameters: horizontal magnification,
|
||||
vertical magnification and aspect ratio. The missing parameter can be calculated using the following formulae:
|
||||
aspect ratio = vertical magnification / horizontal magnification. You can calculate the viewport width
|
||||
and height using the following formulas: viewport width = horizontal magnification * 2, viewport height
|
||||
= vertical magnification * 2.
|
||||
|
||||
@ingroup FCDocument
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDCamera : public FCDTargetedEntity
|
||||
{
|
||||
private:
|
||||
// Camera flags
|
||||
bool isPerspective;
|
||||
bool isOrthographic;
|
||||
bool hasHorizontalView;
|
||||
bool hasVerticalView;
|
||||
|
||||
// Camera parameters
|
||||
float viewY;
|
||||
float viewX;
|
||||
float nearZ;
|
||||
float farZ;
|
||||
float aspectRatio;
|
||||
|
||||
// Maya parameters
|
||||
bool hasAperture;
|
||||
float verticalAperture;
|
||||
float horizontalAperture;
|
||||
float lensSqueeze;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly. Create new cameras using the FCDLibrary::AddEntity function.
|
||||
@param document The COLLADA document that contains this camera entity.*/
|
||||
FCDCamera(FCDocument* document);
|
||||
|
||||
/** Destructor: do not release directly. Release cameras using the FCDLibrary::ReleaseEntity function.
|
||||
All cameras are released with the document that they belong to. */
|
||||
virtual ~FCDCamera();
|
||||
|
||||
/** Retrieves the entity type for this class. This function is part of the FCDEntity interface.
|
||||
@return The entity type: CAMERA. */
|
||||
virtual Type GetType() const { return CAMERA; }
|
||||
|
||||
/** Retrieves whether this camera is a perspective camera.
|
||||
This is the default type of camera.
|
||||
@return Whether this camera is a perspective camera.*/
|
||||
inline bool IsPerspective() const { return isPerspective; }
|
||||
|
||||
/** Sets the type of this camera to perspective. */
|
||||
inline void SetPerspective() { isPerspective = true; isOrthographic = false; }
|
||||
|
||||
/** Retrieves whether the perspective camera defines an horizontal field of view.
|
||||
If the camera does not define the horizontal field of view, you can calculate
|
||||
it using the following formula: horizontal field of view = vertical field of view / aspect ratio.
|
||||
@return Whether the perspective camera defines an horizontal field of view. */
|
||||
inline bool HasHorizontalFov() const { return hasHorizontalView; }
|
||||
|
||||
/** Retrieves whether the perspective camera defines a vertical field of view.
|
||||
If the camera does not define the vertical field of view, you can calculate
|
||||
it using the following formula: vertical field of view = aspect ratio * horizontal field of view.
|
||||
@return Whether the perspective camera defines a vertical field of view. */
|
||||
inline bool HasVerticalFov() const { return hasVerticalView; }
|
||||
|
||||
/** Retrieves the horizontal field of view. Before retrieving this value,
|
||||
check whether the camera defines the horizontal field of view using the
|
||||
HasHorizontalFov function.
|
||||
@return The horizontal field of view, in degrees. */
|
||||
inline float& GetFovX() { return viewX; }
|
||||
inline const float& GetFovX() const { return viewX; } /**< See above. */
|
||||
|
||||
/** Retrieves the vertical field of view. Before retrieving this value,
|
||||
check whether the camera defines the vertical field of view using the
|
||||
HasVerticalFov function.
|
||||
@return The horizontal field of view, in degrees. */
|
||||
inline float& GetFovY() { return viewY; }
|
||||
inline const float& GetFovY() const { return viewY; } /**< See above. */
|
||||
|
||||
/** Sets the horizontal field of view value for this camera.
|
||||
@param fovX The new horizontal field of view, in degrees. */
|
||||
void SetFovX(float fovX);
|
||||
|
||||
/** Sets the vertical field of view value for this camera.
|
||||
@param fovY The new vertical field of view, in degrees. */
|
||||
void SetFovY(float fovY);
|
||||
|
||||
/** Retrieves whether this camera is an orthographic camera.
|
||||
@return Whether this camera is an orthographic camera. */
|
||||
inline bool IsOrthographic() const { return isOrthographic; }
|
||||
|
||||
/** Sets the type of this camera to orthographic. */
|
||||
inline void SetOrthographic() { isPerspective = false; isOrthographic = true; }
|
||||
|
||||
/** Retrieves whether the orthographic camera defines an horizontal magnification.
|
||||
If the camera does not define the horizontal magnification, you can calculate
|
||||
it using the following formula: horizontal magnification = vertical magnification / aspect ratio.
|
||||
@return Whether the orthographic camera defines an horizontal magnification. */
|
||||
inline bool HasHorizontalMag() const { return hasHorizontalView; }
|
||||
|
||||
/** Retrieves whether the perspective camera defines a vertical magnification.
|
||||
If the camera does not define the vertical magnification, you can calculate
|
||||
it using the following formula: vertical magnification = aspect ratio * horizontal magnification.
|
||||
@return Whether the perspective camera defines a vertical magnification. */
|
||||
inline bool HasVerticalMag() const { return hasVerticalView; }
|
||||
|
||||
/** Retrieves the horizontal magnification. Before retrieving this value,
|
||||
check whether the camera defines the horizontal magnification using the
|
||||
HasHorizontalMag function.
|
||||
@return The horizontal magnification. */
|
||||
inline float& GetMagX() { return viewX; }
|
||||
inline const float& GetMagX() const { return viewX; } /**< See above. */
|
||||
|
||||
/** Retrieves the vertical magnification. Before retrieving this value,
|
||||
check whether the camera defines the vertical magnification using the
|
||||
HasVerticalMag function.
|
||||
@return The vertical magnification. */
|
||||
inline float& GetMagY() { return viewY; }
|
||||
inline const float& GetMagY() const { return viewY; } /**< See above. */
|
||||
|
||||
/** Sets the horizontal magnification for this camera.
|
||||
@param magX The new horizontal magnification, in degrees. */
|
||||
inline void SetMagX(float magX) { return SetFovX(magX); }
|
||||
|
||||
/** Sets the vertical magnification value for this camera.
|
||||
@param magY The new vertical magnification, in degrees. */
|
||||
inline void SetMagY(float magY) { return SetFovY(magY); }
|
||||
|
||||
/** Retrieves the near-z value for this camera.
|
||||
The near-z value represent how close the near-clip
|
||||
plane of the view frustrum is. For orthographic cameras,
|
||||
this value is solely used for depth-buffering.
|
||||
@return The near-z value for this camera. */
|
||||
inline float& GetNearZ() { return nearZ; }
|
||||
inline const float& GetNearZ() const { return nearZ; } /**< See above. */
|
||||
|
||||
/** Retrieves the far-z value for this camera. The far-z value represent
|
||||
how close the far-clip plane of the view frustrum is.
|
||||
For orthographic cameras, this value is solely used for depth-buffering.
|
||||
@return The far-z value for this camera. */
|
||||
inline float& GetFarZ() { return farZ; }
|
||||
inline const float& GetFarZ() const { return farZ; } /**< See above. */
|
||||
|
||||
/** Retrieves the aspect ratio for the view of this camera. Before using this value,
|
||||
check if there are only one of the horizontal and vertical view ratios.
|
||||
If there are both of the view ratios provided for the camera, you will
|
||||
need to calculate the aspect ratio using the following formula:
|
||||
aspect ratio = vertical field of view / horizontal field of view.
|
||||
@return The view aspect ratio. */
|
||||
inline float& GetAspectRatio() { return aspectRatio; }
|
||||
inline const float& GetAspectRatio() const { return aspectRatio; } /**< See above. */
|
||||
|
||||
/** Sets the near-z value for this camera.
|
||||
The near-z value represent how close the near-clip
|
||||
plane of the view frustrum is. For orthographic cameras,
|
||||
this value is solely used for depth-buffering.
|
||||
@param _nearZ A valid near-z value. No check is made to verify that the
|
||||
near-z value is greather than the far-z value.*/
|
||||
inline void SetNearZ(float _nearZ) { nearZ = _nearZ; }
|
||||
|
||||
/** Sets the far-z value for this camera. The far-z value represent
|
||||
how close the far-clip plane of the view frustrum is.
|
||||
For orthographic cameras, this value is solely used for depth-buffering.
|
||||
@param _farZ A valid far-z value. No check is made to verify that the
|
||||
far-z value is greather than the near-z value.*/
|
||||
inline void SetFarZ(float _farZ) { farZ = _farZ; }
|
||||
|
||||
/** Sets the aspect ratio for the view of this camera.
|
||||
@param aspectRatio The new view aspect ratio. */
|
||||
void SetAspectRatio(float aspectRatio);
|
||||
|
||||
/** Retrieves whether the camera provides aperture information. This information is specific
|
||||
to COLLADA documents exported from ColladaMaya.
|
||||
@return Whether the camera provides aperture information. */
|
||||
inline bool HasAperture() const { return hasAperture; }
|
||||
|
||||
/** Retrieves the vertical aperture of the camera. This information is specific to
|
||||
COLLADA documents exported from ColladaMaya.
|
||||
@return The vertical aperture of the camera. */
|
||||
inline float& GetVerticalAperture() { return verticalAperture; }
|
||||
inline const float& GetVerticalAperture() const { return verticalAperture; } /**< See above. */
|
||||
|
||||
/** Retrieves the horizontal aperture of the camera. This information is specific to
|
||||
COLLADA documents exported from ColladaMaya.
|
||||
@return The horizontal aperture of the camera. */
|
||||
inline float& GetHorizontalAperture() { return horizontalAperture; }
|
||||
inline const float& GetHorizontalAperture() const { return horizontalAperture; } /**< See above. */
|
||||
|
||||
/** Retrieves the lens squeeze of the camera. This information is specific to
|
||||
COLLADA documents exported from ColladaMaya. The lens squeeze of the camera
|
||||
is a multiplier that acts directly on the horizontal aperture, following this
|
||||
formula: real horizontal aperture = given horizontal aperture * lens squeeze.
|
||||
@return The lens squeeze of the camera. */
|
||||
inline float& GetLensSqueeze() { return lensSqueeze; }
|
||||
inline const float& GetLensSqueeze() const { return lensSqueeze; } /**< See above. */
|
||||
|
||||
/** Sets the vertical aperture of the camera.
|
||||
@param aperture The vertical aperture of the camera. */
|
||||
inline void SetVerticalAperture(float aperture) { verticalAperture = aperture; hasAperture = true; }
|
||||
|
||||
/** Sets the horizontal aperture of the camera.
|
||||
@param aperture The horizontal aperture of the camera. */
|
||||
inline void SetHorizontalAperture(float aperture) { horizontalAperture = aperture; hasAperture = true; }
|
||||
|
||||
/** Sets the lens squeeze of the camera.
|
||||
@param factor The lense squeeze of the camera. */
|
||||
inline void SetLensSqueeze(float factor) { lensSqueeze = factor; }
|
||||
|
||||
/** [INTERNAL] Reads in the \<camera\> element from a given COLLADA XML tree node.
|
||||
@param cameraNode A COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the camera.*/
|
||||
FUStatus LoadFromXML(xmlNode* cameraNode);
|
||||
|
||||
/** [INTERNAL] Writes out the \<camera\> element to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the geometry information.
|
||||
@return The created XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
#endif // _FCD_CAMERA_H_
|
||||
|
||||
123
Extras/FCollada/FCDocument/FCDController.cpp
Normal file
123
Extras/FCollada/FCDocument/FCDController.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDController.h"
|
||||
#include "FCDocument/FCDSkinController.h"
|
||||
#include "FCDocument/FCDMorphController.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
using namespace FUDaeParser;
|
||||
|
||||
FCDController::FCDController(FCDocument* document) : FCDEntity(document, "Controller")
|
||||
{
|
||||
skinController = NULL;
|
||||
morphController = NULL;
|
||||
}
|
||||
|
||||
FCDController::~FCDController()
|
||||
{
|
||||
SAFE_DELETE(skinController);
|
||||
SAFE_DELETE(morphController);
|
||||
}
|
||||
|
||||
|
||||
// Sets the type of this controller to a skin controller.
|
||||
FCDSkinController* FCDController::CreateSkinController()
|
||||
{
|
||||
SAFE_DELETE(skinController);
|
||||
SAFE_DELETE(morphController);
|
||||
skinController = new FCDSkinController(GetDocument(), this);
|
||||
return skinController;
|
||||
}
|
||||
|
||||
// Sets the type of this controller to a morph controller.
|
||||
FCDMorphController* FCDController::CreateMorphController()
|
||||
{
|
||||
SAFE_DELETE(skinController);
|
||||
SAFE_DELETE(morphController);
|
||||
morphController = new FCDMorphController(GetDocument(), this);
|
||||
return morphController;
|
||||
}
|
||||
|
||||
FCDEntity* FCDController::GetBaseTarget()
|
||||
{
|
||||
if (skinController != NULL) return skinController->GetTarget();
|
||||
else if (morphController != NULL) return morphController->GetBaseTarget();
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
const FCDEntity* FCDController::GetBaseTarget() const
|
||||
{
|
||||
if (skinController != NULL) return skinController->GetTarget();
|
||||
else if (morphController != NULL) return morphController->GetBaseTarget();
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
// Load this controller from a Collada <controller> node
|
||||
FUStatus FCDController::LoadFromXML(xmlNode* controllerNode)
|
||||
{
|
||||
FUStatus status = FCDEntity::LoadFromXML(controllerNode);
|
||||
if (!status) return status;
|
||||
if (!IsEquivalent(controllerNode->name, DAE_CONTROLLER_ELEMENT))
|
||||
{
|
||||
return status.Warning(FS("Unexpected node in controller library: <") + TO_FSTRING((const char*) controllerNode->name) + FC(">."), controllerNode->line);
|
||||
}
|
||||
|
||||
// COLLADA 1.3 backward compatiblity: read in the 'target' attribute
|
||||
targetId = ReadNodeProperty(controllerNode, DAE_TARGET_ATTRIBUTE);
|
||||
|
||||
// Find the <skin> or <morph> element and process it
|
||||
xmlNode* skinNode = FindChildByType(controllerNode, DAE_CONTROLLER_SKIN_ELEMENT);
|
||||
xmlNode* morphNode = FindChildByType(controllerNode, DAE_CONTROLLER_MORPH_ELEMENT);
|
||||
if (skinNode != NULL && morphNode != NULL)
|
||||
{
|
||||
status.Warning(FS("A controller cannot be both a skin and a morpher: ") + TO_FSTRING(GetDaeId()), controllerNode->line);
|
||||
}
|
||||
if (skinNode != NULL)
|
||||
{
|
||||
// Create and parse in the skin controller
|
||||
FCDSkinController* controller = CreateSkinController();
|
||||
status.AppendStatus(controller->LoadFromXML(skinNode));
|
||||
}
|
||||
else if (morphNode != NULL)
|
||||
{
|
||||
// Create and parse in the morph controller
|
||||
FCDMorphController* controller = CreateMorphController();
|
||||
status.AppendStatus(controller->LoadFromXML(morphNode));
|
||||
}
|
||||
else
|
||||
{
|
||||
status.Warning(FS("No base type element, <skin> or <morph>, found for controller: ") + TO_FSTRING(GetDaeId()), controllerNode->line);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Write out this controller to a COLLADA xml node tree
|
||||
xmlNode* FCDController::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* controllerNode = FCDEntity::WriteToEntityXML(parentNode, DAE_CONTROLLER_ELEMENT);
|
||||
if (skinController != NULL) skinController->WriteToXML(controllerNode);
|
||||
if (morphController != NULL) morphController->WriteToXML(controllerNode);
|
||||
FCDEntity::WriteToExtraXML(controllerNode);
|
||||
return controllerNode;
|
||||
}
|
||||
|
||||
// Link this controller to the rest of the document: joints/base geometry...
|
||||
FUStatus FCDController::Link()
|
||||
{
|
||||
FUStatus status;
|
||||
|
||||
// Link the controller
|
||||
if (skinController != NULL) status.AppendStatus(skinController->Link());
|
||||
if (morphController != NULL) status.AppendStatus(morphController->Link());
|
||||
return status;
|
||||
}
|
||||
124
Extras/FCollada/FCDocument/FCDController.h
Normal file
124
Extras/FCollada/FCDocument/FCDController.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDController.h
|
||||
This file contains the FCDController class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_CONTROLLER_H_
|
||||
#define _FCD_CONTROLLER_H_
|
||||
|
||||
#include "FCDocument/FCDEntity.h"
|
||||
|
||||
class FCDocument;
|
||||
class FCDSkinController;
|
||||
class FCDMorphController;
|
||||
|
||||
/**
|
||||
A generic COLLADA controller.
|
||||
A COLLADA controller is used to influence a mesh.
|
||||
COLLADA defines two types of controller:
|
||||
skins (FCDSkinController) and morphers (FCDMorphController).
|
||||
|
||||
@ingroup FCDGeometry
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDController : public FCDEntity
|
||||
{
|
||||
private:
|
||||
string targetId; // COLLADA 1.3 backward compatibility
|
||||
|
||||
FCDSkinController* skinController;
|
||||
FCDMorphController* morphController;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDLibrary::AddEntity function.
|
||||
@param document The COLLADA document that owns the controller. */
|
||||
FCDController(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDLibrary::ReleaseEntity function. */
|
||||
virtual ~FCDController();
|
||||
|
||||
/** Retrieves the entity class type.
|
||||
This function is a part of the FCDEntity interface.
|
||||
@return The entity class type: CONTROLLER. */
|
||||
virtual Type GetType() const { return CONTROLLER; };
|
||||
|
||||
/** Retrieves whether this controller is a skin controller.
|
||||
@return Whether this controller is a skin controller. */
|
||||
bool HasSkinController() const { return skinController != NULL; }
|
||||
|
||||
/** Retrieves whether this controller is a morph controller.
|
||||
@return Whether this controller is a morph controller. */
|
||||
bool HasMorphController() const { return morphController != NULL; }
|
||||
|
||||
/** Sets the type of this controller to a skin controller.
|
||||
This function will release any previously created morpher or skin.
|
||||
@return The new skin controller. */
|
||||
FCDSkinController* CreateSkinController();
|
||||
|
||||
/** Sets the type of this controller to a morph controller.
|
||||
This function will release any previously created morpher or skin.
|
||||
@return The new morph controller. */
|
||||
FCDMorphController* CreateMorphController();
|
||||
|
||||
/** Retrieves the skin controller.
|
||||
This pointer is only valid for skins. To verify that this is a skin,
|
||||
check the HasSkinController function.
|
||||
@return The skin controller. This pointer will be NULL, if the controller
|
||||
is not a skin. */
|
||||
FCDSkinController* GetSkinController() { return skinController; }
|
||||
const FCDSkinController* GetSkinController() const { return skinController; } /**< See above. */
|
||||
|
||||
/** Retrieves the morph controller.
|
||||
This pointer is only valid for skins. To verify that this is a morpher,
|
||||
check the HasMorphController function.
|
||||
@return The morph controller. This pointer will be NULL, if the controller
|
||||
is not a morpher. */
|
||||
FCDMorphController* GetMorphController() { return morphController; }
|
||||
const FCDMorphController* GetMorphController() const { return morphController; } /**< See above. */
|
||||
|
||||
/** Retrieves the base target entity for this controller.
|
||||
The base target entity may be another controller or a geometry entity.
|
||||
To change the base target, use the FCDMorphController::SetBaseTarget
|
||||
or the FCDSkinController::SetTarget functions.
|
||||
@return The base target entity. This pointer will be NULL, if no base target is defined. */
|
||||
FCDEntity* GetBaseTarget();
|
||||
const FCDEntity* GetBaseTarget() const; /**< See above. */
|
||||
|
||||
/** [INTERNAL] Retrieves the COLLADA id of the target entity.
|
||||
This value is only useful for COLLADA 1.3 backward compatibility.
|
||||
For more recent COLLADA documents, this value is unused.
|
||||
@return The COLLADA id of the target entity. */
|
||||
const string& GetTargetId() const { return targetId; }
|
||||
|
||||
/** [INTERNAL] Reads in the \<controller\> element from a given COLLADA XML tree node.
|
||||
@param controllerNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the controller.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* controllerNode);
|
||||
|
||||
/** [INTERNAL] Writes out the \<controller\> element to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the controller information.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
|
||||
/** [INTERNAL] Links the controller entities with their many targets/influences.
|
||||
This function is executed for all the controllers, after the scene graph has been imported.
|
||||
It is mainly used to link the skin and its bones.
|
||||
@return The status of the linkage.*/
|
||||
FUStatus Link();
|
||||
};
|
||||
|
||||
#endif // _FCD_CONTROLLER_H_
|
||||
|
||||
268
Extras/FCollada/FCDocument/FCDEffect.cpp
Normal file
268
Extras/FCollada/FCDocument/FCDEffect.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDAnimated.h"
|
||||
#include "FCDocument/FCDEffect.h"
|
||||
#include "FCDocument/FCDEffectStandard.h"
|
||||
#include "FCDocument/FCDEffectProfileFX.h"
|
||||
#include "FCDocument/FCDEffectParameter.h"
|
||||
#include "FCDocument/FCDEffectParameterFactory.h"
|
||||
#include "FCDocument/FCDEffectParameterList.h"
|
||||
#include "FCDocument/FCDLibrary.h"
|
||||
#include "FCDocument/FCDImage.h"
|
||||
#include "FUtils/FUStringConversion.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDEffect::FCDEffect(FCDocument* document) : FCDEntity(document, "Effect")
|
||||
{
|
||||
parameters = new FCDEffectParameterList(GetDocument(), true);
|
||||
}
|
||||
|
||||
FCDEffect::~FCDEffect()
|
||||
{
|
||||
SAFE_DELETE(parameters);
|
||||
CLEAR_POINTER_VECTOR(profiles);
|
||||
}
|
||||
|
||||
void FCDEffect::AddParameter(FCDEffectParameter* parameter)
|
||||
{
|
||||
parameters->push_back(parameter);
|
||||
}
|
||||
|
||||
// Flatten this effect: trickling down all the parameters to the technique level
|
||||
void FCDEffect::Flatten()
|
||||
{
|
||||
for (FCDEffectParameterList::iterator itP = parameters->begin(); itP != parameters->end(); ++itP)
|
||||
{
|
||||
FCDEffectParameterList generators;
|
||||
if ((*itP)->IsModifier())
|
||||
{
|
||||
// Overwrite the generators
|
||||
FindParametersByReference((*itP)->GetReference(), generators);
|
||||
for (FCDEffectParameterList::iterator itQ = generators.begin(); itQ != generators.end(); ++itQ)
|
||||
{
|
||||
if ((*itP) != (*itQ))
|
||||
{
|
||||
(*itP)->Overwrite(*itQ);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add this parameter to hierarchies below
|
||||
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
|
||||
{
|
||||
if ((*itR)->GetType() != FUDaeProfileType::COMMON)
|
||||
{
|
||||
((FCDEffectProfileFX*) (*itR))->AddParameter((*itP)->Clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CLEAR_POINTER_VECTOR(*parameters);
|
||||
|
||||
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
|
||||
{
|
||||
(*itR)->Flatten();
|
||||
}
|
||||
}
|
||||
|
||||
// Search for a profile of the given type
|
||||
FCDEffectProfile* FCDEffect::FindProfile(FUDaeProfileType::Type type)
|
||||
{
|
||||
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
|
||||
{
|
||||
if ((*itR)->GetType() == type) return (*itR);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const FCDEffectProfile* FCDEffect::FindProfile(FUDaeProfileType::Type type) const
|
||||
{
|
||||
for (FCDEffectProfileList::const_iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
|
||||
{
|
||||
if ((*itR)->GetType() == type) return (*itR);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create a new effect profile.
|
||||
FCDEffectProfile* FCDEffect::AddProfile(FUDaeProfileType::Type type)
|
||||
{
|
||||
// Delete any old profile of the same type
|
||||
FCDEffectProfile* profile = FindProfile(type);
|
||||
if (profile != NULL)
|
||||
{
|
||||
ReleaseProfile(profile);
|
||||
profile = NULL;
|
||||
}
|
||||
|
||||
// Create the correct profile for this type.
|
||||
if (type == FUDaeProfileType::COMMON) profile = new FCDEffectStandard(GetDocument(), this);
|
||||
else profile = new FCDEffectProfileFX(GetDocument(), this, type);
|
||||
|
||||
profiles.push_back(profile);
|
||||
return profile;
|
||||
}
|
||||
|
||||
// Releases the effect profile.
|
||||
void FCDEffect::ReleaseProfile(FCDEffectProfile* profile)
|
||||
{
|
||||
FCDEffectProfileList::iterator itR = std::find(profiles.begin(), profiles.end(), profile);
|
||||
if (itR != profiles.end())
|
||||
{
|
||||
delete *itR;
|
||||
profiles.erase(itR);
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the effect parameter with the correct semantic, in order to bind/set its value
|
||||
FCDEffectParameter* FCDEffect::FindParameterBySemantic(const string& semantic)
|
||||
{
|
||||
FCDEffectParameter* p = parameters->FindSemantic(semantic);
|
||||
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end() && p == NULL; ++itR)
|
||||
{
|
||||
p = (*itR)->FindParameterBySemantic(semantic);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void FCDEffect::FindParametersBySemantic(const string& semantic, FCDEffectParameterList& _parameters)
|
||||
{
|
||||
parameters->FindSemantic(semantic, _parameters);
|
||||
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
|
||||
{
|
||||
(*itR)->FindParametersBySemantic(semantic, _parameters);
|
||||
}
|
||||
}
|
||||
|
||||
void FCDEffect::FindParametersByReference(const string& reference, FCDEffectParameterList& _parameters)
|
||||
{
|
||||
parameters->FindReference(reference, _parameters);
|
||||
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
|
||||
{
|
||||
(*itR)->FindParametersBySemantic(reference, _parameters);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse COLLADA document's <effect> element
|
||||
// Also parses the <material> element for COLLADA 1.3 backward compatibility
|
||||
FUStatus FCDEffect::LoadFromXML(xmlNode* effectNode)
|
||||
{
|
||||
FUStatus status = FCDEntity::LoadFromXML(effectNode);
|
||||
if (!status) return status;
|
||||
|
||||
CLEAR_POINTER_VECTOR(*parameters);
|
||||
|
||||
// COLLADA 1.3 backward compatibility: look for a <material><shader> node and parse this into a standard effect.
|
||||
if (IsEquivalent(effectNode->name, DAE_MATERIAL_ELEMENT))
|
||||
{
|
||||
xmlNode* shaderNode = FindChildByType(effectNode, DAE_SHADER_ELEMENT);
|
||||
if (shaderNode != NULL)
|
||||
{
|
||||
FCDEffectProfile* profile = AddProfile(FUDaeProfileType::COMMON);
|
||||
status.AppendStatus(profile->LoadFromXML(shaderNode));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Accept solely <effect> elements at this point.
|
||||
if (!IsEquivalent(effectNode->name, DAE_EFFECT_ELEMENT))
|
||||
{
|
||||
return status.Warning(FS("Unknown element in effect library."), effectNode->line);
|
||||
}
|
||||
|
||||
for (xmlNode* child = effectNode->children; child != NULL; child = child->next)
|
||||
{
|
||||
if (child->type != XML_ELEMENT_NODE) continue;
|
||||
|
||||
if (IsEquivalent(child->name, DAE_IMAGE_ELEMENT))
|
||||
{
|
||||
FCDImage* image = GetDocument()->GetImageLibrary()->AddEntity();
|
||||
status.AppendStatus(image->LoadFromXML(child));
|
||||
images.push_back(image);
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_SETPARAM_ELEMENT) || IsEquivalent(child->name, DAE_FXCMN_NEWPARAM_ELEMENT))
|
||||
{
|
||||
AddParameter(FCDEffectParameterFactory::LoadFromXML(GetDocument(), child, &status));
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_EXTRA_ELEMENT))
|
||||
{
|
||||
// Valid element.. but not processed.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for a valid profile element.
|
||||
FUDaeProfileType::Type type = FUDaeProfileType::FromString((const char*) child->name);
|
||||
if (type != FUDaeProfileType::UNKNOWN)
|
||||
{
|
||||
FCDEffectProfile* profile = AddProfile(type);
|
||||
status.AppendStatus(profile->LoadFromXML(child));
|
||||
}
|
||||
else
|
||||
{
|
||||
status.Warning(FS("Unsupported profile or unknown element in effect: ") + TO_FSTRING(GetDaeId()), child->line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Returns a copy of the effect, with all the animations/textures attached
|
||||
FCDEffect* FCDEffect::Clone()
|
||||
{
|
||||
FCDEffect* clone = new FCDEffect(GetDocument());
|
||||
FCDEntity::Clone(clone);
|
||||
|
||||
for (FCDEffectProfileList::iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
|
||||
{
|
||||
FCDEffectProfile* p = (*itR)->Clone(clone);
|
||||
clone->profiles.push_back(p);
|
||||
}
|
||||
|
||||
for (FCDEffectImageList::iterator itI = images.begin(); itI != images.end(); ++itI)
|
||||
{
|
||||
FCDImage* p = *itI;
|
||||
clone->images.push_back(p);
|
||||
}
|
||||
|
||||
SAFE_DELETE(clone->parameters);
|
||||
clone->parameters = parameters->Clone();
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Write out the <material> element to the COLLADA xml tree
|
||||
xmlNode* FCDEffect::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* effectNode = WriteToEntityXML(parentNode, DAE_EFFECT_ELEMENT);
|
||||
|
||||
// Write out the parameters
|
||||
for (FCDEffectParameterList::iterator itP = parameters->begin(); itP != parameters->end(); ++itP)
|
||||
{
|
||||
(*itP)->WriteToXML(effectNode);
|
||||
}
|
||||
|
||||
// Write out the profiles
|
||||
for (FCDEffectProfileList::const_iterator itR = profiles.begin(); itR != profiles.end(); ++itR)
|
||||
{
|
||||
(*itR)->WriteToXML(effectNode);
|
||||
}
|
||||
|
||||
FCDEffect::WriteToExtraXML(effectNode);
|
||||
return effectNode;
|
||||
}
|
||||
179
Extras/FCollada/FCDocument/FCDEffect.h
Normal file
179
Extras/FCollada/FCDocument/FCDEffect.h
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDEffect.h
|
||||
This file contains the FCDEffect class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_EFFECT_H_
|
||||
#define _FCD_EFFECT_H_
|
||||
|
||||
#include "FUtils/FUDaeEnum.h"
|
||||
#include "FCDocument/FCDEntity.h"
|
||||
|
||||
class FCDocument;
|
||||
class FCDEffectStandard;
|
||||
class FCDEffectParameter;
|
||||
class FCDEffectProfile;
|
||||
class FCDEffectParameterList;
|
||||
|
||||
/**
|
||||
@defgroup FCDEffect COLLADA Effect Classes [ColladaFX]
|
||||
*/
|
||||
|
||||
class FCDEffectProfile;
|
||||
class FCDEffectParameterList;
|
||||
class FCDImage;
|
||||
|
||||
/** A dynamically-sized array of effect profiles. */
|
||||
typedef vector<FCDEffectProfile*> FCDEffectProfileList;
|
||||
typedef vector<FCDImage*> FCDEffectImageList;
|
||||
|
||||
/**
|
||||
A COLLADA effect.
|
||||
|
||||
A COLLADA effect is one of many abstraction level that defines how
|
||||
to render mesh polygon sets. It contains one or more rendering profile
|
||||
that the application can choose to support. In theory, all the rendering
|
||||
profiles should reach the same render output, using different
|
||||
rendering technologies.
|
||||
|
||||
An effect may also declare new general purpose parameters that are common
|
||||
to all the profiles.
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffect : public FCDEntity
|
||||
{
|
||||
private:
|
||||
FCDEffectProfileList profiles;
|
||||
FCDEffectParameterList* parameters;
|
||||
FCDEffectImageList images;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead use the FCDMaterialLibrary::AddEffect function.
|
||||
@param document The COLLADA document that owns this effect. */
|
||||
FCDEffect(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead use the FCDMaterialLibrary::ReleaseEffect function. */
|
||||
virtual ~FCDEffect();
|
||||
|
||||
/** Retrieves the type for this entity class.
|
||||
This function is a part of the FCDEntity interface.
|
||||
@return The entity type: EFFECT. */
|
||||
virtual Type GetType() const { return FCDEntity::EFFECT; }
|
||||
|
||||
/** Retrieves the number of profiles contained within the effect.
|
||||
@return The number of profiles within the effect. */
|
||||
size_t GetProfileCount() const { return profiles.size(); }
|
||||
|
||||
/** Retrieves a profile contained within the effect.
|
||||
@param index The index of the profile.
|
||||
@return The profile. This pointer will be NULL, if the given index is out-of-bounds. */
|
||||
FCDEffectProfile* GetProfile(size_t index) { FUAssert(index < GetProfileCount(), return NULL); return profiles.at(index); }
|
||||
const FCDEffectProfile* GetProfile(size_t index) const { FUAssert(index < GetProfileCount(), return NULL); return profiles.at(index); } /**< See above. */
|
||||
|
||||
/** Retrieves the list of the profiles contained within the effect.
|
||||
@return The list of effect profiles. */
|
||||
FCDEffectProfileList& GetProfiles() { return profiles; }
|
||||
const FCDEffectProfileList& GetProfiles() const { return profiles; } /**< See above. */
|
||||
|
||||
/** Retrieves the profile for a specific profile type.
|
||||
There should only be one profile of each type within an effect. This
|
||||
function allows you to retrieve the profile for a given type.
|
||||
@param type The profile type.
|
||||
@return The profile of this type. This pointer will be NULL if the effect
|
||||
does not have any profile of this type. */
|
||||
FCDEffectProfile* FindProfile(FUDaeProfileType::Type type);
|
||||
const FCDEffectProfile* FindProfile(FUDaeProfileType::Type type) const; /**< See above. */
|
||||
|
||||
/** Retrieves whether the effect contains a profile of the given type.
|
||||
@param type The profile type.
|
||||
@return Whether the effect has a profile of this type. */
|
||||
inline bool HasProfile(FUDaeProfileType::Type type) const { return FindProfile(type) != NULL; }
|
||||
|
||||
/** Creates a profile of the given type.
|
||||
If a profile of this type already exists, it will be released, as
|
||||
a COLLADA effect should only contain one profile of each type.
|
||||
@param type The profile type.
|
||||
@return The new effect profile. */
|
||||
FCDEffectProfile* AddProfile(FUDaeProfileType::Type type);
|
||||
|
||||
/** Releases the given effect profile.
|
||||
@param profile The effect profile. */
|
||||
void ReleaseProfile(FCDEffectProfile* profile);
|
||||
|
||||
/** Retrieves the list of common effect parameters declared at the effect level.
|
||||
According to the COLLADA 1.4 schema, you should expect only parameter generators
|
||||
at this abstraction level.
|
||||
@return The list of effect parameters. */
|
||||
FCDEffectParameterList* GetParameters() { return parameters; }
|
||||
const FCDEffectParameterList* GetParameters() const { return parameters; } /**< See above. */
|
||||
|
||||
/** [INTERNAL] Inserts an existing parameter into the list of common effect parameters
|
||||
at this abstraction level. This function is used during the flattening of a material.
|
||||
@param parameter The effect parameter to insert. */
|
||||
void AddParameter(FCDEffectParameter* parameter);
|
||||
|
||||
/** Retrieves a common effect parameter. Looks for the common effect parameter with the correct
|
||||
semantic, in order to bind or override its value.
|
||||
This function searches through the effect and the level of abstractions below.
|
||||
@param semantic The effect parameter semantic to match.
|
||||
@return The first effect parameter that matches the semantic.
|
||||
This pointer will be NULL if no effect parameter matches the given semantic. */
|
||||
FCDEffectParameter* FindParameterBySemantic(const string& semantic);
|
||||
|
||||
/** Retrieves a subset of the common effect parameter list.
|
||||
Look for the effect parameter generators with the correct semantic.
|
||||
This function searches through the effect and the level of abstractions below.
|
||||
@param semantic The effect parameter semantic to match.
|
||||
@param parameters The list of parameters to fill in. This list is not cleared. */
|
||||
void FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters);
|
||||
|
||||
/** Retrieves a subset of the common effect parameter list.
|
||||
Look for the effect parameter generators with the correct reference.
|
||||
This function searches through the effect and the level of abstractions below.
|
||||
@param reference The effect parameter reference to match. In the case of effect
|
||||
parameter generators, the reference is replaced by the sub-id.
|
||||
@param parameters The list of parameters to fill in. This list is not cleared. */
|
||||
void FindParametersByReference(const string& reference, FCDEffectParameterList& parameters);
|
||||
|
||||
/** Clones the effect object. Everything is cloned, including the effect parameter
|
||||
and their animations. You will need release the cloned effect directly, by deleting the pointer.
|
||||
@return The cloned effect object. You will must delete this pointer. */
|
||||
FCDEffect* Clone();
|
||||
|
||||
/** [INTERNAL] Flattens the effect, pushing all the common effect parameters
|
||||
into to the effect technique level of abstraction. To correctly flatten a
|
||||
material, use the FCDMaterialInstance::FlattenMaterial function. */
|
||||
void Flatten();
|
||||
|
||||
/** [INTERNAL] Reads in the \<effect\> element from a given COLLADA XML tree node.
|
||||
@param effectNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the effect.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* effectNode);
|
||||
|
||||
/** [INTERNAL] Writes out the \<effect\> element to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the effect.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
|
||||
/** Retrieves the list of the images contained within the effect.
|
||||
@return The list of effect images. */
|
||||
FCDEffectImageList& GetImages() { return images; }
|
||||
const FCDEffectImageList& GetImages() const { return images; } /**< See above. */
|
||||
};
|
||||
|
||||
#endif // _FCD_MATERIAL_H_
|
||||
88
Extras/FCollada/FCDocument/FCDEffectCode.cpp
Normal file
88
Extras/FCollada/FCDocument/FCDEffectCode.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDEffectCode.h"
|
||||
#include "FUtils/FUFileManager.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDEffectCode::FCDEffectCode(FCDocument* document) : FCDObject(document, "FCDEffectCode")
|
||||
{
|
||||
type = INCLUDE;
|
||||
}
|
||||
|
||||
FCDEffectCode::~FCDEffectCode()
|
||||
{
|
||||
}
|
||||
|
||||
// Clone
|
||||
FCDEffectCode* FCDEffectCode::Clone() const
|
||||
{
|
||||
FCDEffectCode* clone = new FCDEffectCode(GetDocument());
|
||||
clone->type = type;
|
||||
clone->sid = sid;
|
||||
clone->filename = filename;
|
||||
clone->code = code;
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Read in the code/include from the xml node tree
|
||||
FUStatus FCDEffectCode::LoadFromXML(xmlNode* codeNode)
|
||||
{
|
||||
FUStatus status;
|
||||
if (IsEquivalent(codeNode->name, DAE_FXCMN_INCLUDE_ELEMENT)) type = INCLUDE;
|
||||
else if (IsEquivalent(codeNode->name, DAE_FXCMN_CODE_ELEMENT)) type = CODE;
|
||||
else
|
||||
{
|
||||
return status.Fail(FS("Unknown effect code type."), codeNode->line);
|
||||
}
|
||||
|
||||
// Read in the code identifier and the actual code or filename
|
||||
sid = ReadNodeProperty(codeNode, DAE_SID_ATTRIBUTE);
|
||||
if (type == INCLUDE && sid.empty())
|
||||
{
|
||||
status.Warning(FS("<code>/<include> nodes must have an 'sid' attribute to identify them."), codeNode->line);
|
||||
}
|
||||
if (type == INCLUDE)
|
||||
{
|
||||
filename = ReadNodeUrl(codeNode).prefix;
|
||||
filename = GetDocument()->GetFileManager()->GetFilePath(filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
code = TO_FSTRING(ReadNodeContentDirect(codeNode));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Write out the code/include to the COLLADA xml node tree
|
||||
xmlNode* FCDEffectCode::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
// In COLLADA 1.4, the 'sid' and 'url' attributes are required.
|
||||
// In the case of the sub-id, save it for later use.
|
||||
xmlNode* codeNode;
|
||||
switch (type)
|
||||
{
|
||||
case CODE:
|
||||
codeNode = AddChild(parentNode, DAE_FXCMN_CODE_ELEMENT, code);
|
||||
const_cast<FCDEffectCode*>(this)->sid = AddNodeSid(codeNode, !sid.empty() ? sid.c_str() : "code");
|
||||
break;
|
||||
|
||||
case INCLUDE:
|
||||
codeNode = AddChild(parentNode, DAE_FXCMN_INCLUDE_ELEMENT);
|
||||
const_cast<FCDEffectCode*>(this)->sid = AddNodeSid(codeNode, !sid.empty() ? sid.c_str() : "include");
|
||||
AddAttribute(codeNode, DAE_URL_ATTRIBUTE, filename);
|
||||
break;
|
||||
|
||||
default:
|
||||
codeNode = NULL;
|
||||
}
|
||||
return codeNode;
|
||||
}
|
||||
118
Extras/FCollada/FCDocument/FCDEffectCode.h
Normal file
118
Extras/FCollada/FCDocument/FCDEffectCode.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDEffectCode.h
|
||||
This file contains the FCDEffectCode class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_EFFECT_CODE_H_
|
||||
#define _FCD_EFFECT_CODE_H_
|
||||
|
||||
#include "FCDocument/FCDObject.h"
|
||||
|
||||
class FCDocument;
|
||||
|
||||
/**
|
||||
A COLLADA code inclusion.
|
||||
|
||||
Code inclusions come in two forms: file includes and inline code.
|
||||
For file includes, you will want to grab the filename of the file
|
||||
using the GetFilename function and for inline code, you can get
|
||||
the code directly through the GetCode function.
|
||||
|
||||
Code inclusions are referenced through sub-ids by the effect pass
|
||||
shaders. Regardless of the extension of the filename of file
|
||||
includes, the code inclusions' language is solely determined by
|
||||
the effect profile they belong to.
|
||||
*/
|
||||
class FCDEffectCode : public FCDObject
|
||||
{
|
||||
public:
|
||||
/** The list of support code inclusion types. */
|
||||
enum Type
|
||||
{
|
||||
INCLUDE, /** A file include. @see GetFilename */
|
||||
CODE /** Inlined code. @see GetCode */
|
||||
};
|
||||
|
||||
private:
|
||||
Type type;
|
||||
string sid;
|
||||
fstring code;
|
||||
fstring filename;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectProfile::AddCode
|
||||
or the FCDEffectTechnique::AddCode functions.
|
||||
@param document The COLLADA document that owns this code inclusion. */
|
||||
FCDEffectCode(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectProfile::ReleaseCode
|
||||
or the FCDEffectTechnique::ReleaseCode functions. */
|
||||
~FCDEffectCode();
|
||||
|
||||
/** Retrieves the form of the code inclusion.
|
||||
@return The form. */
|
||||
inline Type GetType() const { return type; }
|
||||
|
||||
/** Sets the form of the code inclusion.
|
||||
Changing the form of the code inclusion will not
|
||||
remove the inline code or the filename.
|
||||
@param _type The form. */
|
||||
inline void SetType(Type _type) { type = _type; }
|
||||
|
||||
/** Retrieves the sub-id of the code inclusion.
|
||||
Used to match the code inclusion within the effect pass shaders.
|
||||
@return The sub-id. */
|
||||
const string& GetSid() const { return sid; }
|
||||
|
||||
/** Sets the sub-id of the code inclusion.
|
||||
This value may change on export, as the sub-id must be unique within its scope.
|
||||
@param _sid The sub-id. */
|
||||
void SetSid(const string& _sid) { sid = _sid; }
|
||||
|
||||
/** Retrieves the inlined code.
|
||||
First verify that this code inclusion contains inlined code
|
||||
using the GetType function.
|
||||
@return The inlined code. */
|
||||
const fstring& GetCode() const { return code; }
|
||||
|
||||
/** Sets the inlined code.
|
||||
As a side-effect, calling this function forces the type of the code inclusion.
|
||||
@param _code The inlined code. */
|
||||
void SetCode(const fstring& _code) { code = _code; type = CODE; }
|
||||
|
||||
/** Retrieves the filename of the code file to open.
|
||||
First verify that this code inclusion contains a filename
|
||||
using the GetType function.
|
||||
@return The code filename. */
|
||||
const fstring& GetFilename() const { return filename; }
|
||||
|
||||
/** Sets the filename of the code file.
|
||||
As a side-effect, calling this function forces the type of the code inclusion.
|
||||
@param _filename The code filename. */
|
||||
void SetFilename(const fstring& _filename) { filename = _filename; type = INCLUDE; }
|
||||
|
||||
/** [INTERNAL] Clones the code inclusion.
|
||||
@return The cloned effect object. You will must delete this pointer. */
|
||||
FCDEffectCode* Clone() const;
|
||||
|
||||
/** [INTERNAL] Reads in the code inclusion from a given COLLADA XML tree node.
|
||||
Code inclusions cover the \<code\> element and the \<include\> element.
|
||||
@param codeNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the code inclusion.*/
|
||||
FUStatus LoadFromXML(xmlNode* codeNode);
|
||||
|
||||
/** [INTERNAL] Writes out the code inclusion to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the code inclusion.
|
||||
@return The created element XML tree node. */
|
||||
xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
#endif // _FCD_EFFECT_CODE_H_
|
||||
646
Extras/FCollada/FCDocument/FCDEffectParameter.cpp
Normal file
646
Extras/FCollada/FCDocument/FCDEffectParameter.cpp
Normal file
@@ -0,0 +1,646 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDAnimated.h"
|
||||
#include "FCDocument/FCDEffectPass.h"
|
||||
#include "FCDocument/FCDEffectProfile.h"
|
||||
#include "FCDocument/FCDEffectTechnique.h"
|
||||
#include "FCDocument/FCDEffectParameter.h"
|
||||
#include "FCDocument/FCDImage.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDEffectParameter::FCDEffectParameter(FCDocument* document) : FCDObject(document, "FCDEffectParameter")
|
||||
{
|
||||
isGenerator = true;
|
||||
isFragment = false;
|
||||
reference = "";
|
||||
semantic = "";
|
||||
bindSymbol = "";
|
||||
}
|
||||
|
||||
FCDEffectParameter::~FCDEffectParameter()
|
||||
{
|
||||
}
|
||||
|
||||
FUStatus FCDEffectParameter::LoadFromXML(xmlNode* parameterNode)
|
||||
{
|
||||
FUStatus status;
|
||||
|
||||
// This parameter is a generator if this is a <newparam> element. Otherwise, it modifies
|
||||
// an existing parameter (<bind>, <bind_semantic> or <setparam>.
|
||||
isGenerator = IsEquivalent(parameterNode->name, DAE_FXCMN_NEWPARAM_ELEMENT);
|
||||
if (isGenerator)
|
||||
{
|
||||
reference = ReadNodeProperty(parameterNode, DAE_SID_ATTRIBUTE);
|
||||
if (reference.empty())
|
||||
{
|
||||
return status.Warning(FS("No reference attribute on generator parameter."), parameterNode->line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reference = ReadNodeProperty(parameterNode, DAE_REF_ATTRIBUTE);
|
||||
if (reference.empty())
|
||||
{
|
||||
return status.Warning(FS("No reference attribute on modifier parameter."), parameterNode->line);
|
||||
}
|
||||
}
|
||||
|
||||
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_SEMANTIC_ELEMENT);
|
||||
if (valueNode != NULL)
|
||||
{
|
||||
semantic = ReadNodeContentDirect(valueNode);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Write out this ColladaFX parameter to the xml node tree
|
||||
xmlNode* FCDEffectParameter::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* parameterNode;
|
||||
if (isGenerator)
|
||||
{
|
||||
parameterNode = AddChild(parentNode, DAE_FXCMN_NEWPARAM_ELEMENT);
|
||||
if (!reference.empty()) AddAttribute(parameterNode, DAE_SID_ATTRIBUTE, reference);
|
||||
if (!semantic.empty()) AddChild(parameterNode, DAE_FXCMN_SEMANTIC_ELEMENT, semantic);
|
||||
}
|
||||
else
|
||||
{
|
||||
parameterNode = AddChild(parentNode, DAE_FXCMN_SETPARAM_ELEMENT);
|
||||
if (!reference.empty()) AddAttribute(parameterNode, DAE_REF_ATTRIBUTE, reference);
|
||||
}
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
void FCDEffectParameter::Clone(FCDEffectParameter* clone)
|
||||
{
|
||||
clone->bindSymbol = bindSymbol;
|
||||
clone->reference = reference;
|
||||
clone->semantic = semantic;
|
||||
clone->isFragment = isFragment;
|
||||
clone->isGenerator = isGenerator;
|
||||
}
|
||||
|
||||
// Flattening: overwrite the target parameter with this parameter
|
||||
void FCDEffectParameter::Overwrite(FCDEffectParameter* UNUSED(target))
|
||||
{
|
||||
// Do nothing on the base class, only values and animations should be overwritten
|
||||
}
|
||||
|
||||
FCDEffectParameterSampler::FCDEffectParameterSampler(FCDocument* document) : FCDEffectParameter(document)
|
||||
{
|
||||
samplerType = SAMPLER2D;
|
||||
}
|
||||
|
||||
FCDEffectParameterSampler::~FCDEffectParameterSampler()
|
||||
{
|
||||
}
|
||||
|
||||
// Clone
|
||||
FCDEffectParameter* FCDEffectParameterSampler::Clone()
|
||||
{
|
||||
FCDEffectParameterSampler* clone = new FCDEffectParameterSampler(GetDocument());
|
||||
FCDEffectParameter::Clone(clone);
|
||||
clone->surfaceSid = surfaceSid;
|
||||
clone->samplerType = samplerType;
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Flattening: overwrite the target parameter with this parameter
|
||||
void FCDEffectParameterSampler::Overwrite(FCDEffectParameter* target)
|
||||
{
|
||||
if (target->GetType() == SAMPLER)
|
||||
{
|
||||
FCDEffectParameterSampler* s = (FCDEffectParameterSampler*) target;
|
||||
if (samplerType == s->samplerType)
|
||||
{
|
||||
s->surfaceSid = surfaceSid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FUStatus FCDEffectParameterSampler::LoadFromXML(xmlNode* parameterNode)
|
||||
{
|
||||
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
|
||||
|
||||
// Find the sampler node
|
||||
xmlNode* samplerNode = NULL;
|
||||
for (xmlNode* child = parameterNode->children; child != NULL; child = child->next)
|
||||
{
|
||||
if (child->type != XML_ELEMENT_NODE) continue;
|
||||
|
||||
if (IsEquivalent(child->name, DAE_FXCMN_SAMPLER1D_ELEMENT)) { samplerType = SAMPLER1D; samplerNode = child; break; }
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLER2D_ELEMENT)) { samplerType = SAMPLER2D; samplerNode = child; break; }
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLER3D_ELEMENT)) { samplerType = SAMPLER3D; samplerNode = child; break; }
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLERCUBE_ELEMENT)) { samplerType = SAMPLERCUBE; samplerNode = child; break; }
|
||||
}
|
||||
|
||||
if (samplerNode == NULL)
|
||||
{
|
||||
return status.Warning(FS("Unable to find sampler node for sampler parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
|
||||
}
|
||||
|
||||
// Parse the source node
|
||||
xmlNode* sourceNode = FindChildByType(samplerNode, DAE_SOURCE_ELEMENT);
|
||||
surfaceSid = ReadNodeContentDirect(sourceNode);
|
||||
if (surfaceSid.empty())
|
||||
{
|
||||
return status.Fail(FS("Empty surface source value for sampler parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectParameterSampler::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
|
||||
const char* samplerName;
|
||||
switch(samplerType)
|
||||
{
|
||||
case SAMPLER1D: samplerName = DAE_FXCMN_SAMPLER1D_ELEMENT; break;
|
||||
case SAMPLER2D: samplerName = DAE_FXCMN_SAMPLER2D_ELEMENT; break;
|
||||
case SAMPLER3D: samplerName = DAE_FXCMN_SAMPLER3D_ELEMENT; break;
|
||||
case SAMPLERCUBE: samplerName = DAE_FXCMN_SAMPLERCUBE_ELEMENT; break;
|
||||
default: samplerName = DAEERR_UNKNOWN_ELEMENT; break;
|
||||
}
|
||||
xmlNode* samplerNode = AddChild(parameterNode, samplerName);
|
||||
if (!surfaceSid.empty()) AddChild(samplerNode, DAE_SOURCE_ELEMENT, surfaceSid);
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
FCDEffectParameterInt::FCDEffectParameterInt(FCDocument* document) : FCDEffectParameter(document) { value = 0; }
|
||||
FCDEffectParameterInt::~FCDEffectParameterInt()
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
|
||||
// Clone
|
||||
FCDEffectParameter* FCDEffectParameterInt::Clone()
|
||||
{
|
||||
FCDEffectParameterInt* clone = new FCDEffectParameterInt(GetDocument());
|
||||
FCDEffectParameter::Clone(clone);
|
||||
clone->value = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Flattening: overwrite the target parameter with this parameter
|
||||
void FCDEffectParameterInt::Overwrite(FCDEffectParameter* target)
|
||||
{
|
||||
if (target->GetType() == INTEGER)
|
||||
{
|
||||
FCDEffectParameterInt* s = (FCDEffectParameterInt*) target;
|
||||
s->value = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse in this ColladaFX integer from the document's XML node
|
||||
FUStatus FCDEffectParameterInt::LoadFromXML(xmlNode* parameterNode)
|
||||
{
|
||||
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
|
||||
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_INT_ELEMENT);
|
||||
const char* valueString = ReadNodeContentDirect(valueNode);
|
||||
if (valueString == NULL || *valueString == 0)
|
||||
{
|
||||
return status.Fail(FS("Bad value for float parameter in integer parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
|
||||
}
|
||||
value = FUStringConversion::ToInt32(valueString);
|
||||
return status;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectParameterInt::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
|
||||
AddChild(parameterNode, DAE_FXCMN_INT_ELEMENT, value);
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
// boolean type parameter
|
||||
FCDEffectParameterBool::FCDEffectParameterBool(FCDocument* document) : FCDEffectParameter(document)
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
|
||||
FCDEffectParameterBool::~FCDEffectParameterBool() {}
|
||||
|
||||
// Clone
|
||||
FCDEffectParameter* FCDEffectParameterBool::Clone()
|
||||
{
|
||||
FCDEffectParameterBool* clone = new FCDEffectParameterBool(GetDocument());
|
||||
FCDEffectParameter::Clone(clone);
|
||||
clone->value = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Flattening: overwrite the target parameter with this parameter
|
||||
void FCDEffectParameterBool::Overwrite(FCDEffectParameter* target)
|
||||
{
|
||||
if (target->GetType() == BOOLEAN)
|
||||
{
|
||||
FCDEffectParameterBool* s = (FCDEffectParameterBool*) target;
|
||||
s->value = value;
|
||||
}
|
||||
}
|
||||
|
||||
FUStatus FCDEffectParameterBool::LoadFromXML(xmlNode* parameterNode)
|
||||
{
|
||||
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
|
||||
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_BOOL_ELEMENT);
|
||||
const char* valueString = ReadNodeContentDirect(valueNode);
|
||||
if (valueString == NULL || *valueString == 0)
|
||||
{
|
||||
return status.Fail(FS("Bad value for boolean parameter in effect: ") + TO_FSTRING(GetReference()), parameterNode->line);
|
||||
}
|
||||
value = FUStringConversion::ToBoolean(valueString);
|
||||
return status;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectParameterBool::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
|
||||
AddChild(parameterNode, DAE_FXCMN_BOOL_ELEMENT, value);
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
// string type parameter
|
||||
FCDEffectParameterString::FCDEffectParameterString(FCDocument* document) : FCDEffectParameter(document)
|
||||
{
|
||||
value = "";
|
||||
}
|
||||
|
||||
FCDEffectParameterString::~FCDEffectParameterString()
|
||||
{
|
||||
}
|
||||
|
||||
// Clone
|
||||
FCDEffectParameter* FCDEffectParameterString::Clone()
|
||||
{
|
||||
FCDEffectParameterString* clone = new FCDEffectParameterString(GetDocument());
|
||||
FCDEffectParameter::Clone(clone);
|
||||
clone->value = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Flattening: overwrite the target parameter with this parameter
|
||||
void FCDEffectParameterString::Overwrite(FCDEffectParameter* target)
|
||||
{
|
||||
if (target->GetType() == STRING)
|
||||
{
|
||||
FCDEffectParameterString* s = (FCDEffectParameterString*) target;
|
||||
s->value = value;
|
||||
}
|
||||
}
|
||||
|
||||
FUStatus FCDEffectParameterString::LoadFromXML(xmlNode* parameterNode)
|
||||
{
|
||||
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
|
||||
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_STRING_ELEMENT);
|
||||
const char* valueString = ReadNodeContentDirect(valueNode);
|
||||
value = valueString;
|
||||
return status;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectParameterString::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
|
||||
AddChild(parameterNode, DAE_FXCMN_STRING_ELEMENT, value);
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
// float type parameter
|
||||
FCDEffectParameterFloat::FCDEffectParameterFloat(FCDocument* document) : FCDEffectParameter(document)
|
||||
{
|
||||
floatType = FLOAT;
|
||||
value = 0.0f;
|
||||
min = 0.0f;
|
||||
max = 1.0f;
|
||||
}
|
||||
|
||||
FCDEffectParameterFloat::~FCDEffectParameterFloat()
|
||||
{
|
||||
}
|
||||
|
||||
// Clone
|
||||
FCDEffectParameter* FCDEffectParameterFloat::Clone()
|
||||
{
|
||||
FCDEffectParameterFloat* clone = new FCDEffectParameterFloat(GetDocument());
|
||||
FCDEffectParameter::Clone(clone);
|
||||
clone->floatType = floatType;
|
||||
clone->value = value;
|
||||
clone->min = min;
|
||||
clone->max = max;
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Flattening: overwrite the target parameter with this parameter
|
||||
void FCDEffectParameterFloat::Overwrite(FCDEffectParameter* target)
|
||||
{
|
||||
if (target->GetType() == FCDEffectParameter::FLOAT)
|
||||
{
|
||||
FCDEffectParameterFloat* s = (FCDEffectParameterFloat*) target;
|
||||
if (s->floatType == floatType) s->value = value;
|
||||
}
|
||||
}
|
||||
|
||||
FUStatus FCDEffectParameterFloat::LoadFromXML(xmlNode* parameterNode)
|
||||
{
|
||||
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
|
||||
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_FLOAT_ELEMENT);
|
||||
if (valueNode == NULL)
|
||||
{
|
||||
valueNode = FindChildByType(parameterNode, DAE_FXCMN_HALF_ELEMENT);
|
||||
floatType = HALF;
|
||||
}
|
||||
else floatType = FLOAT;
|
||||
|
||||
const char* valueString = ReadNodeContentDirect(valueNode);
|
||||
if (valueString == NULL || *valueString == 0)
|
||||
{
|
||||
return status.Fail(FS("Bad float value for float parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
|
||||
}
|
||||
value = FUStringConversion::ToFloat(valueString);
|
||||
|
||||
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &value);
|
||||
|
||||
xmlNode* minannNode = FindChildByName(parameterNode, "UIMin");
|
||||
if(minannNode) {
|
||||
xmlNode* minNode = FindChildByType(minannNode, DAE_FXCMN_FLOAT_ELEMENT);
|
||||
valueString = ReadNodeContentDirect(minNode);
|
||||
if (valueString != NULL) min = FUStringConversion::ToFloat(valueString);
|
||||
}
|
||||
|
||||
xmlNode* maxannNode = FindChildByName(parameterNode, "UIMax");
|
||||
if(maxannNode) {
|
||||
xmlNode* maxNode = FindChildByType(maxannNode, DAE_FXCMN_FLOAT_ELEMENT);
|
||||
valueString = ReadNodeContentDirect(maxNode);
|
||||
if (valueString != NULL) max = FUStringConversion::ToFloat(valueString);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectParameterFloat::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
|
||||
AddChild(parameterNode, (floatType == FLOAT) ? DAE_FXCMN_FLOAT_ELEMENT : DAE_FXCMN_HALF_ELEMENT, value);
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
// float2 type parameter
|
||||
FCDEffectParameterFloat2::FCDEffectParameterFloat2(FCDocument* document) : FCDEffectParameter(document)
|
||||
{
|
||||
floatType = FLOAT;
|
||||
value_x = 0.0f;
|
||||
value_y = 0.0f;
|
||||
}
|
||||
|
||||
FCDEffectParameterFloat2::~FCDEffectParameterFloat2()
|
||||
{
|
||||
}
|
||||
|
||||
// Clone
|
||||
FCDEffectParameter* FCDEffectParameterFloat2::Clone()
|
||||
{
|
||||
FCDEffectParameterFloat2* clone = new FCDEffectParameterFloat2(GetDocument());
|
||||
FCDEffectParameter::Clone(clone);
|
||||
clone->floatType = floatType;
|
||||
clone->value_x = value_x;
|
||||
clone->value_y = value_y;
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Flattening: overwrite the target parameter with this parameter
|
||||
void FCDEffectParameterFloat2::Overwrite(FCDEffectParameter* target)
|
||||
{
|
||||
if (target->GetType() == FLOAT2)
|
||||
{
|
||||
FCDEffectParameterFloat2* s = (FCDEffectParameterFloat2*) target;
|
||||
if (s->floatType == floatType)
|
||||
{
|
||||
s->value_x = value_x;
|
||||
s->value_y = value_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FUStatus FCDEffectParameterFloat2::LoadFromXML(xmlNode* parameterNode)
|
||||
{
|
||||
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
|
||||
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_FLOAT2_ELEMENT);
|
||||
if (valueNode == NULL)
|
||||
{
|
||||
valueNode = FindChildByType(parameterNode, DAE_FXCMN_HALF2_ELEMENT);
|
||||
floatType = HALF;
|
||||
}
|
||||
else floatType = FLOAT;
|
||||
|
||||
const char* valueString = ReadNodeContentDirect(valueNode);
|
||||
if (valueString == NULL || *valueString == 0)
|
||||
{
|
||||
return status.Fail(FS("Bad value for float2 parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
|
||||
}
|
||||
value_x = FUStringConversion::ToFloat(&valueString);
|
||||
value_y = FUStringConversion::ToFloat(&valueString);
|
||||
return status;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectParameterFloat2::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
|
||||
globalSBuilder.set(value_x); globalSBuilder.append(' '); globalSBuilder.append(value_y);
|
||||
AddChild(parameterNode, (floatType == FLOAT) ? DAE_FXCMN_FLOAT2_ELEMENT : DAE_FXCMN_HALF2_ELEMENT, globalSBuilder);
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
// float3 type parameter
|
||||
FCDEffectParameterFloat3::FCDEffectParameterFloat3(FCDocument* document) : FCDEffectParameter(document)
|
||||
{
|
||||
floatType = FLOAT;
|
||||
value = FMVector3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
FCDEffectParameterFloat3::~FCDEffectParameterFloat3()
|
||||
{
|
||||
}
|
||||
|
||||
// Clone
|
||||
FCDEffectParameter* FCDEffectParameterFloat3::Clone()
|
||||
{
|
||||
FCDEffectParameterFloat3* clone = new FCDEffectParameterFloat3(GetDocument());
|
||||
FCDEffectParameter::Clone(clone);
|
||||
clone->floatType = floatType;
|
||||
clone->value = value;
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Flattening: overwrite the target parameter with this parameter
|
||||
void FCDEffectParameterFloat3::Overwrite(FCDEffectParameter* target)
|
||||
{
|
||||
if (target->GetType() == FLOAT3)
|
||||
{
|
||||
FCDEffectParameterFloat3* s = (FCDEffectParameterFloat3*) target;
|
||||
if (s->floatType == floatType)
|
||||
{
|
||||
s->value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FUStatus FCDEffectParameterFloat3::LoadFromXML(xmlNode* parameterNode)
|
||||
{
|
||||
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
|
||||
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_FLOAT3_ELEMENT);
|
||||
if (valueNode == NULL)
|
||||
{
|
||||
valueNode = FindChildByType(parameterNode, DAE_FXCMN_HALF3_ELEMENT);
|
||||
floatType = HALF;
|
||||
}
|
||||
else floatType = FLOAT;
|
||||
|
||||
const char* valueString = ReadNodeContentDirect(valueNode);
|
||||
if (valueString == NULL || *valueString == 0)
|
||||
{
|
||||
return status.Fail(FS("Bad value for float3 parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
|
||||
}
|
||||
value = FUStringConversion::ToPoint(valueString);
|
||||
FCDAnimatedColor::Create(GetDocument(), parameterNode, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectParameterFloat3::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
|
||||
string s = FUStringConversion::ToString(value);
|
||||
AddChild(parameterNode, (floatType == FLOAT) ? DAE_FXCMN_FLOAT3_ELEMENT : DAE_FXCMN_HALF3_ELEMENT, s);
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
FCDEffectParameterVector::FCDEffectParameterVector(FCDocument* document) : FCDEffectParameter(document)
|
||||
{
|
||||
floatType = FLOAT;
|
||||
vector[0] = vector[1] = vector[2] = vector[3] = 0.0f;
|
||||
}
|
||||
|
||||
FCDEffectParameterVector::~FCDEffectParameterVector() {}
|
||||
|
||||
// Clone
|
||||
FCDEffectParameter* FCDEffectParameterVector::Clone()
|
||||
{
|
||||
FCDEffectParameterVector* clone = new FCDEffectParameterVector(GetDocument());
|
||||
FCDEffectParameter::Clone(clone);
|
||||
clone->floatType = floatType;
|
||||
memcpy(clone->vector, vector, sizeof(float) * 4);
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Flattening: overwrite the target parameter with this parameter
|
||||
void FCDEffectParameterVector::Overwrite(FCDEffectParameter* target)
|
||||
{
|
||||
if (target->GetType() == VECTOR)
|
||||
{
|
||||
FCDEffectParameterVector* s = (FCDEffectParameterVector*) target;
|
||||
if (s->floatType == floatType)
|
||||
{
|
||||
memcpy(s->vector, vector, sizeof(float) * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FUStatus FCDEffectParameterVector::LoadFromXML(xmlNode* parameterNode)
|
||||
{
|
||||
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
|
||||
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_FLOAT4_ELEMENT);
|
||||
if (valueNode == NULL)
|
||||
{
|
||||
valueNode = FindChildByType(parameterNode, DAE_FXCMN_HALF4_ELEMENT);
|
||||
floatType = HALF;
|
||||
}
|
||||
else floatType = FLOAT;
|
||||
|
||||
const char* valueString = ReadNodeContentDirect(valueNode);
|
||||
if (valueString == NULL || *valueString == 0)
|
||||
{
|
||||
return status.Fail(FS("Bad value for float4 parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
|
||||
}
|
||||
vector[0] = FUStringConversion::ToFloat(&valueString);
|
||||
vector[1] = FUStringConversion::ToFloat(&valueString);
|
||||
vector[2] = FUStringConversion::ToFloat(&valueString);
|
||||
vector[3] = FUStringConversion::ToFloat(&valueString);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectParameterVector::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
|
||||
globalSBuilder.set(vector[0]); globalSBuilder.append(' '); globalSBuilder.append(vector[1]); globalSBuilder.append(' ');
|
||||
globalSBuilder.append(vector[2]); globalSBuilder.append(' '); globalSBuilder.append(vector[3]);
|
||||
AddChild(parameterNode, (floatType == FLOAT) ? DAE_FXCMN_FLOAT4_ELEMENT : DAE_FXCMN_HALF4_ELEMENT, globalSBuilder);
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
FCDEffectParameterMatrix::FCDEffectParameterMatrix(FCDocument* document) : FCDEffectParameter(document)
|
||||
{
|
||||
floatType = FLOAT;
|
||||
matrix = FMMatrix44::Identity;
|
||||
}
|
||||
|
||||
FCDEffectParameterMatrix::~FCDEffectParameterMatrix()
|
||||
{
|
||||
}
|
||||
|
||||
// Clone
|
||||
FCDEffectParameter* FCDEffectParameterMatrix::Clone()
|
||||
{
|
||||
FCDEffectParameterMatrix* clone = new FCDEffectParameterMatrix(GetDocument());
|
||||
FCDEffectParameter::Clone(clone);
|
||||
clone->floatType = floatType;
|
||||
clone->matrix = matrix;
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Flattening: overwrite the target parameter with this parameter
|
||||
void FCDEffectParameterMatrix::Overwrite(FCDEffectParameter* target)
|
||||
{
|
||||
if (target->GetType() == MATRIX)
|
||||
{
|
||||
FCDEffectParameterMatrix* s = (FCDEffectParameterMatrix*) target;
|
||||
s->matrix = matrix;
|
||||
}
|
||||
}
|
||||
|
||||
FUStatus FCDEffectParameterMatrix::LoadFromXML(xmlNode* parameterNode)
|
||||
{
|
||||
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
|
||||
xmlNode* valueNode = FindChildByType(parameterNode, DAE_FXCMN_FLOAT4X4_ELEMENT);
|
||||
if (valueNode == NULL)
|
||||
{
|
||||
valueNode = FindChildByType(parameterNode, DAE_FXCMN_HALF4X4_ELEMENT);
|
||||
floatType = HALF;
|
||||
}
|
||||
else floatType = FLOAT;
|
||||
|
||||
const char* valueString = ReadNodeContentDirect(valueNode);
|
||||
if (valueString == NULL || *valueString == 0)
|
||||
{
|
||||
return status.Fail(FS("Bad value for matrix parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
|
||||
}
|
||||
FUStringConversion::ToMatrix(valueString, matrix, GetDocument()->GetLengthUnitConversion());
|
||||
return status;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectParameterMatrix::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
|
||||
string s = FUStringConversion::ToString(matrix);
|
||||
AddChild(parameterNode, (floatType == FLOAT) ? DAE_FXCMN_FLOAT4X4_ELEMENT : DAE_FXCMN_HALF4X4_ELEMENT, s);
|
||||
return parameterNode;
|
||||
}
|
||||
844
Extras/FCollada/FCDocument/FCDEffectParameter.h
Normal file
844
Extras/FCollada/FCDocument/FCDEffectParameter.h
Normal file
@@ -0,0 +1,844 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDEffectParameter.h
|
||||
This file contains the FCDEffectParameter interface and most of its derivate classes:
|
||||
FCDEffectParameterSampler, FCDEffectParameterFloat, FCDEffectParameterVector...
|
||||
*/
|
||||
|
||||
#ifndef _FCD_EFFECT_PARAMETER_H_
|
||||
#define _FCD_EFFECT_PARAMETER_H_
|
||||
|
||||
#include "FCDocument/FCDObject.h"
|
||||
|
||||
class FCDEffectPass;
|
||||
class FCDocument;
|
||||
class FCDEffectParameterSurface;
|
||||
|
||||
/**
|
||||
A COLLADA effect parameter.
|
||||
|
||||
This interface class is used to define all the valid
|
||||
ColladaFX parameter types. There are many types of
|
||||
parameters: integers, booleans, floating-point
|
||||
values, 2D, 3D and 4D vectors of floating-point values,
|
||||
matrices, strings, surfaces and their samplers.
|
||||
|
||||
A COLLADA effect parameter may generate a new
|
||||
effect parameter, in which case it will declare a semantic
|
||||
and a reference: to represent it within the COLLADA document.
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameter : public FCDObject
|
||||
{
|
||||
public:
|
||||
/** The type of the effect parameter class. */
|
||||
enum Type
|
||||
{
|
||||
SAMPLER, /**< A sampler effect parameter. Points towards a surface parameter and adds extra texturing parameters. */
|
||||
INTEGER, /**< A single integer effect parameter. */
|
||||
BOOLEAN, /**< A single boolean effect parameter. */
|
||||
FLOAT, /**< A single floating-pointer value effect parameter. */
|
||||
FLOAT2, /**< A 2D vector of floating-pointer values. */
|
||||
FLOAT3, /**< A 3D vector of floating-pointer values. */
|
||||
VECTOR, /**< A 4D vector of floating-pointer values. */
|
||||
MATRIX, /**< A 4x4 matrix. */
|
||||
STRING, /**< A string effect parameter. */
|
||||
SURFACE /**< A surface effect parameter. Contains a COLLADA image pointer. */
|
||||
};
|
||||
|
||||
private:
|
||||
bool isGenerator; // whether this effect parameter structure generates a new value or modifies an existing value (is <newparam>?)
|
||||
string reference;
|
||||
string semantic; // this is a Collada Semantic, not a Cg semantic
|
||||
|
||||
// [glaforte] These two members should be somewhere else
|
||||
string bindSymbol; // this can be used in Cg to bind to the correct variable
|
||||
bool isFragment; // parameter bound to the fragment program or the vertex one
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::AddParameter function.
|
||||
@param document The COLLADA document that owns the effect parameter. */
|
||||
FCDEffectParameter(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::ReleaseParameter function.
|
||||
When released, the effect parameter list will also release all
|
||||
its parameters, if it owns them. */
|
||||
virtual ~FCDEffectParameter();
|
||||
|
||||
/** Retrieves the type of effect parameter class.
|
||||
@return The type of the effect parameter class.*/
|
||||
virtual Type GetType() const = 0;
|
||||
|
||||
/** Retrieves the reference for this effect parameter.
|
||||
In the case of generators, the reference string contains the sub-id.
|
||||
@return The reference. */
|
||||
const string& GetReference() const { return reference; }
|
||||
|
||||
/** Retrieves the semantic for this effect parameter.
|
||||
@return The semantic. */
|
||||
const string& GetSemantic() const { return semantic; }
|
||||
|
||||
/** Sets the semantic for this effect parameter.
|
||||
@param _semantic The semantic. */
|
||||
void SetSemantic(const string& _semantic) { semantic = _semantic; }
|
||||
|
||||
/** Retrieves whether this effect parameter is a parameter generator.
|
||||
A ColladaFX parameter must be generated to be modified or bound at
|
||||
higher abstraction levels.
|
||||
@return Whether this is a generator. */
|
||||
bool IsGenerator() const { return isGenerator; }
|
||||
|
||||
/** Retrieves whether this effect parameter is a parameter modifier.
|
||||
A ColladaFX parameter must be generated to be modified or bound at
|
||||
higher abstraction levels.
|
||||
@return Whether this is a modifier. */
|
||||
bool IsModifier() const { return !isGenerator; }
|
||||
|
||||
/** @deprecated Retrieves the program bind symbol for
|
||||
this parameter. This information should be available
|
||||
per-shader, in the FCDEffectPassShader class.
|
||||
@return The program bind symbol. */
|
||||
const string& GetBindSymbol() const { return bindSymbol; }
|
||||
|
||||
/** @deprecated Sets the program bind symbol for this parameter.
|
||||
This information is available per-shader, in the FCDEffectPassShader class.
|
||||
@param _bindSymbol The program bind symbol. */
|
||||
void SetBindSymbol(const string& _bindSymbol) { bindSymbol = _bindSymbol; }
|
||||
|
||||
/** @deprecated Retrieves whether the program bind symbol attached
|
||||
to this parameter belongs to a fragment/pixel shader.
|
||||
This information is available per-shader, in the FCDEffectPassShader class.
|
||||
@return Whether it belongs to a fragment/pixel shader. */
|
||||
bool IsFragment() const { return isFragment; }
|
||||
|
||||
/** @deprecated Sets whether the program bind symbol attached to this
|
||||
parameter belongs to a fragment/pixel shader.
|
||||
This information is available per-shader, in the FCDEffectPassShader class.
|
||||
@param _isFragment Whether it belongs to a fragment/pixel shader. */
|
||||
void SetFragment(bool _isFragment) { isFragment = _isFragment;}
|
||||
|
||||
/** Creates a full copy of the effect parameter.
|
||||
@return The cloned effect parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameter* Clone() = 0;
|
||||
|
||||
/** [INTERNAL] Overwrites the target parameter with this parameter.
|
||||
This function is used during the flattening of materials.
|
||||
@param target The target parameter to overwrite. */
|
||||
virtual void Overwrite(FCDEffectParameter* target);
|
||||
|
||||
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
|
||||
@param parameterNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the parameter.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the parameter.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
|
||||
protected:
|
||||
/** [INTERNAL] Copies into the given effect parameters, the variables
|
||||
held by the FCDEffectParameter interface. This function is used by the classes
|
||||
based on this interface during the cloning process.
|
||||
@param clone The parameter to clone. */
|
||||
void Clone(FCDEffectParameter* clone);
|
||||
};
|
||||
|
||||
/**
|
||||
A COLLADA sampler effect parameter.
|
||||
A sampler parameter provides the extra texturing information necessary
|
||||
to correctly sample a surface parameter.
|
||||
There are four types of samplers supported: 1D, 2D, 3D and cube.
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterSampler : public FCDEffectParameter
|
||||
{
|
||||
public:
|
||||
/** The type of sampling to execute. */
|
||||
enum SamplerType
|
||||
{
|
||||
SAMPLER1D, /** 1D sampling. */
|
||||
SAMPLER2D, /** 2D sampling. */
|
||||
SAMPLER3D, /** 3D sampling. */
|
||||
SAMPLERCUBE /** Cube-map sampling. */
|
||||
};
|
||||
|
||||
private:
|
||||
SamplerType samplerType;
|
||||
string surfaceSid;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::AddParameter function.
|
||||
@param document The COLLADA document that owns the effect parameter. */
|
||||
FCDEffectParameterSampler(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::ReleaseParameter function.
|
||||
When released, the effect parameter list will also release all
|
||||
its parameters, if it owns them. */
|
||||
virtual ~FCDEffectParameterSampler();
|
||||
|
||||
/** Retrieves the type of effect parameter class.
|
||||
@return The parameter class type: SAMPLER. */
|
||||
virtual Type GetType() const { return SAMPLER; }
|
||||
|
||||
/** Retrieves the sub-id of the surface parameter.
|
||||
You will want to search for that sub-id within the parameters to find the
|
||||
FCDEffectParameterSurface object.
|
||||
@return The sub-id. */
|
||||
const char* GetSurfaceSid() const { return surfaceSid.c_str(); }
|
||||
|
||||
/** Sets the sub-id of the surface parameter to sample.
|
||||
@param sid The surface parameter sub-id. */
|
||||
void SetSurfaceSid(const char* sid) { surfaceSid = sid; }
|
||||
|
||||
/** Retrieves the type of sampling to do.
|
||||
@return The sampling type. */
|
||||
SamplerType GetSamplerType() const { return samplerType; }
|
||||
|
||||
/** Sets the type of sampling to do.
|
||||
@param type The sampling type. */
|
||||
void SetSamplerType(SamplerType type) { samplerType = type; }
|
||||
|
||||
/** Creates a full copy of the effect parameter.
|
||||
@return The cloned effect parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameter* Clone();
|
||||
|
||||
/** [INTERNAL] Overwrites the target parameter with this parameter.
|
||||
This function is used during the flattening of materials.
|
||||
@param target The target parameter to overwrite. */
|
||||
virtual void Overwrite(FCDEffectParameter* target);
|
||||
|
||||
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
|
||||
@param parameterNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the parameter.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the parameter.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
/**
|
||||
A COLLADA integer effect parameter.
|
||||
Contains a single, unanimated integer.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterInt : public FCDEffectParameter
|
||||
{
|
||||
private:
|
||||
int value;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::AddParameter function.
|
||||
@param document The COLLADA document that owns the effect parameter. */
|
||||
FCDEffectParameterInt(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::ReleaseParameter function.
|
||||
When released, the effect parameter list will also release all
|
||||
its parameters, if it owns them. */
|
||||
virtual ~FCDEffectParameterInt();
|
||||
|
||||
/** Retrieves the type of effect parameter class.
|
||||
@return The parameter class type: INTEGER. */
|
||||
virtual Type GetType() const { return INTEGER; }
|
||||
|
||||
/** Retrieves the value of the effect parameter.
|
||||
@return The integer value. */
|
||||
int GetValue() const { return value; }
|
||||
|
||||
/** Sets the integer value of the effect parameter.
|
||||
@param _value The integer value. */
|
||||
void SetValue(int _value) { value = _value; }
|
||||
|
||||
/** Creates a full copy of the effect parameter.
|
||||
@return The cloned effect parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameter* Clone();
|
||||
|
||||
/** [INTERNAL] Overwrites the target parameter with this parameter.
|
||||
This function is used during the flattening of materials.
|
||||
@param target The target parameter to overwrite. */
|
||||
virtual void Overwrite(FCDEffectParameter* target);
|
||||
|
||||
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
|
||||
@param parameterNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the parameter.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the parameter.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
/**
|
||||
A COLLADA boolean effect parameter.
|
||||
Contains a single, unanimated boolean.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterBool : public FCDEffectParameter
|
||||
{
|
||||
private:
|
||||
bool value;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::AddParameter function.
|
||||
@param document The COLLADA document that owns the effect parameter. */
|
||||
FCDEffectParameterBool(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::ReleaseParameter function.
|
||||
When released, the effect parameter list will also release all
|
||||
its parameters, if it owns them. */
|
||||
virtual ~FCDEffectParameterBool();
|
||||
|
||||
/** Retrieves the type of effect parameter class.
|
||||
@return The parameter class type: BOOLEAN. */
|
||||
virtual Type GetType() const { return BOOLEAN; }
|
||||
|
||||
/** Retrieves the boolean value of the effect parameter.
|
||||
@return The boolean value. */
|
||||
bool GetValue() const { return value; }
|
||||
|
||||
/** Sets the boolean value of the effect parameter.
|
||||
@param _value The boolean value. */
|
||||
void SetValue(bool _value) { value = _value; }
|
||||
|
||||
/** Creates a full copy of the effect parameter.
|
||||
@return The cloned effect parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameter* Clone();
|
||||
|
||||
/** [INTERNAL] Overwrites the target parameter with this parameter.
|
||||
This function is used during the flattening of materials.
|
||||
@param target The target parameter to overwrite. */
|
||||
virtual void Overwrite(FCDEffectParameter* target);
|
||||
|
||||
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
|
||||
@param parameterNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the parameter.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the parameter.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
/**
|
||||
A COLLADA string effect parameter.
|
||||
Contains a single, unanimated string.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterString : public FCDEffectParameter
|
||||
{
|
||||
private:
|
||||
string value;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::AddParameter function.
|
||||
@param document The COLLADA document that owns the effect parameter. */
|
||||
FCDEffectParameterString(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::ReleaseParameter function.
|
||||
When released, the effect parameter list will also release all
|
||||
its parameters, if it owns them. */
|
||||
virtual ~FCDEffectParameterString();
|
||||
|
||||
/** Retrieves the type of effect parameter class.
|
||||
@return The parameter class type: STRING. */
|
||||
virtual Type GetType() const { return STRING; }
|
||||
|
||||
/** Retrieves the string contained in the effect parameter.
|
||||
@return The string. */
|
||||
const string& GetValue() const { return value; }
|
||||
|
||||
/** Sets the string contained in the effect parameter.
|
||||
@param _value The string. */
|
||||
void SetValue(const string& _value) { value = _value; }
|
||||
|
||||
/** Creates a full copy of the effect parameter.
|
||||
@return The cloned effect parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameter* Clone();
|
||||
|
||||
/** [INTERNAL] Overwrites the target parameter with this parameter.
|
||||
This function is used during the flattening of materials.
|
||||
@param target The target parameter to overwrite. */
|
||||
virtual void Overwrite(FCDEffectParameter* target);
|
||||
|
||||
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
|
||||
@param parameterNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the parameter.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the parameter.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
/**
|
||||
A COLLADA float effect parameter.
|
||||
Contains a single, possibly animated, floating-point value.
|
||||
The type of the floating-point value may be HALF or FLOAT.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterFloat : public FCDEffectParameter
|
||||
{
|
||||
public:
|
||||
/** The supported types of float-point values. */
|
||||
enum FloatType
|
||||
{
|
||||
FLOAT, /** A full-fledged floating-point value. This is the default. */
|
||||
HALF /** Probably implies a 16-bit floating-point value. */
|
||||
};
|
||||
|
||||
private:
|
||||
FloatType floatType;
|
||||
float value;
|
||||
float min;
|
||||
float max;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::AddParameter function.
|
||||
@param document The COLLADA document that owns the effect parameter. */
|
||||
FCDEffectParameterFloat(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::ReleaseParameter function.
|
||||
When released, the effect parameter list will also release all
|
||||
its parameters, if it owns them. */
|
||||
virtual ~FCDEffectParameterFloat();
|
||||
|
||||
/** Retrieves the type of effect parameter class.
|
||||
@return The parameter class type: FLOAT. */
|
||||
virtual FCDEffectParameter::Type GetType() const { return FCDEffectParameter::FLOAT; }
|
||||
|
||||
/** Retrieves the type of floating-point value held by this effect parameter.
|
||||
@return The type of floating-point value. */
|
||||
FloatType GetFloatType() const { return floatType; }
|
||||
|
||||
/** Sets the type of floating-point value held by this effect parameter.
|
||||
@param type The type of floating-point value. */
|
||||
void SetFloatType(FloatType type) { floatType = type; }
|
||||
|
||||
/** Retrieves the floating-point value of the effect parameter.
|
||||
@return The floating-point value. */
|
||||
float& GetValue() { return value; }
|
||||
const float& GetValue() const { return value; } /**< See above. */
|
||||
|
||||
/** Sets the floating-point value of the effect parameter.
|
||||
@param _value The floating-point value. */
|
||||
void SetValue(float _value) { value = _value; }
|
||||
|
||||
/** Retrieves the minimum value for the UI widget created for this effect parameter.
|
||||
This value is for UI purposes only and has no real impact on the value.
|
||||
@return The minimum value. */
|
||||
float GetMin() const { return min; }
|
||||
|
||||
/** Sets the minimum value for the UI widget created for this effect parameter.
|
||||
This value is for UI purposes only and has no real impact on the value.
|
||||
@param _min The minimum value. */
|
||||
void SetMin(float _min) { min = _min; }
|
||||
|
||||
/** Retrieves the maximum value for the UI widget created for this effect parameter.
|
||||
This value is for UI purposes only and has no real impact on the value.
|
||||
@return The maximum value. */
|
||||
float GetMax() const { return max; }
|
||||
|
||||
/** Sets the maximum value for the UI widget created for this effect parameter.
|
||||
This value is for UI purposes only and has no real impact on the value.
|
||||
@param _max The maximum value. */
|
||||
void SetMax(float _max) { max = _max; }
|
||||
|
||||
/** Creates a full copy of the effect parameter.
|
||||
@return The cloned effect parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameter* Clone();
|
||||
|
||||
/** [INTERNAL] Overwrites the target parameter with this parameter.
|
||||
This function is used during the flattening of materials.
|
||||
@param target The target parameter to overwrite. */
|
||||
virtual void Overwrite(FCDEffectParameter* target);
|
||||
|
||||
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
|
||||
@param parameterNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the parameter.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the parameter.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
/**
|
||||
A COLLADA 2D vector of floats.
|
||||
Contains two, possibly animated, floating-point values.
|
||||
The type of the floating-point values may be HALF or FLOAT.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterFloat2 : public FCDEffectParameter
|
||||
{
|
||||
public:
|
||||
/** The supported types of float-point values. */
|
||||
enum FloatType
|
||||
{
|
||||
FLOAT, /** A full-fledged floating-point value. This is the default. */
|
||||
HALF /** Probably implies a 16-bit floating-point value. */
|
||||
};
|
||||
|
||||
private:
|
||||
FloatType floatType;
|
||||
float value_x;
|
||||
float value_y;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::AddParameter function.
|
||||
@param document The COLLADA document that owns the effect parameter. */
|
||||
FCDEffectParameterFloat2(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::ReleaseParameter function.
|
||||
When released, the effect parameter list will also release all
|
||||
its parameters, if it owns them. */
|
||||
virtual ~FCDEffectParameterFloat2();
|
||||
|
||||
/** Retrieves the type of effect parameter class.
|
||||
@return The parameter class type: FLOAT2. */
|
||||
virtual Type GetType() const { return FLOAT2; }
|
||||
|
||||
/** Retrieves the type of floating-point value held by this effect parameter.
|
||||
@return The type of floating-point value. */
|
||||
FloatType GetFloatType() const { return floatType; }
|
||||
|
||||
/** Sets the type of floating-point value held by this effect parameter.
|
||||
@param type The type of floating-point value. */
|
||||
void SetFloatType(FloatType type) { floatType = type; }
|
||||
|
||||
/** Retrieves the first floating-point value of the effect parameter.
|
||||
@return The first floating-point value. */
|
||||
float& GetValueX() { return value_x; }
|
||||
const float& GetValueX() const { return value_x; } /**< See above. */
|
||||
|
||||
/** Sets the first floating-point value of the effect parameter.
|
||||
@param value The first floating-point value. */
|
||||
void SetValueX(float value) { value_x = value; }
|
||||
|
||||
/** Retrieves the second floating-point value of the effect parameter.
|
||||
@return The second floating-point value. */
|
||||
float& GetValueY() { return value_y; }
|
||||
const float& GetValueY() const { return value_y; } /**< See above. */
|
||||
|
||||
/** Sets the second floating-point value of the effect parameter.
|
||||
@param value The second floating-point value. */
|
||||
void SetValueY(float value) { value_y = value; }
|
||||
|
||||
/** Creates a full copy of the effect parameter.
|
||||
@return The cloned effect parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameter* Clone();
|
||||
|
||||
/** [INTERNAL] Overwrites the target parameter with this parameter.
|
||||
This function is used during the flattening of materials.
|
||||
@param target The target parameter to overwrite. */
|
||||
virtual void Overwrite(FCDEffectParameter* target);
|
||||
|
||||
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
|
||||
@param parameterNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the parameter.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the parameter.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
/**
|
||||
A COLLADA 3D vector of floats.
|
||||
Contains three, possibly animated, floating-point values.
|
||||
The type of the floating-point values may be HALF or FLOAT.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterFloat3 : public FCDEffectParameter
|
||||
{
|
||||
public:
|
||||
/** The supported types of float-point values. */
|
||||
enum FloatType
|
||||
{
|
||||
FLOAT, /** A full-fledged floating-point value. This is the default. */
|
||||
HALF /** Probably implies a 16-bit floating-point value. */
|
||||
};
|
||||
|
||||
private:
|
||||
FloatType floatType;
|
||||
FMVector3 value;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::AddParameter function.
|
||||
@param document The COLLADA document that owns the effect parameter. */
|
||||
FCDEffectParameterFloat3(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::ReleaseParameter function.
|
||||
When released, the effect parameter list will also release all
|
||||
its parameters, if it owns them. */
|
||||
virtual ~FCDEffectParameterFloat3();
|
||||
|
||||
/** Retrieves the type of effect parameter class.
|
||||
@return The parameter class type: FLOAT3. */
|
||||
virtual Type GetType() const { return FLOAT3; }
|
||||
|
||||
/** Retrieves the type of floating-point value held by this effect parameter.
|
||||
@return The type of floating-point value. */
|
||||
FloatType GetFloatType() const { return floatType; }
|
||||
|
||||
/** Sets the type of floating-point value held by this effect parameter.
|
||||
@param type The type of floating-point value. */
|
||||
void SetFloatType(FloatType type) { floatType = type; }
|
||||
|
||||
/** Retrieves the first floating-point value of the effect parameter.
|
||||
@return The first floating-point value. */
|
||||
float& GetValueX() { return value.x; }
|
||||
const float& GetValueX() const { return value.x; } /**< See above. */
|
||||
|
||||
/** Sets the first floating-point value of the effect parameter.
|
||||
@param _value The first floating-point value. */
|
||||
void SetValueX(float _value) { value.x = _value; }
|
||||
|
||||
/** Retrieves the second floating-point value of the effect parameter.
|
||||
@return The second floating-point value. */
|
||||
float& GetValueY() { return value.y; }
|
||||
const float& GetValueY() const { return value.y; } /**< See above. */
|
||||
|
||||
/** Sets the second floating-point value of the effect parameter.
|
||||
@param _value The second floating-point value. */
|
||||
void SetValueY(float _value) { value.y = _value; }
|
||||
|
||||
/** Retrieves the third floating-point value of the effect parameter.
|
||||
@return The third floating-point value. */
|
||||
float& GetValueZ() { return value.z; }
|
||||
const float& GetValueZ() const { return value.z; } /**< See above. */
|
||||
|
||||
/** Sets the third floating-point value of the effect parameter.
|
||||
@param _value The third floating-point value. */
|
||||
void SetValueZ(float _value) { value.z = _value; }
|
||||
|
||||
/** Creates a full copy of the effect parameter.
|
||||
@return The cloned effect parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameter* Clone();
|
||||
|
||||
/** [INTERNAL] Overwrites the target parameter with this parameter.
|
||||
This function is used during the flattening of materials.
|
||||
@param target The target parameter to overwrite. */
|
||||
virtual void Overwrite(FCDEffectParameter* target);
|
||||
|
||||
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
|
||||
@param parameterNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the parameter.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the parameter.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
/**
|
||||
A COLLADA 4D vector of floats.
|
||||
Contains four, possibly animated, floating-point values.
|
||||
The type of the floating-point values may be HALF or FLOAT.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterVector : public FCDEffectParameter
|
||||
{
|
||||
public:
|
||||
/** The supported types of float-point values. */
|
||||
enum FloatType
|
||||
{
|
||||
FLOAT, /** A full-fledged floating-point value. This is the default. */
|
||||
HALF /** Probably implies a 16-bit floating-point value. */
|
||||
};
|
||||
|
||||
private:
|
||||
FloatType floatType;
|
||||
float vector[4];
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::AddParameter function.
|
||||
@param document The COLLADA document that owns the effect parameter. */
|
||||
FCDEffectParameterVector(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::ReleaseParameter function.
|
||||
When released, the effect parameter list will also release all
|
||||
its parameters, if it owns them. */
|
||||
virtual ~FCDEffectParameterVector();
|
||||
|
||||
/** Retrieves the type of effect parameter class.
|
||||
@return The parameter class type: VECTOR. */
|
||||
virtual Type GetType() const { return VECTOR; }
|
||||
|
||||
/** Retrieves the type of floating-point value held by this effect parameter.
|
||||
@return The type of floating-point value. */
|
||||
FloatType GetFloatType() const { return floatType; }
|
||||
|
||||
/** Sets the type of floating-point value held by this effect parameter.
|
||||
@param type The type of floating-point value. */
|
||||
void SetFloatType(FloatType type) { floatType = type; }
|
||||
|
||||
/** Sets the vector value of the effect parameter.
|
||||
@return The vector value. */
|
||||
float* GetVector() { return vector; }
|
||||
const float* GetVector() const { return vector; } /**< See above. */
|
||||
|
||||
/** Retrieves the first floating-point value of the effect parameter.
|
||||
@return The first floating-point value. */
|
||||
float& GetValueX() { return vector[0]; }
|
||||
const float& GetValueX() const { return vector[0]; } /**< See above. */
|
||||
|
||||
/** Sets the first floating-point value of the effect parameter.
|
||||
@param _value The first floating-point value. */
|
||||
void SetValueX(float _value) { vector[0] = _value; }
|
||||
|
||||
/** Retrieves the second floating-point value of the effect parameter.
|
||||
@return The second floating-point value. */
|
||||
float& GetValueY() { return vector[1]; }
|
||||
const float& GetValueY() const { return vector[1]; } /**< See above. */
|
||||
|
||||
/** Sets the second floating-point value of the effect parameter.
|
||||
@param _value The second floating-point value. */
|
||||
void SetValueY(float _value) { vector[1] = _value; }
|
||||
|
||||
/** Retrieves the third floating-point value of the effect parameter.
|
||||
@return The third floating-point value. */
|
||||
float& GetValueZ() { return vector[2]; }
|
||||
const float& GetValueZ() const { return vector[2]; } /**< See above. */
|
||||
|
||||
/** Sets the third floating-point value of the effect parameter.
|
||||
@param _value The third floating-point value. */
|
||||
void SetValueZ(float _value) { vector[2] = _value; }
|
||||
|
||||
/** Retrieves the fourth floating-point value of the effect parameter.
|
||||
@return The fourth floating-point value. */
|
||||
float& GetValueW() { return vector[3]; }
|
||||
const float& GetValueW() const { return vector[3]; } /**< See above. */
|
||||
|
||||
/** Sets the fourth floating-point value of the effect parameter.
|
||||
@param _value The fourth floating-point value. */
|
||||
void SetValueW(float _value) { vector[3] = _value; }
|
||||
|
||||
/** Creates a full copy of the effect parameter.
|
||||
@return The cloned effect parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameter* Clone();
|
||||
|
||||
/** [INTERNAL] Overwrites the target parameter with this parameter.
|
||||
This function is used during the flattening of materials.
|
||||
@param target The target parameter to overwrite. */
|
||||
virtual void Overwrite(FCDEffectParameter* target);
|
||||
|
||||
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
|
||||
@param parameterNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the parameter.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the parameter.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
/**
|
||||
A COLLADA 4x4 matrix.
|
||||
Contains 16 floating-point values that represent a COLLADA column-major 4x4 matrix.
|
||||
The type of the floating-point values may be HALF or FLOAT.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterMatrix : public FCDEffectParameter
|
||||
{
|
||||
public:
|
||||
/** The supported types of float-point values. */
|
||||
enum FloatType
|
||||
{
|
||||
FLOAT, /** A full-fledged floating-point value. This is the default. */
|
||||
HALF /** Probably implies a 16-bit floating-point value. */
|
||||
};
|
||||
|
||||
private:
|
||||
FloatType floatType;
|
||||
FMMatrix44 matrix;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::AddParameter function.
|
||||
@param document The COLLADA document that owns the effect parameter. */
|
||||
FCDEffectParameterMatrix(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::ReleaseParameter function.
|
||||
When released, the effect parameter list will also release all
|
||||
its parameters, if it owns them. */
|
||||
virtual ~FCDEffectParameterMatrix();
|
||||
|
||||
/** Retrieves the type of effect parameter class.
|
||||
@return The parameter class type: MATRIX. */
|
||||
virtual Type GetType() const { return MATRIX; }
|
||||
|
||||
/** Retrieves the type of floating-point value held by this effect parameter.
|
||||
@return The type of floating-point value. */
|
||||
FloatType GetFloatType() const { return floatType; }
|
||||
|
||||
/** Sets the type of floating-point value held by this effect parameter.
|
||||
@param type The type of floating-point value. */
|
||||
void SetFloatType(FloatType type) { floatType = type; }
|
||||
|
||||
/** Retrieves the matrix contained within this effect parameter.
|
||||
@return The matrix. */
|
||||
FMMatrix44& GetMatrix() { return matrix; }
|
||||
const FMMatrix44& GetMatrix() const { return matrix; } /**< See above. */
|
||||
|
||||
/** Sets the matrix contained within this effect parameter.
|
||||
@param mx The matrix. */
|
||||
void SetMatrix(const FMMatrix44& mx) { matrix = mx; }
|
||||
|
||||
/** Creates a full copy of the effect parameter.
|
||||
@return The cloned effect parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameter* Clone();
|
||||
|
||||
/** [INTERNAL] Overwrites the target parameter with this parameter.
|
||||
This function is used during the flattening of materials.
|
||||
@param target The target parameter to overwrite. */
|
||||
virtual void Overwrite(FCDEffectParameter* target);
|
||||
|
||||
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
|
||||
@param parameterNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the parameter.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the parameter.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
#endif // _FCD_EFFECT_PARAMETER_H_
|
||||
|
||||
70
Extras/FCollada/FCDocument/FCDEffectParameterFactory.cpp
Normal file
70
Extras/FCollada/FCDocument/FCDEffectParameterFactory.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDEffectParameter.h"
|
||||
#include "FCDocument/FCDEffectParameterFactory.h"
|
||||
#include "FCDocument/FCDEffectParameterSurface.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
|
||||
// Creates a new effect parameter, given a type.
|
||||
FCDEffectParameter* FCDEffectParameterFactory::Create(FCDocument* document, uint32 type)
|
||||
{
|
||||
FCDEffectParameter* parameter = NULL;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case FCDEffectParameter::SAMPLER: parameter = new FCDEffectParameterSampler(document); break;
|
||||
case FCDEffectParameter::INTEGER: parameter = new FCDEffectParameterInt(document); break;
|
||||
case FCDEffectParameter::BOOLEAN: parameter = new FCDEffectParameterBool(document); break;
|
||||
case FCDEffectParameter::FLOAT: parameter = new FCDEffectParameterFloat(document); break;
|
||||
case FCDEffectParameter::FLOAT2: parameter = new FCDEffectParameterFloat2(document); break;
|
||||
case FCDEffectParameter::FLOAT3: parameter = new FCDEffectParameterFloat3(document); break;
|
||||
case FCDEffectParameter::VECTOR: parameter = new FCDEffectParameterVector(document); break;
|
||||
case FCDEffectParameter::MATRIX: parameter = new FCDEffectParameterMatrix(document); break;
|
||||
case FCDEffectParameter::STRING: parameter = new FCDEffectParameterString(document); break;
|
||||
case FCDEffectParameter::SURFACE: parameter = new FCDEffectParameterSurface(document); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
// Generates the effect parameter object for the given XML node tree
|
||||
FCDEffectParameter* FCDEffectParameterFactory::LoadFromXML(FCDocument* document, xmlNode* parameterNode, FUStatus* status)
|
||||
{
|
||||
// Look for the type of the parameter.
|
||||
FCDEffectParameter* parameter = NULL;
|
||||
for (xmlNode* child = parameterNode->children; child != NULL && parameter == NULL; child = child->next)
|
||||
{
|
||||
if (child->type != XML_ELEMENT_NODE) continue;
|
||||
|
||||
if (IsEquivalent(child->name, DAE_FXCMN_BOOL_ELEMENT)) parameter = new FCDEffectParameterBool(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_FLOAT_ELEMENT)) parameter = new FCDEffectParameterFloat(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_FLOAT2_ELEMENT)) parameter = new FCDEffectParameterFloat2(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_FLOAT3_ELEMENT)) parameter = new FCDEffectParameterFloat3(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_FLOAT4_ELEMENT)) parameter = new FCDEffectParameterVector(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_FLOAT4X4_ELEMENT)) parameter = new FCDEffectParameterMatrix(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_HALF_ELEMENT)) parameter = new FCDEffectParameterFloat(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_HALF2_ELEMENT)) parameter = new FCDEffectParameterFloat2(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_HALF3_ELEMENT)) parameter = new FCDEffectParameterFloat3(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_HALF4_ELEMENT)) parameter = new FCDEffectParameterVector(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_HALF4X4_ELEMENT)) parameter = new FCDEffectParameterMatrix(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_INT_ELEMENT)) parameter = new FCDEffectParameterInt(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLER1D_ELEMENT)) parameter = new FCDEffectParameterSampler(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLER2D_ELEMENT)) parameter = new FCDEffectParameterSampler(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLER3D_ELEMENT)) parameter = new FCDEffectParameterSampler(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_SAMPLERCUBE_ELEMENT)) parameter = new FCDEffectParameterSampler(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_SURFACE_ELEMENT)) parameter = new FCDEffectParameterSurface(document);
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_STRING_ELEMENT)) parameter = new FCDEffectParameterString(document);
|
||||
}
|
||||
|
||||
if (parameter != NULL)
|
||||
{
|
||||
FUStatus s = parameter->LoadFromXML(parameterNode);
|
||||
if (status != NULL) status->AppendStatus(s);
|
||||
}
|
||||
return parameter;
|
||||
}
|
||||
47
Extras/FCollada/FCDocument/FCDEffectParameterFactory.h
Normal file
47
Extras/FCollada/FCDocument/FCDEffectParameterFactory.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDEffectParameterFactory.h
|
||||
This file contains the FCDEffectParameterFactory class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_EFFECT_PARAMETER_FACTORY_H_
|
||||
#define _FCD_EFFECT_PARAMETER_FACTORY_H_
|
||||
|
||||
class FCDocument;
|
||||
|
||||
/**
|
||||
[INTERNAL] The factory for COLLADA effect parameters.
|
||||
|
||||
Takes in a COLLADA XML tree and returns a new
|
||||
parameter that represent it, if one is possible.
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterFactory
|
||||
{
|
||||
private:
|
||||
// Never instantiate: this is a static class
|
||||
FCDEffectParameterFactory() {}
|
||||
|
||||
public:
|
||||
/** [INTERNAL] Creates a new effect parameter, given a type.
|
||||
To create new effect parameters, use the FCDEffectParameterList::AddParameter function.
|
||||
@param document The COLLADA document that will own the effect parameter.
|
||||
@param type The type of effect to create.
|
||||
This value should reflect the FCDEffectParameter::Type enum. */
|
||||
static FCDEffectParameter* Create(FCDocument* document, uint32 type);
|
||||
|
||||
/** [INTERNAL] Generates the effect parameter object for the given XML node tree.
|
||||
@param document The COLLADA document that will own the effect parameter.
|
||||
@param parameterNode The COLLADA XML tree node.
|
||||
@param status An optional return status.
|
||||
@return The new effect parameter. This pointer will be NULL if no parameter can be generated
|
||||
from the given COLLADA XML tree node. */
|
||||
static FCDEffectParameter* LoadFromXML(FCDocument* document, xmlNode* parameterNode, FUStatus* status);
|
||||
};
|
||||
|
||||
#endif // _FCD_EFFECT_PARAMETER_FACTORY_H_
|
||||
124
Extras/FCollada/FCDocument/FCDEffectParameterList.cpp
Normal file
124
Extras/FCollada/FCDocument/FCDEffectParameterList.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDEffectParameter.h"
|
||||
#include "FCDocument/FCDEffectParameterFactory.h"
|
||||
#include "FCDocument/FCDEffectParameterList.h"
|
||||
|
||||
FCDEffectParameterList::FCDEffectParameterList(FCDocument* document, bool _ownParameters)
|
||||
: FCDObject(document, "FCDEffectParameterList")
|
||||
{
|
||||
ownParameters = _ownParameters;
|
||||
}
|
||||
|
||||
FCDEffectParameterList::~FCDEffectParameterList()
|
||||
{
|
||||
if (ownParameters)
|
||||
{
|
||||
size_t l = size();
|
||||
for (size_t i = 0; i < l; ++i)
|
||||
{
|
||||
FCDEffectParameter* p = at(i);
|
||||
SAFE_DELETE(p);
|
||||
}
|
||||
}
|
||||
clear();
|
||||
ownParameters = false;
|
||||
}
|
||||
|
||||
FCDEffectParameter* FCDEffectParameterList::AddParameter(uint32 type)
|
||||
{
|
||||
FCDEffectParameter* parameter = NULL;
|
||||
if (ownParameters)
|
||||
{
|
||||
parameter = FCDEffectParameterFactory::Create(GetDocument(), type);
|
||||
push_back(parameter);
|
||||
}
|
||||
return parameter;
|
||||
}
|
||||
|
||||
void FCDEffectParameterList::ReleaseParameter(FCDEffectParameter* parameter)
|
||||
{
|
||||
iterator it = std::find(begin(), end(), parameter);
|
||||
if (it != end())
|
||||
{
|
||||
if (ownParameters) delete *it;
|
||||
erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
FCDEffectParameter* FCDEffectParameterList::FindReference(const char* reference)
|
||||
{
|
||||
for (iterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
if ((*it)->GetReference() == reference) return (*it);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
const FCDEffectParameter* FCDEffectParameterList::FindReference(const char* reference) const
|
||||
{
|
||||
for (const_iterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
if ((*it)->GetReference() == reference) return (*it);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FCDEffectParameter* FCDEffectParameterList::FindSemantic(const char* semantic)
|
||||
{
|
||||
for (iterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
if ((*it)->GetSemantic() == semantic) return (*it);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
const FCDEffectParameter* FCDEffectParameterList::FindSemantic(const char* semantic) const
|
||||
{
|
||||
for (const_iterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
if ((*it)->GetSemantic() == semantic) return (*it);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void FCDEffectParameterList::FindReference(const char* reference, FCDEffectParameterList& list)
|
||||
{
|
||||
for (iterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
if ((*it)->GetReference() == reference) list.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void FCDEffectParameterList::FindSemantic(const char* semantic, FCDEffectParameterList& list)
|
||||
{
|
||||
for (iterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
if ((*it)->GetSemantic() == semantic) list.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy this list
|
||||
FCDEffectParameterList* FCDEffectParameterList::Clone() const
|
||||
{
|
||||
FCDEffectParameterList* clone = new FCDEffectParameterList(GetDocument(), ownParameters);
|
||||
if (!empty())
|
||||
{
|
||||
clone->reserve(size());
|
||||
|
||||
if (ownParameters)
|
||||
{
|
||||
for (const_iterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
clone->push_back((*it)->Clone());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(*clone) = (*this);
|
||||
}
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
93
Extras/FCollada/FCDocument/FCDEffectParameterList.h
Normal file
93
Extras/FCollada/FCDocument/FCDEffectParameterList.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDEffectParameterList.h
|
||||
This file contains the FCDEffectParameterList class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_EFFECT_PARAMETER_LIST_H_
|
||||
#define _FCD_EFFECT_PARAMETER_LIST_H_
|
||||
|
||||
class FCDEffectParameter;
|
||||
|
||||
/**
|
||||
A searchable list of COLLADA effect parameters.
|
||||
|
||||
This class is based on the STL vector class and adds some
|
||||
useful search methods: by reference and by semantic.
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterList : public vector<FCDEffectParameter*>, public FCDObject
|
||||
{
|
||||
private:
|
||||
bool ownParameters;
|
||||
|
||||
public:
|
||||
/** Constructor.
|
||||
All the objects that need a parameter list will create it when necessary.
|
||||
You may also create new lists for the retrieval of parameters during a search.
|
||||
@param document The COLLADA document that owns this parameter list. This pointer
|
||||
can remain NULL unless you expect to create new parameters within this list.
|
||||
@param ownParameters Whether this list should release the contained parameters
|
||||
during its destruction. */
|
||||
FCDEffectParameterList(FCDocument* document = NULL, bool ownParameters = false);
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~FCDEffectParameterList();
|
||||
|
||||
/** Creates a new parameters within this list.
|
||||
@param type The effect parameter type.
|
||||
@return The new effect parameter. This pointer will be NULL if this list does not own its parameters. */
|
||||
FCDEffectParameter* AddParameter(uint32 type);
|
||||
|
||||
/** Releases a parameter contained within this list.
|
||||
The memory used by this parameter will be released only if this list owns the parameters.
|
||||
@param parameter The effect parameter to release. */
|
||||
void ReleaseParameter(FCDEffectParameter* parameter);
|
||||
|
||||
/** Retrieves the first effect parameter with the given reference.
|
||||
For effect parameter generators, the sub-id is used instead of the reference.
|
||||
@param reference A reference to match.
|
||||
@return The effect parameter that matches the reference. This pointer will be NULL,
|
||||
if no parameter matches the reference. */
|
||||
FCDEffectParameter* FindReference(const char* reference);
|
||||
const FCDEffectParameter* FindReference(const char* reference) const; /**< See above. */
|
||||
inline FCDEffectParameter* FindReference(const string& reference) { return FindReference(reference.c_str()); } /**< See above. */
|
||||
inline const FCDEffectParameter* FindReference(const string& reference) const { return FindReference(reference.c_str()); } /**< See above. */
|
||||
|
||||
/** Retrieves the first effect parameter with the given semantic.
|
||||
@param semantic A semantic to match.
|
||||
@return The effect parameter that matches the semantic. This pointer will be NULL
|
||||
if no parameter matches the semantic. */
|
||||
FCDEffectParameter* FindSemantic(const char* semantic);
|
||||
const FCDEffectParameter* FindSemantic(const char* semantic) const; /**< See above. */
|
||||
inline FCDEffectParameter* FindSemantic(const string& semantic) { return FindReference(semantic.c_str()); } /**< See above. */
|
||||
inline const FCDEffectParameter* FindSemantic(const string& semantic) const { return FindReference(semantic.c_str()); } /**< See above. */
|
||||
|
||||
/** Retrieves a subset of this parameter list.
|
||||
All the effects that match the given reference will be added to the given list.
|
||||
For effect parameter generators, the sub-id is used instead of the reference.
|
||||
@param reference A reference to match.
|
||||
@param list The effect parameter list to fill in with the matched parameters.
|
||||
This list is not clear. */
|
||||
void FindReference(const char* reference, FCDEffectParameterList& list);
|
||||
inline void FindReference(const string& reference, FCDEffectParameterList& list) { return FindReference(reference.c_str(), list); } /**< See above. */
|
||||
|
||||
/** Retrieves a subset of this parameter list.
|
||||
All the effects that match the given semantic will be added to the given list.
|
||||
@param semantic A semantic to match.
|
||||
@param list The effect parameter list to fill in with the matched parameters.
|
||||
This list is not clear. */
|
||||
void FindSemantic(const char* semantic, FCDEffectParameterList& list);
|
||||
inline void FindSemantic(const string& semantic, FCDEffectParameterList& list) { return FindReference(semantic.c_str(), list); } /**< See above. */
|
||||
|
||||
/** Creates a full copy of the list of parameters and its content.
|
||||
@return The cloned list. You will need to delete this pointer.*/
|
||||
FCDEffectParameterList* Clone() const;
|
||||
};
|
||||
|
||||
#endif // _FCD_EFFECT_PARAMETER_LIST_H_
|
||||
589
Extras/FCollada/FCDocument/FCDEffectParameterSurface.cpp
Normal file
589
Extras/FCollada/FCDocument/FCDEffectParameterSurface.cpp
Normal file
@@ -0,0 +1,589 @@
|
||||
/*
|
||||
Copyright (C) 2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDAnimated.h"
|
||||
#include "FCDocument/FCDEffectPass.h"
|
||||
#include "FCDocument/FCDEffectProfile.h"
|
||||
#include "FCDocument/FCDEffectTechnique.h"
|
||||
#include "FCDocument/FCDEffectParameter.h"
|
||||
#include "FCDocument/FCDEffectParameterSurface.h"
|
||||
#include "FCDocument/FCDImage.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
// surface type parameter
|
||||
FCDEffectParameterSurface::FCDEffectParameterSurface(FCDocument* document) : FCDEffectParameter(document)
|
||||
{
|
||||
initMethod = NULL;
|
||||
}
|
||||
|
||||
FCDEffectParameterSurface::~FCDEffectParameterSurface()
|
||||
{
|
||||
SAFE_DELETE(initMethod);
|
||||
names.clear();
|
||||
images.clear();
|
||||
}
|
||||
|
||||
void FCDEffectParameterSurface::SetInitMethod(FCDEffectParameterSurfaceInit* method)
|
||||
{
|
||||
SAFE_DELETE(initMethod);
|
||||
initMethod = method;
|
||||
}
|
||||
|
||||
// Retrieves the index that matches the given image.
|
||||
size_t FCDEffectParameterSurface::FindImage(const FCDImage* image) const
|
||||
{
|
||||
FCDImageList::const_iterator it = std::find(images.begin(), images.end(), image);
|
||||
if (it != images.end())
|
||||
{
|
||||
return it - images.begin();
|
||||
}
|
||||
else return (size_t) -1;
|
||||
}
|
||||
|
||||
// Adds an image to the list.
|
||||
size_t FCDEffectParameterSurface::AddImage(FCDImage* image)
|
||||
{
|
||||
size_t index = FindImage(image);
|
||||
if (index == (size_t) -1)
|
||||
{
|
||||
index = images.size();
|
||||
images.push_back(image);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
// Removes an image from the list.
|
||||
void FCDEffectParameterSurface::RemoveImage(FCDImage* image)
|
||||
{
|
||||
size_t index = FindImage(image);
|
||||
if (index != (size_t) -1)
|
||||
{
|
||||
images.erase(images.begin() + index);
|
||||
|
||||
if (initMethod != NULL && initMethod->GetInitType() == FCDEffectParameterSurfaceInitFactory::CUBE)
|
||||
{
|
||||
// Shift down all the indexes found within the cube map initialization.
|
||||
FCDEffectParameterSurfaceInitCube* cube = (FCDEffectParameterSurfaceInitCube*) initMethod;
|
||||
for (UInt16List::iterator itI = cube->order.begin(); itI != cube->order.end(); ++itI)
|
||||
{
|
||||
if ((*itI) == index) (*itI) = 0;
|
||||
else if ((*itI) > index) --(*itI);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone
|
||||
FCDEffectParameter* FCDEffectParameterSurface::Clone()
|
||||
{
|
||||
FCDEffectParameterSurface* clone = new FCDEffectParameterSurface(GetDocument());
|
||||
FCDEffectParameter::Clone(clone);
|
||||
clone->images.clear();
|
||||
for(uint32 i=0; i<images.size(); i++)
|
||||
clone->images.push_back(images[i]);
|
||||
clone->names.clear();
|
||||
for(uint32 i=0; i<names.size(); i++)
|
||||
clone->names.push_back(names[i]);
|
||||
|
||||
if(initMethod)
|
||||
clone->initMethod = initMethod->Clone();
|
||||
|
||||
clone->size = size;
|
||||
clone->viewportRatio = viewportRatio;
|
||||
clone->mipLevelCount = mipLevelCount;
|
||||
clone->generateMipmaps = generateMipmaps;
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Flattening: overwrite the target parameter with this parameter
|
||||
void FCDEffectParameterSurface::Overwrite(FCDEffectParameter* target)
|
||||
{
|
||||
if (target->GetType() == SURFACE)
|
||||
{
|
||||
FCDEffectParameterSurface* s = (FCDEffectParameterSurface*) target;
|
||||
s->images.clear();
|
||||
for(uint32 i=0; i<images.size(); i++)
|
||||
s->images.push_back(images[i]);
|
||||
s->names.clear();
|
||||
for(uint32 i=0; i<names.size(); i++)
|
||||
s->names.push_back(names[i]);
|
||||
|
||||
// s->initMethod->initType = initMethod->GetInitType();
|
||||
s->size = size;
|
||||
s->viewportRatio = viewportRatio;
|
||||
s->mipLevelCount = mipLevelCount;
|
||||
s->generateMipmaps = generateMipmaps;
|
||||
}
|
||||
}
|
||||
|
||||
FUStatus FCDEffectParameterSurface::LoadFromXML(xmlNode* parameterNode)
|
||||
{
|
||||
FUStatus status = FCDEffectParameter::LoadFromXML(parameterNode);
|
||||
xmlNode* surfaceNode = FindChildByType(parameterNode, DAE_FXCMN_SURFACE_ELEMENT);
|
||||
|
||||
bool initialized = false;
|
||||
xmlNode* valueNode = NULL;
|
||||
//The surface can now contain many init_from elements (1.4.1)
|
||||
xmlNodeList valueNodes;
|
||||
FindChildrenByType(surfaceNode, DAE_INITFROM_ELEMENT, valueNodes);
|
||||
for (xmlNodeList::iterator it = valueNodes.begin(); it != valueNodes.end(); ++it)
|
||||
{
|
||||
initialized = true;
|
||||
if(!initMethod)
|
||||
initMethod = new FCDEffectParameterSurfaceInitFrom();
|
||||
|
||||
FCDEffectParameterSurfaceInitFrom* ptrInit = (FCDEffectParameterSurfaceInitFrom*)initMethod;
|
||||
StringList tempNames;
|
||||
FUStringConversion::ToStringList(ReadNodeContentDirect(*it), tempNames);
|
||||
|
||||
if (tempNames.size() == 0 || tempNames[0].empty())
|
||||
{
|
||||
return status.Fail(FS("<init_from> element is empty in surface parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
|
||||
}
|
||||
|
||||
if(tempNames.size() == 1) //might be 1.4.1, so allow the attributes mip, slice, face
|
||||
{
|
||||
if(HasNodeProperty(*it, DAE_MIP_ATTRIBUTE))
|
||||
{
|
||||
string mip = ReadNodeProperty(*it, DAE_MIP_ATTRIBUTE);
|
||||
ptrInit->mip.push_back(mip);
|
||||
}
|
||||
if(HasNodeProperty(*it, DAE_SLICE_ATTRIBUTE))
|
||||
{
|
||||
string slice = ReadNodeProperty(*it, DAE_SLICE_ATTRIBUTE);
|
||||
ptrInit->slice.push_back(slice);
|
||||
}
|
||||
if(HasNodeProperty(*it, DAE_FACE_ATTRIBUTE))
|
||||
{
|
||||
string face = ReadNodeProperty(*it, DAE_FACE_ATTRIBUTE);
|
||||
ptrInit->face.push_back(face);
|
||||
}
|
||||
}
|
||||
|
||||
//go through the new names, get their images, and add update the image and name lists
|
||||
for(uint32 i=0; i<tempNames.size(); i++)
|
||||
{
|
||||
names.push_back(tempNames[i]);
|
||||
FCDImage* image = GetDocument()->FindImage(tempNames[i]);
|
||||
if (image != NULL)
|
||||
{
|
||||
images.push_back(image);
|
||||
|
||||
}
|
||||
//else return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), parameterNode->line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Check if it's initialized AS NULL
|
||||
if(!initialized)
|
||||
{
|
||||
valueNode = FindChildByType(surfaceNode, DAE_INITASNULL_ELEMENT);
|
||||
if(valueNode)
|
||||
{
|
||||
initialized = true;
|
||||
initMethod = FCDEffectParameterSurfaceInitFactory::Create(FCDEffectParameterSurfaceInitFactory::AS_NULL);
|
||||
}
|
||||
}
|
||||
//Check if it's initialized AS TARGET
|
||||
if(!initialized)
|
||||
{
|
||||
valueNode = FindChildByType(surfaceNode, DAE_INITASTARGET_ELEMENT);
|
||||
if(valueNode)
|
||||
{
|
||||
initialized = true;
|
||||
initMethod = FCDEffectParameterSurfaceInitFactory::Create(FCDEffectParameterSurfaceInitFactory::AS_TARGET);
|
||||
}
|
||||
}
|
||||
//Check if it's initialized AS CUBE
|
||||
if(!initialized)
|
||||
{
|
||||
valueNode = FindChildByType(surfaceNode, DAE_INITCUBE_ELEMENT);
|
||||
if(valueNode)
|
||||
{
|
||||
initialized = true;
|
||||
initMethod = FCDEffectParameterSurfaceInitFactory::Create(FCDEffectParameterSurfaceInitFactory::CUBE);
|
||||
FCDEffectParameterSurfaceInitCube* ptrInit = (FCDEffectParameterSurfaceInitCube*) initMethod;
|
||||
|
||||
//Check if it's an ALL reference
|
||||
xmlNode* refNode = FindChildByType(valueNode, DAE_ALL_ELEMENT);
|
||||
if(refNode)
|
||||
{
|
||||
ptrInit->cubeType = FCDEffectParameterSurfaceInitCube::ALL;
|
||||
string name = ReadNodeProperty(refNode, DAE_REF_ATTRIBUTE);
|
||||
if (name.empty())
|
||||
{
|
||||
return status.Fail(FS("<init_cube>'s all reference is empty in surface parameter: ") + TO_FSTRING(GetReference()), surfaceNode->line);
|
||||
}
|
||||
names.push_back(name);
|
||||
|
||||
FCDImage* image = GetDocument()->FindImage(name);
|
||||
if (image == NULL)
|
||||
{
|
||||
return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), surfaceNode->line);
|
||||
}
|
||||
images.push_back(image);
|
||||
}
|
||||
|
||||
//Check if it's a PRIMARY reference
|
||||
if(!refNode)
|
||||
{
|
||||
refNode = FindChildByType(valueNode, DAE_PRIMARY_ELEMENT);
|
||||
if(refNode)
|
||||
{
|
||||
ptrInit->cubeType = FCDEffectParameterSurfaceInitCube::PRIMARY;
|
||||
string name = ReadNodeProperty(refNode, DAE_REF_ATTRIBUTE);
|
||||
if (name.empty())
|
||||
{
|
||||
return status.Fail(FS("<init_cube>'s primary reference is empty in surface parameter: ") + TO_FSTRING(GetReference()), valueNode->line);
|
||||
}
|
||||
names.push_back(name);
|
||||
|
||||
FCDImage* image = GetDocument()->FindImage(name);
|
||||
if (image == NULL)
|
||||
{
|
||||
return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), valueNode->line);
|
||||
}
|
||||
images.push_back(image);
|
||||
|
||||
xmlNode* orderNode = FindChildByType(refNode, DAE_ORDER_ELEMENT);
|
||||
if(orderNode)
|
||||
{
|
||||
//FIXME: complete when the spec has more info
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Check if it's a FACE reference
|
||||
if(!refNode)
|
||||
{
|
||||
xmlNodeList faceNodes;
|
||||
FindChildrenByType(valueNode, DAE_FACE_ELEMENT, faceNodes);
|
||||
if(faceNodes.size()==6)
|
||||
{
|
||||
ptrInit->cubeType = FCDEffectParameterSurfaceInitCube::FACE;
|
||||
for(uint8 ii=0; ii<faceNodes.size(); ii++)
|
||||
{
|
||||
string valueName = ReadNodeProperty(faceNodes[ii], DAE_REF_ATTRIBUTE);
|
||||
if (valueName.empty())
|
||||
{
|
||||
return status.Fail(FS("<init_cube>'s face reference is empty in surface parameter: ") + TO_FSTRING(GetReference()), refNode->line);
|
||||
}
|
||||
names.push_back(valueName);
|
||||
FCDImage* image = GetDocument()->FindImage(valueName);
|
||||
|
||||
if (image == NULL)
|
||||
{
|
||||
return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), refNode->line);
|
||||
}
|
||||
images.push_back(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Check if it's initialized AS VOLUME
|
||||
if(!initialized)
|
||||
{
|
||||
valueNode = FindChildByType(surfaceNode, DAE_INITVOLUME_ELEMENT);
|
||||
if(valueNode)
|
||||
{
|
||||
initialized = true;
|
||||
initMethod = FCDEffectParameterSurfaceInitFactory::Create(FCDEffectParameterSurfaceInitFactory::VOLUME);
|
||||
FCDEffectParameterSurfaceInitVolume* ptrInit = (FCDEffectParameterSurfaceInitVolume*) initMethod;
|
||||
|
||||
//Check if it's an ALL reference
|
||||
xmlNode* refNode = FindChildByType(valueNode, DAE_ALL_ELEMENT);
|
||||
if(refNode)
|
||||
{
|
||||
ptrInit->volumeType = FCDEffectParameterSurfaceInitVolume::ALL;
|
||||
string name = ReadNodeProperty(refNode, DAE_REF_ATTRIBUTE);
|
||||
if (name.empty())
|
||||
{
|
||||
return status.Fail(FS("<init_cube>'s all reference is empty in surface parameter: ") + TO_FSTRING(GetReference()), refNode->line);
|
||||
}
|
||||
names.push_back(name);
|
||||
|
||||
FCDImage* image = GetDocument()->FindImage(name);
|
||||
if (image == NULL)
|
||||
{
|
||||
return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), refNode->line);
|
||||
}
|
||||
images.push_back(image);
|
||||
}
|
||||
|
||||
//Check if it's a PRIMARY reference
|
||||
if(!refNode)
|
||||
{
|
||||
refNode = FindChildByType(valueNode, DAE_PRIMARY_ELEMENT);
|
||||
if(refNode)
|
||||
{
|
||||
ptrInit->volumeType = FCDEffectParameterSurfaceInitVolume::PRIMARY;
|
||||
string name = ReadNodeProperty(refNode, DAE_REF_ATTRIBUTE);
|
||||
if (name.empty())
|
||||
{
|
||||
return status.Fail(FS("<init_cube>'s primary reference is empty in surface parameter: ") + TO_FSTRING(GetReference()), valueNode->line);
|
||||
}
|
||||
names.push_back(name);
|
||||
|
||||
FCDImage* image = GetDocument()->FindImage(name);
|
||||
if (image == NULL)
|
||||
{
|
||||
return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), valueNode->line);
|
||||
}
|
||||
images.push_back(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Check if it's initialized as PLANAR
|
||||
if(!initialized)
|
||||
{
|
||||
valueNode = FindChildByType(surfaceNode, DAE_INITPLANAR_ELEMENT);
|
||||
if(valueNode)
|
||||
{
|
||||
initialized = true;
|
||||
initMethod = FCDEffectParameterSurfaceInitFactory::Create(FCDEffectParameterSurfaceInitFactory::PLANAR);
|
||||
|
||||
//Check if it's an ALL reference
|
||||
xmlNode* refNode = FindChildByType(valueNode, DAE_ALL_ELEMENT);
|
||||
if(refNode)
|
||||
{
|
||||
string name = ReadNodeProperty(refNode, DAE_REF_ATTRIBUTE);
|
||||
if (name.empty())
|
||||
{
|
||||
return status.Fail(FS("<init_planar>'s all reference is empty in surface parameter: ") + TO_FSTRING(GetReference()), refNode->line);
|
||||
}
|
||||
names.push_back(name);
|
||||
|
||||
FCDImage* image = GetDocument()->FindImage(name);
|
||||
if (image == NULL)
|
||||
{
|
||||
return status.Fail(FS("Unable to find image source for surface parameter: ") + TO_FSTRING(GetReference()), refNode->line);
|
||||
}
|
||||
images.push_back(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It is acceptable for a surface not to have an initialization option
|
||||
//but we should flag a warning
|
||||
if(!initialized)
|
||||
{
|
||||
DebugOut("Warning: surface %s not initialized", GetReference().c_str());
|
||||
}
|
||||
|
||||
xmlNode* sizeNode = FindChildByType(parameterNode, DAE_SIZE_ELEMENT);
|
||||
size = FUStringConversion::ToPoint(ReadNodeContentDirect(sizeNode));
|
||||
xmlNode* viewportRatioNode = FindChildByType(parameterNode, DAE_VIEWPORT_RATIO);
|
||||
viewportRatio = FUStringConversion::ToFloat(ReadNodeContentDirect(viewportRatioNode));
|
||||
xmlNode* mipLevelsNode = FindChildByType(parameterNode, DAE_MIP_LEVELS);
|
||||
mipLevelCount = (uint16) FUStringConversion::ToInt32(ReadNodeContentDirect(mipLevelsNode));
|
||||
xmlNode* mipmapGenerateNode = FindChildByType(parameterNode, DAE_MIPMAP_GENERATE);
|
||||
generateMipmaps = FUStringConversion::ToBoolean(ReadNodeContentDirect(mipmapGenerateNode));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectParameterSurface::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* parameterNode = FCDEffectParameter::WriteToXML(parentNode);
|
||||
xmlNode* surfaceNode = AddChild(parameterNode, DAE_FXCMN_SURFACE_ELEMENT);
|
||||
if (!images.empty() && initMethod != NULL)
|
||||
{
|
||||
switch (initMethod->GetInitType())
|
||||
{
|
||||
case FCDEffectParameterSurfaceInitFactory::FROM:
|
||||
{
|
||||
//Since 1.4.1, there are two possibilities here.
|
||||
//Possibility 1
|
||||
//<init_from> image1 image2...imageN </init_from>
|
||||
|
||||
//Possibility 2
|
||||
//<init_from mip=... face=... slice=...> image1 </init_from>
|
||||
//<init_from mip=... face=... slice=...> image2 </init_from>
|
||||
|
||||
FCDEffectParameterSurfaceInitFrom* in = (FCDEffectParameterSurfaceInitFrom*)initMethod;
|
||||
size_t size = images.size(); //images.size() should always be equal to names.size()
|
||||
|
||||
if( size == in->face.size() || size == in->mip.size() || size == in->slice.size())
|
||||
{
|
||||
//This is possibility 2
|
||||
for(uint32 i=0; i<size; i++)
|
||||
{
|
||||
xmlNode* childNode = AddChild(surfaceNode, DAE_INITFROM_ELEMENT, images[i]->GetDaeId());
|
||||
AddAttribute(childNode, DAE_MIP_ATTRIBUTE, in->mip[i]);
|
||||
AddAttribute(childNode, DAE_SLICE_ATTRIBUTE, in->slice[i]);
|
||||
AddAttribute(childNode, DAE_FACE_ATTRIBUTE, in->face[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//This is possibility 1
|
||||
globalSBuilder.reserve(size * 18); // Pulled out of a hat
|
||||
StringList::const_iterator itV = names.begin();
|
||||
globalSBuilder.set(*itV);
|
||||
for (++itV; itV != names.end(); ++itV)
|
||||
{
|
||||
globalSBuilder.append(' ');
|
||||
globalSBuilder.append(*itV);
|
||||
}
|
||||
|
||||
xmlNode* childNode = AddChild(surfaceNode, DAE_INITFROM_ELEMENT);
|
||||
AddContent(childNode, globalSBuilder.ToString());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FCDEffectParameterSurfaceInitFactory::AS_NULL:
|
||||
{
|
||||
AddChild(surfaceNode, DAE_INITASNULL_ELEMENT);
|
||||
break;
|
||||
}
|
||||
case FCDEffectParameterSurfaceInitFactory::AS_TARGET:
|
||||
{
|
||||
AddChild(surfaceNode, DAE_INITASTARGET_ELEMENT);
|
||||
break;
|
||||
}
|
||||
case FCDEffectParameterSurfaceInitFactory::VOLUME:
|
||||
{
|
||||
FCDEffectParameterSurfaceInitVolume* in = (FCDEffectParameterSurfaceInitVolume*)initMethod;
|
||||
xmlNode* childNode = AddChild(surfaceNode, DAE_INITVOLUME_ELEMENT);
|
||||
if(in->volumeType == FCDEffectParameterSurfaceInitVolume::ALL)
|
||||
{
|
||||
xmlNode* typeNode = AddChild(childNode, DAE_ALL_ELEMENT);
|
||||
AddAttribute(typeNode, DAE_REF_ATTRIBUTE, names[0]);
|
||||
}
|
||||
else if(in->volumeType == FCDEffectParameterSurfaceInitVolume::PRIMARY)
|
||||
{
|
||||
xmlNode* typeNode = AddChild(childNode, DAE_PRIMARY_ELEMENT);
|
||||
AddAttribute(typeNode, DAE_REF_ATTRIBUTE, names[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FCDEffectParameterSurfaceInitFactory::CUBE:
|
||||
{
|
||||
FCDEffectParameterSurfaceInitCube* in = (FCDEffectParameterSurfaceInitCube*)initMethod;
|
||||
xmlNode* childNode = AddChild(surfaceNode, DAE_INITCUBE_ELEMENT);
|
||||
if(in->cubeType == FCDEffectParameterSurfaceInitCube::ALL)
|
||||
{
|
||||
xmlNode* typeNode = AddChild(childNode, DAE_ALL_ELEMENT);
|
||||
AddAttribute(typeNode, DAE_REF_ATTRIBUTE, names[0]);
|
||||
}
|
||||
else if(in->cubeType == FCDEffectParameterSurfaceInitCube::PRIMARY)
|
||||
{
|
||||
xmlNode* typeNode = AddChild(childNode, DAE_PRIMARY_ELEMENT);
|
||||
AddChild(typeNode, DAE_ORDER_ELEMENT); //FIXME: complete when the spec gets more info.
|
||||
AddAttribute(typeNode, DAE_REF_ATTRIBUTE, names[0]);
|
||||
}
|
||||
if(in->cubeType == FCDEffectParameterSurfaceInitCube::FACE)
|
||||
{
|
||||
xmlNode* childNode = AddChild(surfaceNode, DAE_FACE_ELEMENT);
|
||||
AddAttribute(childNode, DAE_REF_ATTRIBUTE, names[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FCDEffectParameterSurfaceInitFactory::PLANAR:
|
||||
{
|
||||
xmlNode* childNode = AddChild(surfaceNode, DAE_INITPLANAR_ELEMENT);
|
||||
xmlNode* typeNode = AddChild(childNode, DAE_ALL_ELEMENT);
|
||||
AddAttribute(typeNode, DAE_REF_ATTRIBUTE, names[0]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
|
||||
void FCDEffectParameterSurfaceInit::Clone(FCDEffectParameterSurfaceInit* UNUSED(clone))
|
||||
{
|
||||
//no member variables to copy in this class, but leave this for future use.
|
||||
}
|
||||
|
||||
FCDEffectParameterSurfaceInitCube::FCDEffectParameterSurfaceInitCube()
|
||||
{
|
||||
cubeType = ALL;
|
||||
}
|
||||
|
||||
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitCube::Clone()
|
||||
{
|
||||
FCDEffectParameterSurfaceInitCube* clone = new FCDEffectParameterSurfaceInitCube();
|
||||
FCDEffectParameterSurfaceInit::Clone(clone);
|
||||
clone->cubeType = cubeType;
|
||||
return clone;
|
||||
}
|
||||
|
||||
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitFrom::Clone()
|
||||
{
|
||||
FCDEffectParameterSurfaceInitFrom* clone = new FCDEffectParameterSurfaceInitFrom();
|
||||
FCDEffectParameterSurfaceInit::Clone(clone);
|
||||
clone->face = face;
|
||||
clone->mip = mip;
|
||||
clone->slice = slice;
|
||||
return clone;
|
||||
}
|
||||
|
||||
FCDEffectParameterSurfaceInitVolume::FCDEffectParameterSurfaceInitVolume()
|
||||
{
|
||||
volumeType = ALL;
|
||||
}
|
||||
|
||||
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitVolume::Clone()
|
||||
{
|
||||
FCDEffectParameterSurfaceInitVolume* clone = new FCDEffectParameterSurfaceInitVolume();
|
||||
FCDEffectParameterSurfaceInit::Clone(clone);
|
||||
clone->volumeType = volumeType;
|
||||
return clone;
|
||||
}
|
||||
|
||||
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitAsNull::Clone()
|
||||
{
|
||||
FCDEffectParameterSurfaceInitAsNull* clone = new FCDEffectParameterSurfaceInitAsNull();
|
||||
FCDEffectParameterSurfaceInit::Clone(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitAsTarget::Clone()
|
||||
{
|
||||
FCDEffectParameterSurfaceInitAsTarget* clone = new FCDEffectParameterSurfaceInitAsTarget();
|
||||
FCDEffectParameterSurfaceInit::Clone(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitPlanar::Clone()
|
||||
{
|
||||
FCDEffectParameterSurfaceInitPlanar* clone = new FCDEffectParameterSurfaceInitPlanar();
|
||||
FCDEffectParameterSurfaceInit::Clone(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
FCDEffectParameterSurfaceInit* FCDEffectParameterSurfaceInitFactory::Create(InitType type)
|
||||
{
|
||||
FCDEffectParameterSurfaceInit* parameter = NULL;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case FCDEffectParameterSurfaceInitFactory::AS_NULL: parameter = new FCDEffectParameterSurfaceInitAsNull(); break;
|
||||
case FCDEffectParameterSurfaceInitFactory::AS_TARGET: parameter = new FCDEffectParameterSurfaceInitAsTarget(); break;
|
||||
case FCDEffectParameterSurfaceInitFactory::CUBE: parameter = new FCDEffectParameterSurfaceInitCube(); break;
|
||||
case FCDEffectParameterSurfaceInitFactory::FROM: parameter = new FCDEffectParameterSurfaceInitFrom(); break;
|
||||
case FCDEffectParameterSurfaceInitFactory::PLANAR: parameter = new FCDEffectParameterSurfaceInitPlanar(); break;
|
||||
case FCDEffectParameterSurfaceInitFactory::VOLUME: parameter = new FCDEffectParameterSurfaceInitVolume(); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return parameter;
|
||||
}
|
||||
435
Extras/FCollada/FCDocument/FCDEffectParameterSurface.h
Normal file
435
Extras/FCollada/FCDocument/FCDEffectParameterSurface.h
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
Copyright (C) 2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDEffectParameterSurface.h
|
||||
This file contains the FCDEffectParameterSurface class,
|
||||
the FCDEffectParameterSurfaceInit interface and its derivate classes.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_EFFECT_PARAMETER_SURFACE_H_
|
||||
#define _FCD_EFFECT_PARAMETER_SURFACE_H_
|
||||
|
||||
#include "FCDocument/FCDEffectParameter.h"
|
||||
|
||||
class FCDEffectParameterSurfaceInit;
|
||||
|
||||
/** A dynamically-sized array of COLLADA images */
|
||||
typedef std::vector<FCDImage*> FCDImageList;
|
||||
|
||||
/**
|
||||
A COLLADA surface parameter.
|
||||
This parameters hold the texture loading information. The texture
|
||||
placement information should be held by the sampler parameter.
|
||||
|
||||
@see FCDEffectParameterSampler
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterSurface : public FCDEffectParameter
|
||||
{
|
||||
private:
|
||||
StringList names;
|
||||
FCDImageList images;
|
||||
FCDEffectParameterSurfaceInit* initMethod;
|
||||
FMVector3 size;
|
||||
float viewportRatio;
|
||||
uint16 mipLevelCount;
|
||||
bool generateMipmaps;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::AddParameter function.
|
||||
@param document The COLLADA document that owns the effect parameter. */
|
||||
FCDEffectParameterSurface(FCDocument* document);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectParameterList::ReleaseParameter function.
|
||||
When released, the effect parameter list will also release all
|
||||
its parameters, if it owns them. */
|
||||
virtual ~FCDEffectParameterSurface();
|
||||
|
||||
/** Retrieves the type of effect parameter class.
|
||||
@return The parameter class type: SURFACE. */
|
||||
virtual Type GetType() const { return SURFACE; }
|
||||
|
||||
/** Retrieves the initialization method for the surface parameter.
|
||||
The initialization method is a powerful method of describing how
|
||||
to build complex textures, such as cube maps, from one or
|
||||
multiple image files.
|
||||
@return The surface initialization method. This pointer will be NULL,
|
||||
if no initialization method is provided. */
|
||||
FCDEffectParameterSurfaceInit* GetInitMethod() { return initMethod; }
|
||||
const FCDEffectParameterSurfaceInit* GetInitMethod() const { return initMethod; } /**< See above. */
|
||||
|
||||
/** Sets the initialization method for the surface parameter.
|
||||
The initialization method is a powerful method of describing how
|
||||
to build complex textures, such as cube maps, from one or
|
||||
multiple image files.
|
||||
@param method The new initialization method.
|
||||
The old initialization method will be released.
|
||||
You should create a new initialization method
|
||||
for each surface parameter. */
|
||||
void SetInitMethod(FCDEffectParameterSurfaceInit* method);
|
||||
|
||||
/** Retrieves the number of COLLADA images that make up this surface.
|
||||
There should never be more than six images to build a surface.
|
||||
In the large majority of cases, expect one image.
|
||||
@return The number of images. */
|
||||
size_t GetImageCount() const { return images.size(); }
|
||||
|
||||
/** Retrieves the list of images that make up this surface.
|
||||
There should never be more than six images to build a surface.
|
||||
In the large majority of cases, expect one image.
|
||||
@return The list of images. */
|
||||
FCDImageList& GetImages() { return images; }
|
||||
const FCDImageList& GetImages() const { return images; } /**< See above. */
|
||||
|
||||
/** Retrieves a specific image.
|
||||
@param index The index of the image.
|
||||
@return The image. This pointer will be NULL if the index is out-of-bounds. */
|
||||
FCDImage* GetImage(size_t index = 0) { return index < images.size() ? images.at(index) : NULL; }
|
||||
const FCDImage* GetImage(size_t index = 0) const { return index < images.size() ? images.at(index) : NULL; } /**< See above. */
|
||||
|
||||
/** Retrieves the index that matches the given image.
|
||||
@param image The image to match.
|
||||
@return The index within the list for this image.
|
||||
This index may be -1 if no match was found. */
|
||||
size_t FindImage(const FCDImage* image) const;
|
||||
|
||||
/** Adds an image to the list.
|
||||
The initialization method indexes the images from this list.
|
||||
This function will verify that this image does not already exist within the list,
|
||||
so use the returned index.
|
||||
@param image The new image.
|
||||
@return The index of the image within the list. */
|
||||
size_t AddImage(FCDImage* image);
|
||||
|
||||
/** Removes an image from the list.
|
||||
The initialization method indexes the images from this list.
|
||||
This function will shift all the indexes in the initialization method
|
||||
so that they continue matching the correct image.
|
||||
@param image The image to remove. Its memory is not released. */
|
||||
void RemoveImage(FCDImage* image);
|
||||
|
||||
/** Retrieves the wanted dimensions of the surface.
|
||||
This parameter is optional and may contain all zeroes to indicate
|
||||
that you should read the surface dimensions from the image file(s).
|
||||
@return The wanted dimensions. */
|
||||
const FMVector3& GetSize() const { return size; }
|
||||
|
||||
/** Sets the wanted dimensions of the surface.
|
||||
This parameter is optional and can contain all zeroes to indicate
|
||||
that you should read the surface dimensions from the image file(s).
|
||||
@param dimensions The wanted dimensions. */
|
||||
void SetSize(const FMVector3& dimensions) { size = dimensions; }
|
||||
|
||||
/** Retrieves the viewport ratio to use when the surface is a render target.
|
||||
@return The viewport ratio. */
|
||||
float GetViewportRatio() const { return viewportRatio; }
|
||||
|
||||
/** Sets the viewport ratio to use when the surface is a render target.
|
||||
@param ratio The viewport ratio. */
|
||||
void SetViewportRatio(float ratio) { viewportRatio = ratio; }
|
||||
|
||||
/** Retrieves the wanted number of mip-levels.
|
||||
This parameter is optional and may be zero to indicate that you should
|
||||
retrieve the mip-levels from the image file(s) or generate a full
|
||||
mip-chain, depending on the mip-map generate flag.
|
||||
@see GetMipMapGenerate
|
||||
@return The wanted number of mip-levels. */
|
||||
uint16 GetMipLevelCount() const { return mipLevelCount; }
|
||||
|
||||
/** Sets the wanted number of mip-levels.
|
||||
This parameter is optional and can be zero to indicate that you should
|
||||
retrieve the mip-levels from the image file(s) or generate a full
|
||||
mip-chain, depending on the mip-map generate flag.
|
||||
@param levelCount The wanted number of mip-levels. */
|
||||
void SetMipLevelCount(uint16 levelCount) { mipLevelCount = levelCount; }
|
||||
|
||||
/** Retrieves whether to generate the mip-map levels on load.
|
||||
The alternative is to load the mip-map levels from the image files.
|
||||
@return Whether to generate the mip-map levels on load. */
|
||||
bool IsGenerateMipMaps() const { return generateMipmaps; }
|
||||
|
||||
/** Sets whether to generate the mip-map levels of load.
|
||||
The alternative is to load the mip-map levels from the image files.
|
||||
@param _generateMipmaps Whether to generate the mip-map levels on load. */
|
||||
void SetGenerateMipMaps(bool _generateMipmaps) { generateMipmaps = _generateMipmaps; }
|
||||
|
||||
/** Retrieves a specific sub-id.
|
||||
@todo I'm not too sure of the implications of the names,
|
||||
at this level of abstraction: once I'm clear why they exists, add the
|
||||
necessary interface to access/pull/push items from/to the list.
|
||||
@param index The sub-id index.
|
||||
@return The sub-id. This pointer will be NULL if the index is out-of-bounds. */
|
||||
const char* GetName(size_t index = 0) const { return (index < names.size()) ? names[index].c_str() : NULL; }
|
||||
|
||||
/** Creates a full copy of the effect parameter.
|
||||
@todo The cloning does not clone the initialization method correctly.
|
||||
@return The cloned effect parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameter* Clone();
|
||||
|
||||
/** [INTERNAL] Overwrites the target parameter with this parameter.
|
||||
This function is used during the flattening of materials.
|
||||
@param target The target parameter to overwrite. */
|
||||
virtual void Overwrite(FCDEffectParameter* target);
|
||||
|
||||
/** [INTERNAL] Reads in the effect parameter from a given COLLADA XML tree node.
|
||||
@param parameterNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the parameter.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* parameterNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect parameter to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the parameter.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
[INTERNAL] The factory for COLLADA effect parameter surface initialization.
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitFactory
|
||||
{
|
||||
private:
|
||||
// Never instantiate: this is a static class
|
||||
FCDEffectParameterSurfaceInitFactory() {}
|
||||
|
||||
public:
|
||||
|
||||
/** The supported initialization types. */
|
||||
enum InitType
|
||||
{
|
||||
FROM, /**< Loads a surface from one simple image file. @see FCDEffectParameterSurfaceInitFrom */
|
||||
AS_NULL, /**< No initialization. This surface may be initialized by some future effect parameter override. */
|
||||
AS_TARGET, /**< Initializes an engine-specific render target for offscreen rendering. In this case, the dimensions should be provided by the surface effect parameter. */
|
||||
CUBE, /**< Loads a cube-map from one complex image file or six simple image files. @see FCDEffectParameterSurfaceInitCube */
|
||||
VOLUME, /**< Loads a 3D images for one image file. @see FCDEffectParameterSurfaceInitVolume */
|
||||
PLANAR /**< Loads a surface from one simple image file. */
|
||||
};
|
||||
|
||||
/** [INTERNAL] Creates a new effect surface initialization parameter, given a type.
|
||||
@param type The type of initialization parameter to create.*/
|
||||
static FCDEffectParameterSurfaceInit* Create(InitType type);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
A surface initialization method.
|
||||
In COLLADA 1.4.1, this information was added to support complex surface types.
|
||||
There are six types of initialization methods, described in the InitType enumerated type.
|
||||
Expect the FROM initialization type in the large majority of cases.
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInit
|
||||
{
|
||||
public:
|
||||
|
||||
/** Constructor: builds a new surface initialization method. */
|
||||
FCDEffectParameterSurfaceInit() {}
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~FCDEffectParameterSurfaceInit() {}
|
||||
|
||||
/** Retrieves the initialization type. You cannot modify this value.
|
||||
To change the initialization type of a surface parameter, create a new
|
||||
surface initialization structure of the correct type.
|
||||
@return The initialization type. */
|
||||
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const = 0;
|
||||
|
||||
/** Copies all member variables into clone.
|
||||
@param clone a valid pointer to a FCDEffectParameterSurfaceInit object*/
|
||||
void Clone(FCDEffectParameterSurfaceInit* clone);
|
||||
|
||||
/** Creates a full copy of the surface initialization parameter.
|
||||
@return The surface initialization parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameterSurfaceInit* Clone() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
A cube-map surface initialization method.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitCube : public FCDEffectParameterSurfaceInit
|
||||
{
|
||||
public:
|
||||
/** The types of cube-map initializations. */
|
||||
enum CubeType
|
||||
{
|
||||
ALL, /** Load all the mip-levels of all the cube-map faces from one image file. */
|
||||
PRIMARY, /** Load the first mip-level of all the cube-map faces from one image file. */
|
||||
FACE /** Load all the cube-map faces from separate image files. */
|
||||
};
|
||||
|
||||
public:
|
||||
/** Constructor: builds a new cube-map initialization method. */
|
||||
FCDEffectParameterSurfaceInitCube();
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~FCDEffectParameterSurfaceInitCube() {}
|
||||
|
||||
/** Retrieves the initialization type. You cannot modify this value.
|
||||
To change the initialization type of a surface parameter, create a new
|
||||
surface initialization structure of the correct type.
|
||||
@return The initialization type. */
|
||||
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const {return FCDEffectParameterSurfaceInitFactory::CUBE;}
|
||||
|
||||
/** Creates a full copy of the surface initialization parameter.
|
||||
@return The surface initialization parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameterSurfaceInit* Clone();
|
||||
|
||||
/** The type of cube-map initialization. */
|
||||
CubeType cubeType;
|
||||
|
||||
/** The list of image indices.
|
||||
The images are contained within the surface effect parameter.
|
||||
This is used only for the FACE cube-map initialization type and indicates
|
||||
how to match the faces of faces of the cube-map with the images in the surface effect parameter. */
|
||||
UInt16List order;
|
||||
};
|
||||
|
||||
/**
|
||||
A volumetric surface initialization method.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitVolume : public FCDEffectParameterSurfaceInit
|
||||
{
|
||||
public:
|
||||
/** The types of volumetric surfaces initialization. */
|
||||
enum VolumeType
|
||||
{
|
||||
ALL, /** Load all the mip-levels from the image file. */
|
||||
PRIMARY /** Load the first mip-level from the image file. */
|
||||
};
|
||||
|
||||
public:
|
||||
/** Constructor: builds a new volumetric surface initialization method. */
|
||||
FCDEffectParameterSurfaceInitVolume();
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~FCDEffectParameterSurfaceInitVolume() {}
|
||||
|
||||
/** Retrieves the initialization type. You cannot modify this value.
|
||||
To change the initialization type of a surface parameter, create a new
|
||||
surface initialization structure of the correct type.
|
||||
@return The initialization type. */
|
||||
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const {return FCDEffectParameterSurfaceInitFactory::VOLUME;}
|
||||
|
||||
/** Creates a full copy of the surface initialization parameter.
|
||||
@return The surface initialization parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameterSurfaceInit* Clone();
|
||||
|
||||
/** The type of volumetric initialization. */
|
||||
VolumeType volumeType;
|
||||
};
|
||||
|
||||
/**
|
||||
A simple file surface initialization method.
|
||||
This is the method used for backward-compatibility.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitFrom : public FCDEffectParameterSurfaceInit
|
||||
{
|
||||
public:
|
||||
/** Constructor: builds a new file surface initialization method. */
|
||||
FCDEffectParameterSurfaceInitFrom() {}
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~FCDEffectParameterSurfaceInitFrom() {}
|
||||
|
||||
/** Retrieves the initialization type. You cannot modify this value.
|
||||
To change the initialization type of a surface parameter, create a new
|
||||
surface initialization structure of the correct type.
|
||||
@return The initialization type. */
|
||||
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const {return FCDEffectParameterSurfaceInitFactory::FROM;}
|
||||
|
||||
/** Creates a full copy of the surface initialization parameter.
|
||||
@return The surface initialization parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameterSurfaceInit* Clone();
|
||||
|
||||
/** The list of mip levels. */
|
||||
StringList mip;
|
||||
|
||||
/** The list of matching slices. */
|
||||
StringList slice;
|
||||
|
||||
/** The list of matching faces. */
|
||||
StringList face;
|
||||
};
|
||||
|
||||
/**
|
||||
This method allows to initialize the surface at a later point.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitAsNull : public FCDEffectParameterSurfaceInit
|
||||
{
|
||||
public:
|
||||
/** Constructor: builds a new file surface initialization method. */
|
||||
FCDEffectParameterSurfaceInitAsNull() {}
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~FCDEffectParameterSurfaceInitAsNull() {}
|
||||
|
||||
/** Retrieves the initialization type. You cannot modify this value.
|
||||
To change the initialization type of a surface parameter, create a new
|
||||
surface initialization structure of the correct type.
|
||||
@return The initialization type. */
|
||||
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const {return FCDEffectParameterSurfaceInitFactory::AS_NULL;}
|
||||
|
||||
/** Creates a full copy of the surface initialization parameter.
|
||||
@return The surface initialization parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameterSurfaceInit* Clone();
|
||||
};
|
||||
|
||||
/**
|
||||
This method allows to initialize the surface as a rendering target.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitAsTarget : public FCDEffectParameterSurfaceInit
|
||||
{
|
||||
public:
|
||||
/** Constructor: builds a new file surface initialization method. */
|
||||
FCDEffectParameterSurfaceInitAsTarget() {};
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~FCDEffectParameterSurfaceInitAsTarget() {}
|
||||
|
||||
/** Retrieves the initialization type. You cannot modify this value.
|
||||
To change the initialization type of a surface parameter, create a new
|
||||
surface initialization structure of the correct type.
|
||||
@return The initialization type. */
|
||||
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const {return FCDEffectParameterSurfaceInitFactory::AS_TARGET;}
|
||||
|
||||
/** Creates a full copy of the surface initialization parameter.
|
||||
@return The surface initialization parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameterSurfaceInit* Clone();
|
||||
};
|
||||
|
||||
/**
|
||||
This method allows to initialize the surface as planar.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectParameterSurfaceInitPlanar : public FCDEffectParameterSurfaceInit
|
||||
{
|
||||
public:
|
||||
/** Constructor: builds a new file surface initialization method. */
|
||||
FCDEffectParameterSurfaceInitPlanar() {};
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~FCDEffectParameterSurfaceInitPlanar() {}
|
||||
|
||||
/** Retrieves the initialization type. You cannot modify this value.
|
||||
To change the initialization type of a surface parameter, create a new
|
||||
surface initialization structure of the correct type.
|
||||
@return The initialization type. */
|
||||
virtual FCDEffectParameterSurfaceInitFactory::InitType GetInitType() const {return FCDEffectParameterSurfaceInitFactory::PLANAR;}
|
||||
|
||||
/** Creates a full copy of the surface initialization parameter.
|
||||
@return The surface initialization parameter. You will need to delete this pointer. */
|
||||
virtual FCDEffectParameterSurfaceInit* Clone();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // _FCD_EFFECT_PARAMETER_SURFACE_H_
|
||||
194
Extras/FCollada/FCDocument/FCDEffectPass.cpp
Normal file
194
Extras/FCollada/FCDocument/FCDEffectPass.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDEffectTechnique.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDEffectPass.h"
|
||||
#include "FCDocument/FCDEffectPassShader.h"
|
||||
#include "FCDocument/FCDEffectParameter.h"
|
||||
#include "FCDocument/FCDEffectParameterList.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDEffectPass::FCDEffectPass(FCDocument* document, FCDEffectTechnique *_parent) : FCDObject(document, "FCDEffectPass")
|
||||
{
|
||||
parent = _parent;
|
||||
}
|
||||
|
||||
FCDEffectPass::~FCDEffectPass()
|
||||
{
|
||||
CLEAR_POINTER_VECTOR(shaders);
|
||||
meshdata.clear();
|
||||
parent = NULL;
|
||||
}
|
||||
|
||||
// Adds a new shader to the pass.
|
||||
FCDEffectPassShader* FCDEffectPass::AddShader()
|
||||
{
|
||||
FCDEffectPassShader* shader = new FCDEffectPassShader(GetDocument(), this);
|
||||
shaders.push_back(shader);
|
||||
return shader;
|
||||
}
|
||||
|
||||
// Releases a shader contained within the pass.
|
||||
void FCDEffectPass::ReleaseShader(FCDEffectPassShader* shader)
|
||||
{
|
||||
FCDEffectPassShaderList::iterator it = std::find(shaders.begin(), shaders.end(), shader);
|
||||
if (it != shaders.end())
|
||||
{
|
||||
delete *it;
|
||||
shaders.push_back(shader);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a new vertex shader to the pass.
|
||||
// If a vertex shader already exists within the pass, it will be released.
|
||||
FCDEffectPassShader* FCDEffectPass::AddVertexShader()
|
||||
{
|
||||
FCDEffectPassShader* vertexShader;
|
||||
for (vertexShader = GetVertexShader(); vertexShader != NULL; vertexShader = GetVertexShader())
|
||||
{
|
||||
ReleaseShader(vertexShader);
|
||||
}
|
||||
|
||||
vertexShader = AddShader();
|
||||
vertexShader->AffectsVertices();
|
||||
return vertexShader;
|
||||
}
|
||||
|
||||
// Adds a new fragment shader to the pass.
|
||||
// If a fragment shader already exists within the pass, it will be released.
|
||||
FCDEffectPassShader* FCDEffectPass::AddFragmentShader()
|
||||
{
|
||||
FCDEffectPassShader* fragmentShader;
|
||||
for (fragmentShader = GetFragmentShader(); fragmentShader != NULL; fragmentShader = GetFragmentShader())
|
||||
{
|
||||
ReleaseShader(fragmentShader);
|
||||
}
|
||||
|
||||
fragmentShader = AddShader();
|
||||
fragmentShader->AffectsFragments();
|
||||
return fragmentShader;
|
||||
}
|
||||
|
||||
FCDEffectPass* FCDEffectPass::Clone(FCDEffectTechnique* newParent) const
|
||||
{
|
||||
FCDEffectPass* clone = new FCDEffectPass(GetDocument(), newParent);
|
||||
clone->name = name;
|
||||
clone->meshdata = meshdata;
|
||||
|
||||
// Clone the shaderss
|
||||
clone->shaders.reserve(shaders.size());
|
||||
for (FCDEffectPassShaderList::const_iterator itS = shaders.begin(); itS != shaders.end(); ++itS)
|
||||
{
|
||||
clone->shaders.push_back((*itS)->Clone(clone));
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
const string& FCDEffectPass::GetDaeId() const
|
||||
{
|
||||
return parent->GetDaeId();
|
||||
}
|
||||
|
||||
// Retrieve the type-specific shaders
|
||||
FCDEffectPassShader* FCDEffectPass::GetVertexShader()
|
||||
{
|
||||
for (FCDEffectPassShaderList::iterator itS = shaders.begin(); itS != shaders.end(); ++itS)
|
||||
{
|
||||
if ((*itS)->IsVertexShader()) return (*itS);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
const FCDEffectPassShader* FCDEffectPass::GetVertexShader() const
|
||||
{
|
||||
for (FCDEffectPassShaderList::const_iterator itS = shaders.begin(); itS != shaders.end(); ++itS)
|
||||
{
|
||||
if ((*itS)->IsVertexShader()) return (*itS);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FCDEffectPassShader* FCDEffectPass::GetFragmentShader()
|
||||
{
|
||||
for (FCDEffectPassShaderList::iterator itS = shaders.begin(); itS != shaders.end(); ++itS)
|
||||
{
|
||||
if ((*itS)->IsFragmentShader()) return (*itS);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
const FCDEffectPassShader* FCDEffectPass::GetFragmentShader() const
|
||||
{
|
||||
for (FCDEffectPassShaderList::const_iterator itS = shaders.begin(); itS != shaders.end(); ++itS)
|
||||
{
|
||||
if ((*itS)->IsFragmentShader()) return (*itS);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FUStatus FCDEffectPass::LoadFromXML(xmlNode* passNode, xmlNode* techniqueNode, xmlNode* profileNode)
|
||||
{
|
||||
FUStatus status;
|
||||
if (!IsEquivalent(passNode->name, DAE_PASS_ELEMENT))
|
||||
{
|
||||
return status.Warning(FS("Pass contains unknown element."), passNode->line);
|
||||
}
|
||||
name = TO_FSTRING(ReadNodeProperty(passNode, DAE_SID_ATTRIBUTE));
|
||||
|
||||
// parse mesh data
|
||||
const char* smdnames[10] = { "COLOR0", "COLOR1", "TEXCOORD0", "TEXCOORD1", "TEXCOORD2", "TEXCOORD3", "TEXCOORD4", "TEXCOORD5", "TEXCOORD6", "TEXCOORD7" };
|
||||
for(uint32 i = 0; i < 10; ++i)
|
||||
{
|
||||
string smdname = smdnames[i];
|
||||
|
||||
string smdata = "";
|
||||
xmlNode *mdataNode = FindChildByProperty(profileNode, "sid", smdname.c_str() );
|
||||
if(mdataNode == NULL)
|
||||
mdataNode = FindChildByProperty(techniqueNode, "sid", smdname.c_str() );
|
||||
|
||||
if( mdataNode != NULL )
|
||||
{
|
||||
xmlNode *stringNode = FindChildByType(mdataNode, "string" );
|
||||
smdata = ReadNodeContentDirect(stringNode);
|
||||
}
|
||||
|
||||
meshdata.push_back(smdata);
|
||||
}
|
||||
|
||||
// Look for the <shader> elements
|
||||
xmlNodeList shaderNodes;
|
||||
FindChildrenByType(passNode, DAE_SHADER_ELEMENT, shaderNodes);
|
||||
for (xmlNodeList::iterator itS = shaderNodes.begin(); itS != shaderNodes.end(); ++itS)
|
||||
{
|
||||
FCDEffectPassShader* shader = new FCDEffectPassShader(GetDocument(), this);
|
||||
shaders.push_back(shader);
|
||||
status.AppendStatus(shader->LoadFromXML(*itS));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Write out the pass to the COLLADA xml node tree
|
||||
xmlNode* FCDEffectPass::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
// Write out the <pass> element, with the shader's name
|
||||
xmlNode* passNode = AddChild(parentNode, DAE_PASS_ELEMENT);
|
||||
if (!name.empty())
|
||||
{
|
||||
const_cast<FCDEffectPass*>(this)->name = TO_FSTRING(AddNodeSid(passNode, TO_STRING(name).c_str()));
|
||||
}
|
||||
|
||||
// Write out the shaders
|
||||
for (FCDEffectPassShaderList::const_iterator itS = shaders.begin(); itS != shaders.end(); ++itS)
|
||||
{
|
||||
(*itS)->WriteToXML(passNode);
|
||||
}
|
||||
|
||||
return passNode;
|
||||
}
|
||||
140
Extras/FCollada/FCDocument/FCDEffectPass.h
Normal file
140
Extras/FCollada/FCDocument/FCDEffectPass.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDEffectPass.h
|
||||
This file contains the FCDEffectPass class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_EFFECT_PASS_H_
|
||||
#define _FCD_EFFECT_PASS_H_
|
||||
|
||||
#include "FCDocument/FCDObject.h"
|
||||
|
||||
class FCDEffectTechnique;
|
||||
class FCDEffectParameter;
|
||||
class FCDEffectParameterList;
|
||||
class FCDEffectPassShader;
|
||||
|
||||
typedef vector<FCDEffectPassShader*> FCDEffectPassShaderList; /**< A dynamically-sized array of shaders. */
|
||||
typedef vector<string> MeshDataList; /**< @deprecated A dynamically-sized array of mesh bindings. These should be bound using the \<bind\> element, at the instantiation level! */
|
||||
|
||||
/**
|
||||
A COLLADA effect pass.
|
||||
|
||||
The effect pass contains a list of effect shaders. While they
|
||||
may be missing, it does not make sense for the effect pass to
|
||||
contain more than two shaders: a vertex shader and a fragment/pixel shader.
|
||||
|
||||
For this reason, we provide the GetVertexShader and the GetFragmentShader
|
||||
which we expect will be used for most applications, rather than looking
|
||||
through the list of shader objects.
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectPass : public FCDObject
|
||||
{
|
||||
private:
|
||||
fstring name;
|
||||
FCDEffectTechnique* parent;
|
||||
FCDEffectPassShaderList shaders;
|
||||
MeshDataList meshdata;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectTechnique::AddPass function.
|
||||
@param document The COLLADA document that owns this effect pass.
|
||||
@param _parent The effect technique that contains this effect pass. */
|
||||
FCDEffectPass(FCDocument* document, FCDEffectTechnique *_parent);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectTechnique::ReleasePass function. */
|
||||
virtual ~FCDEffectPass();
|
||||
|
||||
/** Retrieves the effect techniques which contains this effect pass.
|
||||
@return The parent technique. */
|
||||
FCDEffectTechnique* GetParent() { return parent; }
|
||||
const FCDEffectTechnique* GetParent() const { return parent; } /**< See above. */
|
||||
|
||||
/** Retrieves the COLLADA id of the parent effect.
|
||||
This function is mostly useful as a shortcut for debugging and reporting.
|
||||
@return The COLLADA id of the parent effect. */
|
||||
const string& GetDaeId() const;
|
||||
|
||||
/** Retrieves the sub-id of the effect pass.
|
||||
This sub-id is optional.
|
||||
@return The sub-id. */
|
||||
const fstring& GetPassName() const { return name; }
|
||||
|
||||
/** Sets the optional sub-id for the effect pass.
|
||||
This sub-id is optional.
|
||||
@param _name The sub-id. */
|
||||
void SetPassName(const fstring& _name) { name = _name; }
|
||||
|
||||
/** @deprecated Retrieves the list of mesh data bindings.
|
||||
This patches bad export data in ColladaMaya and will be removed soon.
|
||||
@return The list of mesh data bindings. */
|
||||
const MeshDataList& GetMeshData() const { return meshdata; }
|
||||
|
||||
/** Retrieves the number of shaders contained within the effect pass.
|
||||
@return The number of shaders. */
|
||||
size_t GetShaderCount() const { return shaders.size(); }
|
||||
|
||||
/** Retrieves a specific shader.
|
||||
@param index The index of the shader.
|
||||
@return The shader. This pointer will be NULL if the index is out-of-bounds. */
|
||||
FCDEffectPassShader* GetShader(size_t index) { FUAssert(index < GetShaderCount(), return NULL); return shaders.at(index); }
|
||||
const FCDEffectPassShader* GetShader(size_t index) const { FUAssert(index < GetShaderCount(), return NULL); return shaders.at(index); } /**< See above. */
|
||||
|
||||
/** Adds a new shader to the pass.
|
||||
@return The new shader. */
|
||||
FCDEffectPassShader* AddShader();
|
||||
|
||||
/** Releases a shader contained within the pass.
|
||||
@param shader The shader to release. */
|
||||
void ReleaseShader(FCDEffectPassShader* shader);
|
||||
|
||||
/** Retrieves the vertex shader for this effect pass.
|
||||
@return The vertex shader. This pointer will be NULL if no
|
||||
shader within the pass affects vertices. */
|
||||
FCDEffectPassShader* GetVertexShader();
|
||||
const FCDEffectPassShader* GetVertexShader() const; /**< See above. */
|
||||
|
||||
/** Retrieves the fragment shader for this effect pass.
|
||||
@return The fragment shader. This pointer will be NULL if no
|
||||
shader within the pass affects pixels/fragments. */
|
||||
FCDEffectPassShader* GetFragmentShader();
|
||||
const FCDEffectPassShader* GetFragmentShader() const; /**< See above. */
|
||||
|
||||
/** Adds a new vertex shader to the pass.
|
||||
If a vertex shader already exists within the pass, it will be released.
|
||||
@return The new vertex shader. */
|
||||
FCDEffectPassShader* AddVertexShader();
|
||||
|
||||
/** Adds a new fragment shader to the pass.
|
||||
If a fragment shader already exists within the pass, it will be released.
|
||||
@return The new fragment shader. */
|
||||
FCDEffectPassShader* AddFragmentShader();
|
||||
|
||||
/** [INTERNAL] Clones the full effect pass.
|
||||
@param newParent The effect technique that will contain the cloned profile.
|
||||
@return The cloned pass. This pointer will never be NULL. */
|
||||
FCDEffectPass* Clone(FCDEffectTechnique* newParent) const;
|
||||
|
||||
/** [INTERNAL] Reads in the effect pass from a given COLLADA XML tree node.
|
||||
@param passNode The COLLADA XML tree node.
|
||||
@param techniqueNode X @deprecated bad interface : this dependency must be taken out[3]
|
||||
@param profileNode X @deprecated bad interface : this dependency must be taken out[2]
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the effect pass.*/
|
||||
FUStatus LoadFromXML(xmlNode* passNode, xmlNode* techniqueNode, xmlNode* profileNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect pass to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the effect pass.
|
||||
@return The created element XML tree node. */
|
||||
xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
148
Extras/FCollada/FCDocument/FCDEffectPassShader.cpp
Normal file
148
Extras/FCollada/FCDocument/FCDEffectPassShader.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDEffectCode.h"
|
||||
#include "FCDocument/FCDEffectPass.h"
|
||||
#include "FCDocument/FCDEffectPassShader.h"
|
||||
#include "FCDocument/FCDEffectProfileFX.h"
|
||||
#include "FCDocument/FCDEffectTechnique.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDEffectPassShader::FCDEffectPassShader(FCDocument* document, FCDEffectPass* _parent) : FCDObject(document, "FCDEffectPassShader")
|
||||
{
|
||||
parent = _parent;
|
||||
isFragment = false;
|
||||
code = NULL;
|
||||
}
|
||||
|
||||
FCDEffectPassShader::~FCDEffectPassShader()
|
||||
{
|
||||
parent = NULL;
|
||||
code = NULL;
|
||||
}
|
||||
|
||||
|
||||
// Adds a new binding to this shader.
|
||||
FCDEffectPassBind* FCDEffectPassShader::AddBinding()
|
||||
{
|
||||
bindings.push_back(FCDEffectPassBind());
|
||||
return &bindings.back();
|
||||
}
|
||||
|
||||
// Releases a binding contained within this shader.
|
||||
void FCDEffectPassShader::ReleaseBinding(FCDEffectPassBind* binding)
|
||||
{
|
||||
for (FCDEffectPassBindList::iterator it = bindings.begin(); it != bindings.end(); ++it)
|
||||
{
|
||||
if (&(*it) == binding)
|
||||
{
|
||||
bindings.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cloning
|
||||
FCDEffectPassShader* FCDEffectPassShader::Clone(FCDEffectPass* newParent) const
|
||||
{
|
||||
FCDEffectPassShader* clone = new FCDEffectPassShader(GetDocument(), newParent);
|
||||
clone->isFragment = isFragment;
|
||||
clone->bindings = bindings;
|
||||
clone->compilerTarget = compilerTarget;
|
||||
clone->compilerOptions = compilerOptions;
|
||||
clone->name = name;
|
||||
|
||||
// Look for the new code within the parent.
|
||||
if (code != NULL)
|
||||
{
|
||||
clone->code = newParent->GetParent()->FindCode(code->GetSid());
|
||||
if (clone->code == NULL) clone->code = newParent->GetParent()->GetParent()->FindCode(code->GetSid());
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Read in the ColladaFX pass shader from the xml node tree
|
||||
FUStatus FCDEffectPassShader::LoadFromXML(xmlNode* shaderNode)
|
||||
{
|
||||
FUStatus status;
|
||||
if (!IsEquivalent(shaderNode->name, DAE_SHADER_ELEMENT))
|
||||
{
|
||||
return status.Warning(FS("Pass shader contains unknown element."), shaderNode->line);
|
||||
}
|
||||
|
||||
// Read in the shader's name and stage
|
||||
xmlNode* nameNode = FindChildByType(shaderNode, DAE_FXCMN_NAME_ELEMENT);
|
||||
name = ReadNodeContentDirect(nameNode);
|
||||
string codeSource = ReadNodeProperty(nameNode, DAE_SOURCE_ATTRIBUTE);
|
||||
if (name.empty())
|
||||
{
|
||||
return status.Warning(FS("Unnamed effect pass shader found."), shaderNode->line);
|
||||
}
|
||||
string stage = ReadNodeStage(shaderNode);
|
||||
isFragment = stage == DAE_FXCMN_FRAGMENT_SHADER;
|
||||
if (!isFragment && stage != DAE_FXCMN_VERTEX_SHADER)
|
||||
{
|
||||
return status.Warning(FS("Unknown stage for effect pass shader: ") + TO_FSTRING(name), shaderNode->line);
|
||||
}
|
||||
|
||||
// Look-up the code filename for this shader, if available
|
||||
code = parent->GetParent()->FindCode(codeSource);
|
||||
if (code == NULL) code = parent->GetParent()->GetParent()->FindCode(codeSource);
|
||||
|
||||
// Read in the compiler-related elements
|
||||
xmlNode* compilerTargetNode = FindChildByType(shaderNode, DAE_FXCMN_COMPILERTARGET_ELEMENT);
|
||||
compilerTarget = TO_FSTRING(ReadNodeContentDirect(compilerTargetNode));
|
||||
xmlNode* compilerOptionsNode = FindChildByType(shaderNode, DAE_FXCMN_COMPILEROPTIONS_ELEMENT);
|
||||
compilerOptions = TO_FSTRING(ReadNodeContentDirect(compilerOptionsNode));
|
||||
|
||||
// Read in the bind parameters
|
||||
xmlNodeList bindNodes;
|
||||
FindChildrenByType(shaderNode, DAE_FXCMN_BIND_ELEMENT, bindNodes);
|
||||
for (xmlNodeList::iterator itB = bindNodes.begin(); itB != bindNodes.end(); ++itB)
|
||||
{
|
||||
xmlNode* paramNode = FindChildByType(*itB, DAE_PARAMETER_ELEMENT);
|
||||
|
||||
FCDEffectPassBind& bind = *(bindings.insert(bindings.end(), FCDEffectPassBind()));
|
||||
bind.symbol = ReadNodeProperty((*itB), DAE_SYMBOL_ATTRIBUTE);
|
||||
bind.reference = ReadNodeProperty(paramNode, DAE_REF_ATTRIBUTE);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Write out the pass shader to the COLLADA xml node tree
|
||||
xmlNode* FCDEffectPassShader::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* shaderNode = AddChild(parentNode, DAE_SHADER_ELEMENT);
|
||||
|
||||
// Write out the compiler information and the shader's name/stage
|
||||
if (!compilerTarget.empty()) AddChild(shaderNode, DAE_FXCMN_COMPILERTARGET_ELEMENT, compilerTarget);
|
||||
if (!compilerOptions.empty()) AddChild(shaderNode, DAE_FXCMN_COMPILEROPTIONS_ELEMENT, compilerOptions);
|
||||
AddAttribute(shaderNode, DAE_STAGE_ATTRIBUTE, isFragment ? DAE_FXCMN_FRAGMENT_SHADER : DAE_FXCMN_VERTEX_SHADER);
|
||||
if (!name.empty())
|
||||
{
|
||||
xmlNode* nameNode = AddChild(shaderNode, DAE_FXCMN_NAME_ELEMENT, name);
|
||||
if (code != NULL) AddAttribute(nameNode, DAE_SOURCE_ATTRIBUTE, code->GetSid());
|
||||
}
|
||||
|
||||
// Write out the bindings
|
||||
for (FCDEffectPassBindList::const_iterator itB = bindings.begin(); itB != bindings.end(); ++itB)
|
||||
{
|
||||
const FCDEffectPassBind& b = (*itB);
|
||||
if (!b.reference.empty() && !b.symbol.empty())
|
||||
{
|
||||
xmlNode* bindNode = AddChild(shaderNode, DAE_BIND_ELEMENT);
|
||||
AddAttribute(bindNode, DAE_SYMBOL_ATTRIBUTE, b.symbol);
|
||||
xmlNode* paramNode = AddChild(bindNode, DAE_PARAMETER_ELEMENT);
|
||||
AddAttribute(paramNode, DAE_REF_ATTRIBUTE, b.reference);
|
||||
}
|
||||
}
|
||||
return shaderNode;
|
||||
}
|
||||
169
Extras/FCollada/FCDocument/FCDEffectPassShader.h
Normal file
169
Extras/FCollada/FCDocument/FCDEffectPassShader.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDEffectPassShader.h
|
||||
This file contains the FCDEffectPassShader and the FCDEffectPassBind classes.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_EFFECT_PASS_SHADER_H_
|
||||
#define _FCD_EFFECT_PASS_SHADER_H_
|
||||
|
||||
#include "FCDocument/FCDObject.h"
|
||||
|
||||
class FCDocument;
|
||||
class FCDEffectCode;
|
||||
|
||||
/**
|
||||
A COLLADA shader binding.
|
||||
|
||||
Binds an external symbol to a COLLADA effect parameter, by reference.
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectPassBind
|
||||
{
|
||||
public:
|
||||
string reference; /**< A COLLADA effect parameter reference. */
|
||||
string symbol; /**< An external symbol, used within the shader code. */
|
||||
};
|
||||
|
||||
typedef vector<FCDEffectPassBind> FCDEffectPassBindList; /**< A dynamically-sized array of shader bindings. */
|
||||
|
||||
/**
|
||||
A COLLADA shader.
|
||||
|
||||
The shader abstraction level in ColladaFX is contained within the effect passes.
|
||||
There are two types of shaders: vertex shaders and fragment/pixel shaders.
|
||||
A COLLADA shader contains a list of bindings to attach the effect parameters to the
|
||||
shader input parameters.
|
||||
|
||||
The shader object also contains the compiler information necessary to build
|
||||
the shader: its code, the compiler target and the compiler options.
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectPassShader : public FCDObject
|
||||
{
|
||||
private:
|
||||
FCDEffectPass* parent;
|
||||
|
||||
FCDEffectPassBindList bindings;
|
||||
fstring compilerTarget;
|
||||
fstring compilerOptions;
|
||||
string name;
|
||||
bool isFragment;
|
||||
FCDEffectCode* code;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly. Instead, use the FCDEffectPass::AddShader,
|
||||
FCDEffectPass::AddVertexShader or FCDEffectPass::AddFragmentShader functions.
|
||||
@param document The COLLADA document that owns this shader.
|
||||
@param parent The effect pass that contains this shader. */
|
||||
FCDEffectPassShader(FCDocument* document, FCDEffectPass* parent);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectPass::ReleaseShader function. */
|
||||
virtual ~FCDEffectPassShader();
|
||||
|
||||
/** Retrieves the effect pass that contains this shader.
|
||||
@return The effect pass. */
|
||||
inline FCDEffectPass* GetParent() { return parent; }
|
||||
inline const FCDEffectPass* GetParent() const { return parent; } /**< See above. */
|
||||
|
||||
/** Sets this shader as affecting vertices.
|
||||
This sets the stage of the shader to the vertex pipeline. */
|
||||
inline void AffectsVertices() { isFragment = false; }
|
||||
|
||||
/** Sets this shader as affecting fragments/pixels.
|
||||
This sets the stage of the shader to the fragment/pixel pipeline. */
|
||||
inline void AffectsFragments() { isFragment = true; }
|
||||
|
||||
/** Retrieves whether this shader affects fragments/pixels.
|
||||
@return Whether this shader affects fragments/pixels. */
|
||||
inline bool IsFragmentShader() const { return isFragment; }
|
||||
|
||||
/** Retrieves whether this shader affects vertices.
|
||||
@return Whether this shader affects vertices. */
|
||||
inline bool IsVertexShader() const { return !isFragment; }
|
||||
|
||||
/** Retrieves the list of bindings for this shader.
|
||||
@return The list of bindings. */
|
||||
inline FCDEffectPassBindList& GetBindings() { return bindings; }
|
||||
inline const FCDEffectPassBindList& GetBindings() const { return bindings; } /**< See above. */
|
||||
|
||||
/** Retrieves the number of bindings for this shader.
|
||||
@return The number of bindings. */
|
||||
inline size_t GetBindingCount() const { return bindings.size(); }
|
||||
|
||||
/** Retrieves a binding contained in this shader.
|
||||
@param index The index of the binding.
|
||||
@return The binding. This pointer will be NULL if the index is out-of-bounds. */
|
||||
inline FCDEffectPassBind* GetBinding(size_t index) { FUAssert(index < GetBindingCount(), return NULL); return &bindings.at(index); }
|
||||
inline const FCDEffectPassBind* GetBinding(size_t index) const { FUAssert(index < GetBindingCount(), return NULL); return &bindings.at(index); } /**< See above. */
|
||||
|
||||
/** Adds a new binding to this shader.
|
||||
@return The new binding. */
|
||||
FCDEffectPassBind* AddBinding();
|
||||
|
||||
/** Releases a binding contained within this shader.
|
||||
@param binding The binding to release. */
|
||||
void ReleaseBinding(FCDEffectPassBind* binding);
|
||||
|
||||
/** Retrieves the compiler target information.
|
||||
The validity of this string depends on the type of the profile that contains this shader.
|
||||
@return The compiler target information string. */
|
||||
inline const fstring& GetCompilerTarget() const { return compilerTarget; }
|
||||
|
||||
/** Sets the compiler target information string.
|
||||
The validity of this string depends on the type of the profile that contains this shader.
|
||||
@param _compilerTarget The compiler target information. */
|
||||
inline void SetCompilerTarget(const fstring& _compilerTarget) { compilerTarget = _compilerTarget; }
|
||||
|
||||
/** Retrieves the compiler option string.
|
||||
The validity of this string depends on the type of the profile that contains this shader.
|
||||
@return The compiler option string. */
|
||||
inline const fstring& GetCompilerOptions() const { return compilerOptions; }
|
||||
|
||||
/** Sets the compiler option string.
|
||||
The validity of this string depends on the type of the profile that contains this shader.
|
||||
@param _compilerOptions The compiler option string. */
|
||||
inline void SetCompilerOptions(const fstring& _compilerOptions) { compilerOptions = _compilerOptions; }
|
||||
|
||||
/** Retrieves the sub-id of the shader.
|
||||
@return The sub-id. */
|
||||
inline const string& GetName() const { return name; }
|
||||
|
||||
/** Sets the sub-id of the shader.
|
||||
@param _name The sub-id. */
|
||||
inline void SetName(const string& _name) { name = _name; }
|
||||
|
||||
/** Retrieves the code inclusion that contains the code for this shader.
|
||||
@return The code inclusion. This pointer will be NULL if this shader
|
||||
is not yet attached to any code. */
|
||||
inline FCDEffectCode* GetCode() { return code; }
|
||||
inline const FCDEffectCode* GetCode() const { return code; } /**< See above. */
|
||||
|
||||
/** Sets the code inclusion that contains the code for this shader.
|
||||
@param _code The code inclusion. This pointer will be NULL to detach
|
||||
a shader from its code. */
|
||||
inline void SetCode(FCDEffectCode* _code) { code = _code; }
|
||||
|
||||
/** [INTERNAL] Clones this shader. You must manually delete the clone.
|
||||
@param newParent The effect pass that will contain the clone.
|
||||
@return The cloned shader. */
|
||||
FCDEffectPassShader* Clone(FCDEffectPass* newParent) const;
|
||||
|
||||
/** [INTERNAL] Reads in the pass shader from a given COLLADA XML tree node.
|
||||
@param shaderNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the shader.*/
|
||||
FUStatus LoadFromXML(xmlNode* shaderNode);
|
||||
|
||||
/** [INTERNAL] Writes out the pass shader to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the effect profile.
|
||||
@return The created element XML tree node. */
|
||||
xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
#endif // _FCD_EFFECT_PASS_SHADER_H_
|
||||
24
Extras/FCollada/FCDocument/FCDEffectProfile.cpp
Normal file
24
Extras/FCollada/FCDocument/FCDEffectProfile.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDEffect.h"
|
||||
#include "FCDocument/FCDEffectProfile.h"
|
||||
|
||||
FCDEffectProfile::FCDEffectProfile(FCDocument* document, FCDEffect* _parent) : FCDObject(document, "FCDEffectProfile")
|
||||
{
|
||||
parent = _parent;
|
||||
}
|
||||
|
||||
FCDEffectProfile::~FCDEffectProfile()
|
||||
{
|
||||
parent = NULL;
|
||||
}
|
||||
|
||||
const string& FCDEffectProfile::GetDaeId() const
|
||||
{
|
||||
return parent->GetDaeId();
|
||||
}
|
||||
111
Extras/FCollada/FCDocument/FCDEffectProfile.h
Normal file
111
Extras/FCollada/FCDocument/FCDEffectProfile.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDEffectProfile.h
|
||||
This file contains the FCDEffectProfile abstract class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_EFFECT_PROFILE_H_
|
||||
#define _FCD_EFFECT_PROFILE_H_
|
||||
|
||||
#include "FUtils/FUDaeEnum.h"
|
||||
#include "FCDocument/FCDObject.h"
|
||||
|
||||
class FCDocument;
|
||||
class FCDEffect;
|
||||
|
||||
/**
|
||||
The base for a COLLADA effect profile.
|
||||
|
||||
COLLADA has multiple effect profiles: CG, HLSL, GLSL, GLES and the COMMON profile.
|
||||
For each profile, there is a class which implements this abstract class.
|
||||
This abstract class solely holds the parent effect and allows access to the
|
||||
profile type.
|
||||
|
||||
@see FCDEffectProfileFX FCDEffectStandard
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectProfile : public FCDObject
|
||||
{
|
||||
private:
|
||||
FCDEffect* parent;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffect::AddProfile function.
|
||||
@param document The COLLADA document that owns this effect profile.
|
||||
@param parent The effect which contains this profile. */
|
||||
FCDEffectProfile(FCDocument* document, FCDEffect* parent);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffect::ReleaseProfile function. */
|
||||
virtual ~FCDEffectProfile();
|
||||
|
||||
/** Retrieves the profile type for this effect.
|
||||
This function allows you to up-cast the pointer safely to a more specific
|
||||
effect profile class.
|
||||
@return The profile type. */
|
||||
virtual FUDaeProfileType::Type GetType() const = 0;
|
||||
|
||||
/** Retrieves the parent effect.
|
||||
This is the effect which contains this profile.
|
||||
@return The parent effect. This pointer will never be NULL. */
|
||||
FCDEffect* GetParent() { return parent; }
|
||||
const FCDEffect* GetParent() const { return parent; } /**< See above. */
|
||||
|
||||
/** [INTERNAL] Retrieves the COLLADA id of the parent effect.
|
||||
This function is useful when reporting errors and warnings.
|
||||
@return The COLLADA id of the parent effect. */
|
||||
const string& GetDaeId() const;
|
||||
|
||||
/** Retrieves an effect parameter. Looks for the effect parameter with the correct
|
||||
semantic, in order to bind or override its value.
|
||||
This function searches through the effect profile and the level of abstractions below.
|
||||
@param semantic The effect parameter semantic to match.
|
||||
@return The effect parameter that matches the semantic. This pointer will be NULL
|
||||
if no effect parameter matches the given semantic. */
|
||||
virtual FCDEffectParameter* FindParameterBySemantic(const string& semantic) = 0;
|
||||
|
||||
/** Retrieves a subset of the effect parameter list.
|
||||
Look for effect parameters with the correct semantic.
|
||||
This function searches through the effect profile and the level of abstractions below.
|
||||
@param semantic The effect parameter semantic to match.
|
||||
@param parameters The list of parameters to fill in. This list is not cleared. */
|
||||
virtual void FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters) = 0;
|
||||
|
||||
/** Retrieves a subset of the effect parameter list.
|
||||
Look for effect parameters with the correct reference.
|
||||
This function searches through the effect profile and the level of abstractions below.
|
||||
@param reference The effect parameter reference to match. In the case of effect
|
||||
parameter generators, the reference is replaced by the sub-id.
|
||||
@param parameters The list of parameters to fill in. This list is not cleared. */
|
||||
virtual void FindParametersByReference(const string& reference, FCDEffectParameterList& parameters) = 0;
|
||||
|
||||
/** [INTERNAL] Clones the profile effect and its parameters.
|
||||
@param newParent The effect that will contain the cloned profile.
|
||||
@return The cloned profile. This pointer will never be NULL. */
|
||||
virtual FCDEffectProfile* Clone(FCDEffect* newParent) = 0;
|
||||
|
||||
/** [INTERNAL] Flattens this effect profile, pushing all the effect parameter overrides
|
||||
into the effect parameter generators and moving all the parameters to the
|
||||
effect technique level of abstraction. To flatten the material, use the
|
||||
FCDMaterialInstance::FlattenMaterial function. */
|
||||
virtual void Flatten() = 0;
|
||||
|
||||
/** [INTERNAL] Reads in the effect profile from a given COLLADA XML tree node.
|
||||
@param profileNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the effect profile.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* profileNode) = 0;
|
||||
|
||||
/** [INTERNAL] Writes out the effect profile to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the effect profile.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const = 0;
|
||||
};
|
||||
|
||||
#endif // _FCD_EFFECT_PROFILE_H_
|
||||
282
Extras/FCollada/FCDocument/FCDEffectProfileFX.cpp
Normal file
282
Extras/FCollada/FCDocument/FCDEffectProfileFX.cpp
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDEffect.h"
|
||||
#include "FCDocument/FCDEffectCode.h"
|
||||
#include "FCDocument/FCDEffectProfileFX.h"
|
||||
#include "FCDocument/FCDEffectParameter.h"
|
||||
#include "FCDocument/FCDEffectParameterList.h"
|
||||
#include "FCDocument/FCDEffectParameterFactory.h"
|
||||
#include "FCDocument/FCDEffectTechnique.h"
|
||||
#include "FCDocument/FCDLibrary.h"
|
||||
#include "FCDocument/FCDImage.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDEffectProfileFX::FCDEffectProfileFX(FCDocument* document, FCDEffect* _parent, FUDaeProfileType::Type _type) : FCDEffectProfile(document, _parent)
|
||||
{
|
||||
type = _type;
|
||||
parameters = new FCDEffectParameterList(GetDocument(), true);
|
||||
}
|
||||
|
||||
FCDEffectProfileFX::~FCDEffectProfileFX()
|
||||
{
|
||||
CLEAR_POINTER_VECTOR(techniques);
|
||||
CLEAR_POINTER_VECTOR(codes);
|
||||
SAFE_DELETE(parameters);
|
||||
}
|
||||
|
||||
FCDEffectTechnique* FCDEffectProfileFX::AddTechnique()
|
||||
{
|
||||
FCDEffectTechnique* technique = new FCDEffectTechnique(GetDocument(), this);
|
||||
techniques.push_back(technique);
|
||||
return technique;
|
||||
}
|
||||
|
||||
void FCDEffectProfileFX::ReleaseTechnique(FCDEffectTechnique* technique)
|
||||
{
|
||||
FCDEffectTechniqueList::iterator it = std::find(techniques.begin(), techniques.end(), technique);
|
||||
if (it != techniques.end())
|
||||
{
|
||||
delete *it;
|
||||
techniques.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void FCDEffectProfileFX::AddParameter(FCDEffectParameter* parameter)
|
||||
{
|
||||
parameters->push_back(parameter);
|
||||
}
|
||||
|
||||
// Look for the parameter with the given reference.
|
||||
const FCDEffectParameter* FCDEffectProfileFX::FindParameter(const char* ref) const
|
||||
{
|
||||
const FCDEffectParameter* parameter = parameters->FindReference(ref);
|
||||
for (FCDEffectTechniqueList::const_iterator it = techniques.begin(); it != techniques.end() && parameter == NULL; ++it)
|
||||
{
|
||||
parameter = (*it)->FindParameter(ref);
|
||||
}
|
||||
return parameter;
|
||||
}
|
||||
|
||||
// Look for the effect parameter with the correct semantic, in order to bind/set its value
|
||||
FCDEffectParameter* FCDEffectProfileFX::FindParameterBySemantic(const string& semantic)
|
||||
{
|
||||
FCDEffectParameter* parameter = parameters->FindSemantic(semantic);
|
||||
for (FCDEffectTechniqueList::iterator it = techniques.begin(); it != techniques.end() && parameter == NULL; ++it)
|
||||
{
|
||||
parameter = (*it)->FindParameterBySemantic(semantic);
|
||||
}
|
||||
return parameter;
|
||||
}
|
||||
|
||||
void FCDEffectProfileFX::FindParametersBySemantic(const string& semantic, FCDEffectParameterList& _parameters)
|
||||
{
|
||||
// Look in the local parameters
|
||||
parameters->FindSemantic(semantic, _parameters);
|
||||
|
||||
// Look in the techniques
|
||||
for( FCDEffectTechniqueList::iterator it = techniques.begin(); it != techniques.end(); ++it)
|
||||
{
|
||||
(*it)->FindParametersBySemantic(semantic, _parameters);
|
||||
}
|
||||
}
|
||||
|
||||
void FCDEffectProfileFX::FindParametersByReference(const string& reference, FCDEffectParameterList& _parameters)
|
||||
{
|
||||
// Look in the local parameters
|
||||
parameters->FindReference(reference, _parameters);
|
||||
|
||||
// Look in the techniques
|
||||
for( FCDEffectTechniqueList::iterator it = techniques.begin(); it != techniques.end(); ++it)
|
||||
{
|
||||
(*it)->FindParametersBySemantic(reference, _parameters);
|
||||
}
|
||||
}
|
||||
|
||||
FCDEffectCode* FCDEffectProfileFX::FindCode(const string& sid)
|
||||
{
|
||||
for (FCDEffectCodeList::iterator itC = codes.begin(); itC != codes.end(); ++itC)
|
||||
{
|
||||
if ((*itC)->GetSid() == sid) return (*itC);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
const FCDEffectCode* FCDEffectProfileFX::FindCode(const string& sid) const
|
||||
{
|
||||
for (FCDEffectCodeList::const_iterator itC = codes.begin(); itC != codes.end(); ++itC)
|
||||
{
|
||||
if ((*itC)->GetSid() == sid) return (*itC);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Adds a new code inclusion to this effect profile.
|
||||
FCDEffectCode* FCDEffectProfileFX::AddCode()
|
||||
{
|
||||
FCDEffectCode* code = new FCDEffectCode(GetDocument());
|
||||
codes.push_back(code);
|
||||
return code;
|
||||
}
|
||||
|
||||
// Releases a code inclusion contained within this effect profile.
|
||||
void FCDEffectProfileFX::ReleaseCode(FCDEffectCode* code)
|
||||
{
|
||||
FCDEffectCodeList::iterator itC = std::find(codes.begin(), codes.end(), code);
|
||||
if (itC != codes.end())
|
||||
{
|
||||
delete *itC;
|
||||
codes.erase(itC);
|
||||
}
|
||||
}
|
||||
|
||||
// Clone the profile effect and its parameters
|
||||
FCDEffectProfile* FCDEffectProfileFX::Clone(FCDEffect* newParent)
|
||||
{
|
||||
// Hack, because I'm time-bound right now.
|
||||
FCDEffectProfileFX* clone = new FCDEffectProfileFX(GetDocument(), newParent, type);
|
||||
SAFE_DELETE(clone->parameters);
|
||||
clone->parameters = parameters->Clone();
|
||||
clone->includeFilename = includeFilename;
|
||||
|
||||
// Clone the codes: needs to happen before the techniques are cloned.
|
||||
clone->codes.reserve(codes.size());
|
||||
for (FCDEffectCodeList::const_iterator itC = codes.begin(); itC != codes.end(); ++itC)
|
||||
{
|
||||
clone->codes.push_back((*itC)->Clone());
|
||||
}
|
||||
|
||||
// Clone the techniques
|
||||
clone->techniques.reserve(techniques.size());
|
||||
for (FCDEffectTechniqueList::iterator itPs = techniques.begin(); itPs != techniques.end(); ++itPs)
|
||||
{
|
||||
clone->techniques.push_back((*itPs)->Clone(clone));
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Flatten this effect profile: trickling down all the parameters to the techniques
|
||||
void FCDEffectProfileFX::Flatten()
|
||||
{
|
||||
for (FCDEffectParameterList::iterator itP = parameters->begin(); itP != parameters->end(); ++itP)
|
||||
{
|
||||
FCDEffectParameterList generators;
|
||||
if ((*itP)->IsModifier())
|
||||
{
|
||||
// Overwrite the generators
|
||||
FindParametersByReference((*itP)->GetReference(), generators);
|
||||
for (FCDEffectParameterList::iterator itQ = generators.begin(); itQ != generators.end(); ++itQ)
|
||||
{
|
||||
if ((*itP) != (*itQ))
|
||||
{
|
||||
(*itP)->Overwrite(*itQ);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add this parameter to the techniques
|
||||
for (FCDEffectTechniqueList::iterator itT = techniques.begin(); itT != techniques.end(); ++itT)
|
||||
{
|
||||
(*itT)->AddParameter((*itP)->Clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
CLEAR_POINTER_VECTOR(*parameters);
|
||||
|
||||
// Flatten the techniques
|
||||
for (FCDEffectTechniqueList::iterator itT = techniques.begin(); itT != techniques.end(); ++itT)
|
||||
{
|
||||
(*itT)->Flatten();
|
||||
}
|
||||
}
|
||||
|
||||
// Read a <profile_X> node for a given COLLADA effect
|
||||
// Note that this function should do most of the work, except for profile-specific states
|
||||
FUStatus FCDEffectProfileFX::LoadFromXML(xmlNode* profileNode)
|
||||
{
|
||||
FUStatus status;
|
||||
|
||||
// Verify that we are given a valid XML input node.
|
||||
const char* profileName = FUDaeProfileType::ToString(type);
|
||||
if (!IsEquivalent(profileNode->name, profileName))
|
||||
{
|
||||
return status.Warning(FS("Invalid profile input node for effect") + TO_FSTRING(GetDaeId()), profileNode->line);
|
||||
}
|
||||
|
||||
// Read in the target platform for this effect profile
|
||||
platform = TO_FSTRING(ReadNodeProperty(profileNode, DAE_PLATFORM_ATTRIBUTE));
|
||||
|
||||
// Parse in the child elements: parameters and techniques
|
||||
SAFE_DELETE(parameters);
|
||||
parameters = new FCDEffectParameterList(GetDocument(), true);
|
||||
|
||||
for (xmlNode* child = profileNode->children; child != NULL; child = child->next)
|
||||
{
|
||||
if (child->type != XML_ELEMENT_NODE) continue;
|
||||
|
||||
if (IsEquivalent(child->name, DAE_TECHNIQUE_ELEMENT))
|
||||
{
|
||||
FCDEffectTechnique* technique = AddTechnique();
|
||||
status.AppendStatus(technique->LoadFromXML(child, profileNode));
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_NEWPARAM_ELEMENT))
|
||||
{
|
||||
AddParameter(FCDEffectParameterFactory::LoadFromXML(GetDocument(), child, &status));
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_CODE_ELEMENT) || IsEquivalent(child->name, DAE_FXCMN_INCLUDE_ELEMENT))
|
||||
{
|
||||
FCDEffectCode* code = AddCode();
|
||||
status.AppendStatus(code->LoadFromXML(child));
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_IMAGE_ELEMENT))
|
||||
{
|
||||
// You can create images within the ColladaFX profile: tell the image library about it.
|
||||
FCDImage* image = GetDocument()->GetImageLibrary()->AddEntity();
|
||||
status.AppendStatus(image->LoadFromXML(child));
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectProfileFX::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* profileNode = AddChild(parentNode, FUDaeProfileType::ToString(type));
|
||||
|
||||
// Write out the profile properties/base elements
|
||||
if (!platform.empty()) AddAttribute(profileNode, DAE_PLATFORM_ATTRIBUTE, platform);
|
||||
if (!includeFilename.empty()) AddChild(profileNode, DAE_FXCMN_INCLUDE_ELEMENT, includeFilename);
|
||||
|
||||
// Write out the code/includes
|
||||
for (FCDEffectCodeList::const_iterator itC = codes.begin(); itC != codes.end(); ++itC)
|
||||
{
|
||||
(*itC)->WriteToXML(profileNode);
|
||||
}
|
||||
|
||||
// Write out the parameters
|
||||
for (FCDEffectParameterList::const_iterator itP = parameters->begin(); itP != parameters->end(); ++itP)
|
||||
{
|
||||
(*itP)->WriteToXML(profileNode);
|
||||
}
|
||||
|
||||
// Write out the techniques
|
||||
for (FCDEffectTechniqueList::const_iterator itT = techniques.begin(); itT != techniques.end(); ++itT)
|
||||
{
|
||||
(*itT)->WriteToXML(profileNode);
|
||||
}
|
||||
|
||||
return profileNode;
|
||||
}
|
||||
219
Extras/FCollada/FCDocument/FCDEffectProfileFX.h
Normal file
219
Extras/FCollada/FCDocument/FCDEffectProfileFX.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDEffectProfileFX.h
|
||||
This file declares the FCDEffectProfileFX class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_EFFECT_PROFILE_FX_H_
|
||||
#define _FCD_EFFECT_PROFILE_FX_H_
|
||||
|
||||
#include "FUtils/FUDaeEnum.h"
|
||||
#include "FCDocument/FCDEffectProfile.h"
|
||||
|
||||
class FCDocument;
|
||||
class FCDEffect;
|
||||
class FCDEffectCode;
|
||||
class FCDEffectParameter;
|
||||
class FCDEffectParameterSurface;
|
||||
class FCDEffectTechnique;
|
||||
class FCDEffectParameterList;
|
||||
|
||||
typedef vector<FCDEffectTechnique*> FCDEffectTechniqueList; /**< A dynamically-sized array of effect techniques. */
|
||||
typedef vector<FCDEffectCode*> FCDEffectCodeList; /**< A dynamically-sized array of effect code inclusion. */
|
||||
|
||||
/**
|
||||
A general effect profile description.
|
||||
|
||||
The general effect profile contains all the information necessary
|
||||
to implement the advanced effect profiles, such as CG, HLSL, GLSL and GLES.
|
||||
Since these effect profiles contains extremely similar information, they
|
||||
use the same description structure. For the COMMON profile,
|
||||
see the FCDEffectStandard class.
|
||||
|
||||
You should use the GetType function to figure out which profile this structure
|
||||
addresses. You can then retrieve one or many of the FCDEffectTechnique objects
|
||||
that describe how to render for this profile. You may want to check the
|
||||
FCDEffectMaterialTechniqueHint objects at the FCDMaterial level, in order to
|
||||
determine which technique(s) to use for your platform. At the profile
|
||||
level of abstraction, parameters may be generated within the FCDEffectParamterList.
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectProfileFX : public FCDEffectProfile
|
||||
{
|
||||
private:
|
||||
FUDaeProfileType::Type type;
|
||||
string includeFilename;
|
||||
fstring platform;
|
||||
|
||||
FCDEffectCodeList codes;
|
||||
FCDEffectTechniqueList techniques;
|
||||
FCDEffectParameterList* parameters;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly. Instead, use the FCDEffect::AddProfile function.
|
||||
@param document The COLLADA document which owns the effect profile.
|
||||
@param parent The effect which contains this profile.
|
||||
@param type The type of profile. */
|
||||
FCDEffectProfileFX(FCDocument* document, FCDEffect* parent, FUDaeProfileType::Type type);
|
||||
|
||||
/** Destructor: do not use directly. Instead, use the FCDEffect:RemoveProfile function. */
|
||||
virtual ~FCDEffectProfileFX();
|
||||
|
||||
/** Retrieves the profile type for this effect.
|
||||
This function is a part of the FCDEffectProfile interface and allows you
|
||||
to up-cast an effect profile pointer safely to this class.
|
||||
@return The profile type. This should never be the value: 'COMMON',
|
||||
but all other profiles currently derive from this class. */
|
||||
virtual FUDaeProfileType::Type GetType() const { return type; }
|
||||
|
||||
/** @deprecated Retrieves the filename of the file that contains the code for this effect profile.
|
||||
Instead, look through the FCDEffectCode object, using the GetCodeList function and retrieve
|
||||
the correct object and its filename string.
|
||||
@return The filename of the file to import. */
|
||||
const string& GetIncludeFilename() const { return includeFilename; }
|
||||
|
||||
/** Retrieves the name of the platform in which to use the effect profile.
|
||||
This parameter is very optional.
|
||||
@return The platform name. */
|
||||
const fstring& GetPlatform() const { return platform; }
|
||||
|
||||
/** Sets the name of the platform in which to use the effect profile.
|
||||
This parameter is very optional.
|
||||
@param _platform The platform name. */
|
||||
void SetPlatform(fstring& _platform) { platform = _platform; }
|
||||
|
||||
/** Retrieves the list of techniques contained within this effect profile.
|
||||
You may want to check the FCDEffectMaterialTechniqueHint objects at the FCDMaterial level,
|
||||
in order to determine which technique(s) to use for your platform.
|
||||
@return The list of inner techniques. */
|
||||
FCDEffectTechniqueList& GetTechniqueList() { return techniques; }
|
||||
const FCDEffectTechniqueList& GetTechniqueList() const { return techniques; } /**< See above. */
|
||||
|
||||
/** Retrieves the number of techniques contained within this effect profile.
|
||||
@return The number of inner techniques. */
|
||||
size_t GetTechniqueCount() const { return techniques.size(); }
|
||||
|
||||
/** Retrieves a technique contained within this effect profile.
|
||||
You may want to check the FCDEffectMaterialTechniqueHint objects at the FCDMaterial level,
|
||||
in order to determine which technique(s) to use for your platform.
|
||||
@param index The index of the technique.
|
||||
@return The inner technique. This pointer will be NULL if the index is out-of-bounds. */
|
||||
FCDEffectTechnique* GetTechnique(size_t index) { FUAssert(index < GetTechniqueCount(), return NULL); return techniques.at(index); }
|
||||
const FCDEffectTechnique* GetTechnique(size_t index) const { FUAssert(index < GetTechniqueCount(), return NULL); return techniques.at(index); } /**< See above. */
|
||||
|
||||
/** Adds a new technique to this effect profile.
|
||||
@return The new technique object. */
|
||||
FCDEffectTechnique* AddTechnique();
|
||||
|
||||
/** Releases a technique contained within this effect profile.
|
||||
@param technique The technique to release. */
|
||||
void ReleaseTechnique(FCDEffectTechnique* technique);
|
||||
|
||||
/** Retrieves the list of code inclusions.
|
||||
@return The list of code inclusions. */
|
||||
FCDEffectCodeList& GetCodeList() { return codes; }
|
||||
const FCDEffectCodeList& GetCodeList() const { return codes; } /**< See above. */
|
||||
|
||||
/** Retrieves the number of code inclusions contained within the effect profile.
|
||||
@return The number of code inclusions. */
|
||||
size_t GetCodeCount() const { return codes.size(); }
|
||||
|
||||
/** Retrieves a code inclusion contained within the effect profile.
|
||||
@param index The index of the code inclusion.
|
||||
@return The code inclusion. This pointer will be NULL if the index is out-of-bounds. */
|
||||
FCDEffectCode* GetCode(size_t index) { FUAssert(index < GetCodeCount(), return NULL); return codes.at(index); }
|
||||
const FCDEffectCode* GetCode(size_t index) const { FUAssert(index < GetCodeCount(), return NULL); return codes.at(index); } /**< See above. */
|
||||
|
||||
/** Retrieves the code inclusion with the given sub-id.
|
||||
@param sid A COLLADA sub-id.
|
||||
@return The code inclusion with the given sub-id. This pointer will be NULL,
|
||||
if there are no code inclusions that match the given sub-id. */
|
||||
FCDEffectCode* FindCode(const string& sid);
|
||||
const FCDEffectCode* FindCode(const string& sid) const; /**< See above. */
|
||||
|
||||
/** Adds a new code inclusion to this effect profile.
|
||||
@return The new code inclusion. */
|
||||
FCDEffectCode* AddCode();
|
||||
|
||||
/** Releases a code inclusion contained within this effect profile.
|
||||
@param code The code inclusion to release. */
|
||||
void ReleaseCode(FCDEffectCode* code);
|
||||
|
||||
/** Retrieves the list of effect parameters contained within the effect profile.
|
||||
At this level of abstraction, there should be only effect parameter generators.
|
||||
@return The list of effect parameters. */
|
||||
FCDEffectParameterList* GetParameters() { return parameters; }
|
||||
const FCDEffectParameterList* GetParameters() const { return parameters; } /**< See above. */
|
||||
|
||||
/** [INTERNAL] Inserts an existing parameter into the list of effect parameters
|
||||
at this abstraction level. This function is used during the flattening of a material.
|
||||
@param parameter The effect parameter to insert. */
|
||||
void AddParameter(FCDEffectParameter* parameter);
|
||||
|
||||
/** Retrieves an effect parameter.
|
||||
Looks for the effect parameter with the correct reference, in order to bind or override its value.
|
||||
This function searches through the effect profile and the level of abstractions below.
|
||||
@param reference The reference to match. In the case of effect parameter generators,
|
||||
the sub-id is used to match.
|
||||
@return The first effect parameter that matches the reference.
|
||||
This pointer will be NULL if no effect parameter matches the given semantic. */
|
||||
const FCDEffectParameter* FindParameter(const char* reference) const;
|
||||
|
||||
/** Retrieves an effect parameter.
|
||||
Looks for the effect parameter with the correct semantic, in order to bind or override its value.
|
||||
This function searches through the effect profile and the level of abstractions below.
|
||||
@param semantic The effect parameter semantic to match.
|
||||
@return The first effect parameter that matches the semantic.
|
||||
This pointer will be NULL if no effect parameter matches the given semantic. */
|
||||
virtual FCDEffectParameter* FindParameterBySemantic(const string& semantic);
|
||||
|
||||
/** Retrieves a subset of the effect parameter list.
|
||||
Look for the effect parameter generators with the correct semantic.
|
||||
This function searches through the effect profile and the level of abstractions below.
|
||||
@param semantic The effect parameter semantic to match.
|
||||
@param parameters The list of parameters to fill in. This list is not cleared. */
|
||||
virtual void FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters);
|
||||
|
||||
/** Retrieves a subset of the effect parameter list.
|
||||
Look for the effect parameter generators with the correct reference.
|
||||
This function searches through the effect profile and the level of abstractions below.
|
||||
@param reference The effect parameter reference to match. In the case of effect
|
||||
parameter generators, the reference is replaced by the sub-id.
|
||||
@param parameters The list of parameters to fill in. This list is not cleared. */
|
||||
virtual void FindParametersByReference(const string& reference, FCDEffectParameterList& parameters);
|
||||
|
||||
/** [INTERNAL] Clones the full effect profile.
|
||||
@param newParent The effect that will contain the cloned profile.
|
||||
@return The cloned profile. This pointer will never be NULL. */
|
||||
virtual FCDEffectProfile* Clone(FCDEffect* newParent);
|
||||
|
||||
/** [INTERNAL] Flattens this effect profile. Pushes all the effect parameter overrides
|
||||
into the effect parameter generators and moves all the parameters to the
|
||||
effect technique level of abstraction. To flatten the material, use the
|
||||
FCDMaterialInstance::FlattenMaterial function. */
|
||||
virtual void Flatten();
|
||||
|
||||
/** [INTERNAL] Reads in the effect profile from a given COLLADA XML tree node.
|
||||
@param profileNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the effect profile.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* profileNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect profile to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the material declaration.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
#endif // _FCD_EFFECT_PROFILE_H_
|
||||
572
Extras/FCollada/FCDocument/FCDEffectStandard.cpp
Normal file
572
Extras/FCollada/FCDocument/FCDEffectStandard.cpp
Normal file
@@ -0,0 +1,572 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDAnimated.h"
|
||||
#include "FCDocument/FCDEffect.h"
|
||||
#include "FCDocument/FCDEffectStandard.h"
|
||||
#include "FCDocument/FCDMaterial.h"
|
||||
#include "FCDocument/FCDTexture.h"
|
||||
#include "FUtils/FUDaeEnum.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
#include "FUtils/FUStringConversion.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDEffectStandard::FCDEffectStandard(FCDocument* document, FCDEffect* _parent) : FCDEffectProfile(document, _parent)
|
||||
{
|
||||
emissionColor = translucencyColor = diffuseColor = ambientColor = specularColor = FMVector3::Origin;
|
||||
reflectivityFactor = translucencyFactor = specularFactor = emissionFactor = 1.0f;
|
||||
reflectivityColor = translucencyColor = FMVector3(1.0f, 1.0f, 1.0f);
|
||||
shininess = 20.0f;
|
||||
type = CONSTANT;
|
||||
isWireframe = isFaceMap = isDoubleSided = isFaceted = isEmissionFactor = false;
|
||||
textureBuckets = new FCDTextureList[FUDaeTextureChannel::COUNT];
|
||||
}
|
||||
|
||||
FCDEffectStandard::~FCDEffectStandard()
|
||||
{
|
||||
for (uint32 i = 0; i < FUDaeTextureChannel::COUNT; ++i)
|
||||
{
|
||||
FCDTextureList& t = textureBuckets[i];
|
||||
CLEAR_POINTER_VECTOR(t);
|
||||
}
|
||||
SAFE_DELETE_ARRAY(textureBuckets);
|
||||
}
|
||||
|
||||
// Retrieve one of the buckets
|
||||
const FCDTextureList& FCDEffectStandard::GetTextureBucket(uint32 bucket) const
|
||||
{
|
||||
if (bucket < FUDaeTextureChannel::COUNT) return textureBuckets[bucket];
|
||||
else return textureBuckets[FUDaeTextureChannel::FILTER]; // Because I think this one will almost always be empty. ;)
|
||||
}
|
||||
|
||||
// Adds a texture to a specific channel.
|
||||
FCDTexture* FCDEffectStandard::AddTexture(uint32 bucket)
|
||||
{
|
||||
FUAssert(bucket < FUDaeTextureChannel::COUNT, return NULL);
|
||||
FCDTexture* texture = new FCDTexture(GetDocument());
|
||||
textureBuckets[bucket].push_back(texture);
|
||||
return texture;
|
||||
}
|
||||
|
||||
// Releases a texture contained within this effect profile.
|
||||
void FCDEffectStandard::ReleaseTexture(FCDTexture* texture)
|
||||
{
|
||||
for (uint32 i = 0; i < FUDaeTextureChannel::COUNT; ++i)
|
||||
{
|
||||
FCDTextureList::iterator it = std::find(textureBuckets[i].begin(), textureBuckets[i].end(), texture);
|
||||
if (it != textureBuckets[i].end())
|
||||
{
|
||||
delete *it;
|
||||
textureBuckets[i].erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the opacity for this material
|
||||
float FCDEffectStandard::GetOpacity() const
|
||||
{
|
||||
return 1.0f - (translucencyColor.x + translucencyColor.y + translucencyColor.z) / 3.0f * translucencyFactor;
|
||||
}
|
||||
|
||||
// Calculate the overall reflectivity for this material
|
||||
float FCDEffectStandard::GetReflectivity() const
|
||||
{
|
||||
return (reflectivityColor.x + reflectivityColor.y + reflectivityColor.z) / 3.0f * reflectivityFactor;
|
||||
}
|
||||
|
||||
// Look for the effect parameter with the correct semantic, in order to bind/set its value
|
||||
FCDEffectParameter* FCDEffectStandard::FindParameterBySemantic(const string& semantic)
|
||||
{
|
||||
// Check only the texture buckets, for now.
|
||||
for (uint32 i = 0; i < FUDaeTextureChannel::COUNT; ++i)
|
||||
{
|
||||
for (FCDTextureList::iterator itT = textureBuckets[i].begin(); itT != textureBuckets[i].end(); ++itT)
|
||||
{
|
||||
FCDEffectParameter* p = (*itT)->FindParameterBySemantic(semantic);
|
||||
if (p != NULL) return p;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void FCDEffectStandard::FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters)
|
||||
{
|
||||
// Check only the texture buckets, for now.
|
||||
for (uint32 i = 0; i < FUDaeTextureChannel::COUNT; ++i)
|
||||
{
|
||||
for (FCDTextureList::iterator itT = textureBuckets[i].begin(); itT != textureBuckets[i].end(); ++itT)
|
||||
{
|
||||
(*itT)->FindParametersBySemantic(semantic, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FCDEffectStandard::FindParametersByReference(const string& reference, FCDEffectParameterList& parameters)
|
||||
{
|
||||
// Check only the texture buckets, for now.
|
||||
for (uint32 i = 0; i < FUDaeTextureChannel::COUNT; ++i)
|
||||
{
|
||||
for (FCDTextureList::iterator itT = textureBuckets[i].begin(); itT != textureBuckets[i].end(); ++itT)
|
||||
{
|
||||
(*itT)->FindParametersByReference(reference, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone the standard effect
|
||||
FCDEffectProfile* FCDEffectStandard::Clone(FCDEffect* newParent)
|
||||
{
|
||||
FCDEffectStandard* clone = new FCDEffectStandard(GetDocument(), newParent);
|
||||
clone->type = type;
|
||||
for (uint32 i = 0; i < FUDaeTextureChannel::COUNT; ++i)
|
||||
{
|
||||
for (FCDTextureList::iterator itT = textureBuckets[i].begin(); itT != textureBuckets[i].end(); ++itT)
|
||||
{
|
||||
clone->textureBuckets[i].push_back((*itT)->Clone());
|
||||
}
|
||||
}
|
||||
|
||||
# define CLONE_ANIMATED_F(flt) clone->flt = flt; FCDAnimatedFloat::Clone(GetDocument(), &flt, &clone->flt);
|
||||
# define CLONE_ANIMATED_C(flt) clone->flt = flt; FCDAnimatedColor::Clone(GetDocument(), &flt, &clone->flt);
|
||||
|
||||
CLONE_ANIMATED_C(emissionColor); CLONE_ANIMATED_F(emissionFactor); clone->isEmissionFactor = isEmissionFactor;
|
||||
CLONE_ANIMATED_C(translucencyColor); CLONE_ANIMATED_F(translucencyFactor);
|
||||
CLONE_ANIMATED_C(diffuseColor); CLONE_ANIMATED_C(ambientColor);
|
||||
CLONE_ANIMATED_C(specularColor); CLONE_ANIMATED_F(specularFactor); CLONE_ANIMATED_F(shininess);
|
||||
CLONE_ANIMATED_C(reflectivityColor); CLONE_ANIMATED_F(reflectivityFactor);
|
||||
clone->isFaceted = isFaceted;
|
||||
clone->isDoubleSided = isDoubleSided;
|
||||
clone->isWireframe = isWireframe;
|
||||
clone->isFaceMap = isFaceMap;
|
||||
|
||||
# undef CLONE_ANIMATED_F
|
||||
# undef CLONE_ANIMATED_C
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Read in a <material> node from the COLLADA document
|
||||
FUStatus FCDEffectStandard::LoadFromXML(xmlNode* baseNode)
|
||||
{
|
||||
FUStatus status;
|
||||
|
||||
// <shader> support is for COLLADA 1.3 backward compatibility
|
||||
bool isCollada1_3 = IsEquivalent(baseNode->name, DAE_SHADER_ELEMENT);
|
||||
if (!isCollada1_3 && !IsEquivalent(baseNode->name, DAE_FX_PROFILE_COMMON_ELEMENT))
|
||||
{
|
||||
return status.Warning(FS("Unknown element as standard material base."), baseNode->line);
|
||||
}
|
||||
|
||||
// For COLLADA 1.3 backward compatibility: find the correct base node for the profile.
|
||||
// While we're digging, find the node with the Max-specific parameters
|
||||
xmlNode* maxParameterNode = NULL;
|
||||
xmlNode* mayaParameterNode = NULL;
|
||||
if (isCollada1_3)
|
||||
{
|
||||
// COLLADA 1.3 backward compatibility: the base node is <shader><technique><pass>
|
||||
// and the Max-specific parameters are in <shader><technique><pass><program>.
|
||||
xmlNode* commonTechniqueNode = FindTechnique(baseNode, DAE_COMMON_PROFILE);
|
||||
xmlNode* maxTechniqueNode = FindTechnique(baseNode, DAEMAX_MAX_PROFILE);
|
||||
baseNode = FindChildByType(commonTechniqueNode, DAE_PASS_ELEMENT);
|
||||
xmlNode* maxPassNode = FindChildByType(maxTechniqueNode, DAE_PASS_ELEMENT);
|
||||
maxParameterNode = FindChildByType(maxPassNode, DAE_PROGRAM_ELEMENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Bump the base node up the first <technique> element
|
||||
xmlNode* techniqueNode = FindChildByType(baseNode, DAE_TECHNIQUE_ELEMENT);
|
||||
if (techniqueNode == NULL)
|
||||
{
|
||||
return status.Warning(FS("Expecting <technique> within the <profile_COMMON> element for effect: ") + TO_FSTRING(GetDaeId()), baseNode->line);
|
||||
}
|
||||
baseNode = techniqueNode;
|
||||
|
||||
// Look for an <extra><technique> node for Max-specific parameter
|
||||
xmlNode* extraNode = FindChildByType(baseNode, DAE_EXTRA_ELEMENT);
|
||||
maxParameterNode = FindTechnique(extraNode, DAEMAX_MAX_PROFILE);
|
||||
mayaParameterNode = FindTechnique(extraNode, DAEMAYA_MAYA_PROFILE);
|
||||
}
|
||||
|
||||
if (isCollada1_3)
|
||||
{
|
||||
// COLLADA 1.3 backward compatibility: look for <input> elements pointing to textures
|
||||
xmlNodeList textureInputNodes;
|
||||
FindChildrenByType(baseNode, DAE_INPUT_ELEMENT, textureInputNodes);
|
||||
for (xmlNodeList::iterator it = textureInputNodes.begin(); it != textureInputNodes.end(); ++it)
|
||||
{
|
||||
string semantic = ReadNodeSemantic(*it);
|
||||
if (semantic != DAE_TEXTURE_INPUT)
|
||||
{
|
||||
status.Warning(FS("Unknown input semantic in material: ") + TO_FSTRING(GetDaeId()), (*it)->line);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Retrieve the texture and bucket it
|
||||
string textureId = ReadNodeSource(*it);
|
||||
FCDTexture* texture = GetDocument()->FindTexture(textureId);
|
||||
if (texture != NULL)
|
||||
{
|
||||
uint32 channel = (uint32) texture->GetTextureChannel();
|
||||
textureBuckets[(uint32) channel].push_back(texture->Clone());
|
||||
}
|
||||
else
|
||||
{
|
||||
status.Warning(FS("Unknown input texture '") + TO_FSTRING(textureId) + FS("' in material: ") + TO_FSTRING(GetDaeId()), (*it)->line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the material's program node and figure out the correct shader type
|
||||
xmlNode* commonParameterNode = NULL;
|
||||
if (isCollada1_3)
|
||||
{
|
||||
// COLLADA 1.3 backward compatibility: read in the type attribute of the <program> node
|
||||
commonParameterNode = FindChildByType(baseNode, DAE_PROGRAM_ELEMENT);
|
||||
FUUri programUrl = ReadNodeUrl(commonParameterNode);
|
||||
string materialType = FUStringConversion::ToString(programUrl.prefix);
|
||||
if (materialType == DAE_CONSTANT_MATERIAL_PROGRAM) type = CONSTANT;
|
||||
else if (materialType == DAE_LAMBERT_MATERIAL_PROGRAM) type = LAMBERT;
|
||||
else if (materialType == DAE_PHONG_MATERIAL_PROGRAM) type = PHONG;
|
||||
else
|
||||
{
|
||||
return status.Warning(FS("Unsupported shader program type: '") + programUrl.prefix + FS("' in material: ") + TO_FSTRING(GetDaeId()), commonParameterNode->line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Either <phong>, <lambert> or <constant> are expected
|
||||
for (commonParameterNode = baseNode->children; commonParameterNode != NULL; commonParameterNode = commonParameterNode->next)
|
||||
{
|
||||
if (commonParameterNode->type != XML_ELEMENT_NODE) continue;
|
||||
if (IsEquivalent(commonParameterNode->name, DAE_FXSTD_CONSTANT_ELEMENT)) { type = CONSTANT; break; }
|
||||
else if (IsEquivalent(commonParameterNode->name, DAE_FXSTD_LAMBERT_ELEMENT)) { type = LAMBERT; break; }
|
||||
else if (IsEquivalent(commonParameterNode->name, DAE_FXSTD_PHONG_ELEMENT)) { type = PHONG; break; }
|
||||
else if (IsEquivalent(commonParameterNode->name, DAE_FXSTD_BLINN_ELEMENT)) { type = BLINN; break; }
|
||||
}
|
||||
}
|
||||
if (commonParameterNode == NULL)
|
||||
{
|
||||
return status.Fail(FS("Unable to find the program node for standard effect: ") + TO_FSTRING(GetDaeId()), baseNode->line);
|
||||
}
|
||||
|
||||
bool hasTranslucency = false, hasReflectivity = false;
|
||||
FCDTextureList emptyBucket;
|
||||
|
||||
// Read in the parameters for the common program types and apply them to the shader
|
||||
StringList parameterNames;
|
||||
xmlNodeList parameterNodes;
|
||||
FindParameters(commonParameterNode, parameterNames, parameterNodes);
|
||||
FindParameters(maxParameterNode, parameterNames, parameterNodes);
|
||||
FindParameters(mayaParameterNode, parameterNames, parameterNodes);
|
||||
size_t parameterCount = parameterNodes.size();
|
||||
for (size_t i = 0; i < parameterCount; ++i)
|
||||
{
|
||||
xmlNode* parameterNode = parameterNodes[i];
|
||||
const string& parameterName = parameterNames[i];
|
||||
const char* parameterContent = ReadNodeContentDirect(parameterNode);
|
||||
if (parameterName == DAE_EMISSION_MATERIAL_PARAMETER || parameterName == DAE_EMISSION_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
status.AppendStatus(ParseColorTextureParameter(parameterNode, emissionColor, textureBuckets[FUDaeTextureChannel::EMISSION]));
|
||||
}
|
||||
else if (parameterName == DAE_DIFFUSE_MATERIAL_PARAMETER || parameterName == DAE_DIFFUSE_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
status.AppendStatus(ParseColorTextureParameter(parameterNode, diffuseColor, textureBuckets[FUDaeTextureChannel::DIFFUSE]));
|
||||
}
|
||||
else if (parameterName == DAE_AMBIENT_MATERIAL_PARAMETER || parameterName == DAE_AMBIENT_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
status.AppendStatus(ParseColorTextureParameter(parameterNode, ambientColor, textureBuckets[FUDaeTextureChannel::AMBIENT]));
|
||||
}
|
||||
else if (parameterName == DAE_TRANSPARENT_MATERIAL_PARAMETER || parameterName == DAE_TRANSPARENT_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
status.AppendStatus(ParseColorTextureParameter(parameterNode, translucencyColor, textureBuckets[FUDaeTextureChannel::TRANSPARENT]));
|
||||
hasTranslucency = true;
|
||||
}
|
||||
else if (parameterName == DAE_TRANSPARENCY_MATERIAL_PARAMETER || parameterName == DAE_TRANSPARENCY_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
status.AppendStatus(ParseFloatTextureParameter(parameterNode, translucencyFactor, textureBuckets[FUDaeTextureChannel::OPACITY]));
|
||||
hasTranslucency = true;
|
||||
}
|
||||
else if (parameterName == DAE_SPECULAR_MATERIAL_PARAMETER || parameterName == DAE_SPECULAR_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
status.AppendStatus(ParseColorTextureParameter(parameterNode, specularColor, textureBuckets[FUDaeTextureChannel::SPECULAR]));
|
||||
}
|
||||
else if (parameterName == DAE_SPECULAR_MATERIAL_PARAMETER || parameterName == DAE_SPECULAR_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
status.AppendStatus(ParseColorTextureParameter(parameterNode, specularColor, textureBuckets[FUDaeTextureChannel::SPECULAR]));
|
||||
}
|
||||
else if (parameterName == DAE_SHININESS_MATERIAL_PARAMETER || parameterName == DAE_SHININESS_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
status.AppendStatus(ParseFloatTextureParameter(parameterNode, shininess, textureBuckets[FUDaeTextureChannel::SHININESS]));
|
||||
}
|
||||
else if (parameterName == DAE_REFLECTIVE_MATERIAL_PARAMETER || parameterName == DAE_REFLECTIVE_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
status.AppendStatus(ParseColorTextureParameter(parameterNode, reflectivityColor, textureBuckets[FUDaeTextureChannel::REFLECTION]));
|
||||
hasReflectivity = true;
|
||||
}
|
||||
else if (parameterName == DAE_REFLECTIVITY_MATERIAL_PARAMETER || parameterName == DAE_REFLECTIVITY_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
status.AppendStatus(ParseFloatTextureParameter(parameterNode, reflectivityFactor, emptyBucket));
|
||||
hasReflectivity = true;
|
||||
}
|
||||
else if (parameterName == DAE_BUMP_MATERIAL_PARAMETER)
|
||||
{
|
||||
status.AppendStatus(ParseSimpleTextureParameter(parameterNode, textureBuckets[FUDaeTextureChannel::BUMP]));
|
||||
}
|
||||
else if (parameterName == DAEMAX_SPECLEVEL_MATERIAL_PARAMETER || parameterName == DAEMAX_SPECLEVEL_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
status.AppendStatus(ParseFloatTextureParameter(parameterNode, specularFactor, textureBuckets[FUDaeTextureChannel::SPECULAR_LEVEL]));
|
||||
}
|
||||
else if (parameterName == DAEMAX_EMISSIONLEVEL_MATERIAL_PARAMETER || parameterName == DAEMAX_EMISSIONLEVEL_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
status.AppendStatus(ParseFloatTextureParameter(parameterNode, emissionFactor, textureBuckets[FUDaeTextureChannel::EMISSION]));
|
||||
isEmissionFactor = true;
|
||||
}
|
||||
else if (parameterName == DAEMAX_FACETED_MATERIAL_PARAMETER || parameterName == DAEMAX_FACETED_MATERIAL_PARAMETER1_3)
|
||||
{
|
||||
isFaceted = FUStringConversion::ToBoolean(parameterContent);
|
||||
}
|
||||
else if (parameterName == DAESHD_DOUBLESIDED_PARAMETER)
|
||||
{
|
||||
isDoubleSided = FUStringConversion::ToBoolean(parameterContent);
|
||||
}
|
||||
else if (parameterName == DAEMAX_WIREFRAME_MATERIAL_PARAMETER)
|
||||
{
|
||||
isWireframe = FUStringConversion::ToBoolean(parameterContent);
|
||||
}
|
||||
else if (parameterName == DAEMAX_FACEMAP_MATERIAL_PARAMETER)
|
||||
{
|
||||
isFaceMap = FUStringConversion::ToBoolean(parameterContent);
|
||||
}
|
||||
else if (parameterName == DAEMAX_INDEXOFREFRACTION_MATERIAL_PARAMETER)
|
||||
{
|
||||
status.AppendStatus(ParseSimpleTextureParameter(parameterNode, textureBuckets[FUDaeTextureChannel::REFRACTION]));
|
||||
}
|
||||
else if (parameterName == DAEMAX_DISPLACEMENT_MATERIAL_PARAMETER)
|
||||
{
|
||||
status.AppendStatus(ParseSimpleTextureParameter(parameterNode, textureBuckets[FUDaeTextureChannel::DISPLACEMENT]));
|
||||
}
|
||||
else if (parameterName == DAEMAX_FILTERCOLOR_MATERIAL_PARAMETER)
|
||||
{
|
||||
status.AppendStatus(ParseSimpleTextureParameter(parameterNode, textureBuckets[FUDaeTextureChannel::FILTER]));
|
||||
}
|
||||
else
|
||||
{
|
||||
status.Warning(FS("Unknown parameter name for material ") + TO_FSTRING(GetDaeId()), parameterNode->line);
|
||||
}
|
||||
}
|
||||
|
||||
bool isEmptyBucketEmpty = emptyBucket.empty();
|
||||
CLEAR_POINTER_VECTOR(emptyBucket);
|
||||
if (!isEmptyBucketEmpty)
|
||||
{
|
||||
return status.Fail(FS("Unexpected texture sampler on some parameters for material ") + TO_FSTRING(GetDaeId()), baseNode->line);
|
||||
}
|
||||
|
||||
// Although the default COLLADA materials gives, wrongly, a transparent material,
|
||||
// when neither the TRANSPARENT or TRANSPARENCY parameters are set, assume an opaque material.
|
||||
// Similarly for reflectivity
|
||||
if (!hasTranslucency)
|
||||
{
|
||||
translucencyColor = FMVector3::Origin;
|
||||
translucencyFactor = 0.0f;
|
||||
}
|
||||
if (!hasReflectivity)
|
||||
{
|
||||
reflectivityColor = FMVector3::Origin;
|
||||
reflectivityFactor = 0.0f;
|
||||
}
|
||||
|
||||
// Convert some of the values that may appear in different formats
|
||||
if (!isEmissionFactor)
|
||||
{
|
||||
emissionFactor = (emissionColor.x + emissionColor.y + emissionColor.z) / 3.0f;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectStandard::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* profileCommonNode = AddChild(parentNode, DAE_FX_PROFILE_COMMON_ELEMENT);
|
||||
xmlNode* techniqueCommonNode = AddChild(profileCommonNode, DAE_TECHNIQUE_ELEMENT);
|
||||
AddNodeSid(techniqueCommonNode, "common");
|
||||
|
||||
const char* materialName;
|
||||
switch (type)
|
||||
{
|
||||
case CONSTANT: materialName = DAE_FXSTD_CONSTANT_ELEMENT; break;
|
||||
case LAMBERT: materialName = DAE_FXSTD_LAMBERT_ELEMENT; break;
|
||||
case PHONG: materialName = DAE_FXSTD_PHONG_ELEMENT; break;
|
||||
case BLINN: materialName = DAE_FXSTD_BLINN_ELEMENT; break;
|
||||
case UNKNOWN:
|
||||
default: materialName = DAEERR_UNKNOWN_ELEMENT; break;
|
||||
}
|
||||
xmlNode* materialNode = AddChild(techniqueCommonNode, materialName);
|
||||
xmlNode* techniqueNode = AddExtraTechniqueChild(techniqueCommonNode, DAEMAYA_MAYA_PROFILE);
|
||||
|
||||
// Export the color/float parameters
|
||||
FCDTextureList emptyBucket; float emptyValue = 0.0f; FMVector3 emptyColor;
|
||||
WriteColorTextureParameterToXML(materialNode, DAE_EMISSION_MATERIAL_PARAMETER, emissionColor, textureBuckets[FUDaeTextureChannel::EMISSION]);
|
||||
if (type != CONSTANT)
|
||||
{
|
||||
WriteColorTextureParameterToXML(materialNode, DAE_AMBIENT_MATERIAL_PARAMETER, emissionColor, textureBuckets[FUDaeTextureChannel::AMBIENT]);
|
||||
WriteColorTextureParameterToXML(materialNode, DAE_DIFFUSE_MATERIAL_PARAMETER, diffuseColor, textureBuckets[FUDaeTextureChannel::DIFFUSE]);
|
||||
if (type != LAMBERT)
|
||||
{
|
||||
WriteColorTextureParameterToXML(materialNode, DAE_SPECULAR_MATERIAL_PARAMETER, specularColor, textureBuckets[FUDaeTextureChannel::SPECULAR]);
|
||||
WriteFloatTextureParameterToXML(materialNode, DAE_SHININESS_MATERIAL_PARAMETER, shininess, emptyBucket);
|
||||
if (!textureBuckets[FUDaeTextureChannel::SHININESS].empty())
|
||||
{
|
||||
WriteFloatTextureParameterToXML(techniqueNode, DAE_SHININESS_MATERIAL_PARAMETER, shininess, textureBuckets[FUDaeTextureChannel::SHININESS]);
|
||||
WriteFloatTextureParameterToXML(techniqueNode, DAEMAX_SPECLEVEL_MATERIAL_PARAMETER, specularFactor, textureBuckets[FUDaeTextureChannel::SPECULAR_LEVEL]);
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteColorTextureParameterToXML(materialNode, DAE_REFLECTIVE_MATERIAL_PARAMETER, reflectivityColor, textureBuckets[FUDaeTextureChannel::REFLECTION]);
|
||||
WriteFloatTextureParameterToXML(materialNode, DAE_REFLECTIVITY_MATERIAL_PARAMETER, reflectivityFactor, emptyBucket);
|
||||
|
||||
// Translucency includes both transparent and opacity textures
|
||||
FCDTextureList translucencyBucket = textureBuckets[FUDaeTextureChannel::TRANSPARENT];
|
||||
translucencyBucket.insert(translucencyBucket.end(), textureBuckets[FUDaeTextureChannel::OPACITY].begin(), textureBuckets[FUDaeTextureChannel::OPACITY].end());
|
||||
WriteColorTextureParameterToXML(materialNode, DAE_TRANSPARENT_MATERIAL_PARAMETER, translucencyColor, translucencyBucket);
|
||||
WriteFloatTextureParameterToXML(materialNode, DAE_TRANSPARENCY_MATERIAL_PARAMETER, translucencyFactor, emptyBucket);
|
||||
WriteFloatTextureParameterToXML(materialNode, DAEMAX_INDEXOFREFRACTION_MATERIAL_PARAMETER, emptyValue, textureBuckets[FUDaeTextureChannel::REFRACTION]);
|
||||
|
||||
// Non-COLLADA parameters
|
||||
if (!textureBuckets[FUDaeTextureChannel::BUMP].empty())
|
||||
{
|
||||
WriteFloatTextureParameterToXML(techniqueNode, DAE_BUMP_MATERIAL_PARAMETER, emptyValue, textureBuckets[FUDaeTextureChannel::BUMP]);
|
||||
}
|
||||
if (!textureBuckets[FUDaeTextureChannel::DISPLACEMENT].empty())
|
||||
{
|
||||
WriteFloatTextureParameterToXML(techniqueNode, DAEMAX_DISPLACEMENT_MATERIAL_PARAMETER, emptyValue, textureBuckets[FUDaeTextureChannel::DISPLACEMENT]);
|
||||
}
|
||||
if (!textureBuckets[FUDaeTextureChannel::FILTER].empty())
|
||||
{
|
||||
WriteColorTextureParameterToXML(techniqueNode, DAEMAX_FILTERCOLOR_MATERIAL_PARAMETER, emptyColor, textureBuckets[FUDaeTextureChannel::FILTER]);
|
||||
}
|
||||
|
||||
return profileCommonNode;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectStandard::WriteColorTextureParameterToXML(xmlNode* parentNode, const char* parameterNodeName, const FMVector3& value, const FCDTextureList& textureBucket) const
|
||||
{
|
||||
xmlNode* parameterNode = AddChild(parentNode, parameterNodeName);
|
||||
if (WriteTextureParameterToXML(parameterNode, textureBucket) == NULL)
|
||||
{
|
||||
// The color value expected by the profile_COMMON <color> element has four floating-point values.
|
||||
string colorValue = FUStringConversion::ToString(value) + " 1.0";
|
||||
xmlNode* valueNode = AddChild(parameterNode, DAE_FXSTD_COLOR_ELEMENT, colorValue);
|
||||
GetDocument()->WriteAnimatedValueToXML(&value.x, valueNode, parameterNodeName);
|
||||
}
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectStandard::WriteFloatTextureParameterToXML(xmlNode* parentNode, const char* parameterNodeName, const float& value, const FCDTextureList& textureBucket) const
|
||||
{
|
||||
xmlNode* parameterNode = AddChild(parentNode, parameterNodeName);
|
||||
if (WriteTextureParameterToXML(parameterNode, textureBucket) == NULL)
|
||||
{
|
||||
xmlNode* valueNode = AddChild(parameterNode, DAE_FXSTD_FLOAT_ELEMENT, value);
|
||||
GetDocument()->WriteAnimatedValueToXML(&value, valueNode, parameterNodeName);
|
||||
}
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
xmlNode* FCDEffectStandard::WriteTextureParameterToXML(xmlNode* parentNode, const FCDTextureList& textureBucket) const
|
||||
{
|
||||
xmlNode* textureNode = NULL;
|
||||
for (FCDTextureList::const_iterator itT = textureBucket.begin(); itT != textureBucket.end(); ++itT)
|
||||
{
|
||||
xmlNode* newTextureNode = (*itT)->WriteToXML(parentNode);
|
||||
if (newTextureNode != NULL && textureNode == NULL) textureNode = newTextureNode;
|
||||
}
|
||||
return textureNode;
|
||||
}
|
||||
|
||||
// Parse in the different standard effect parameters, bucketing the textures
|
||||
FUStatus FCDEffectStandard::ParseColorTextureParameter(xmlNode* parameterNode, FMVector3& value, FCDTextureList& textureBucket)
|
||||
{
|
||||
FUStatus status;
|
||||
|
||||
// Look for <texture> elements, they pre-empt everything else
|
||||
size_t originalSize = textureBucket.size();
|
||||
ParseSimpleTextureParameter(parameterNode, textureBucket);
|
||||
if (originalSize < textureBucket.size()) { value = FMVector3(1.0f, 1.0f, 1.0f); return status; }
|
||||
|
||||
// Next, look for a <color> element
|
||||
// COLLADA 1.3 backward compatibility: also look for the color value directly inside the parameter node.
|
||||
xmlNode* colorNode = FindChildByType(parameterNode, DAE_FXSTD_COLOR_ELEMENT);
|
||||
const char* content = ReadNodeContentDirect(colorNode);
|
||||
if (content == NULL || *content == 0) content = ReadNodeContentDirect(parameterNode);
|
||||
|
||||
// Parse the color value and allow for an animation of it
|
||||
value = FUStringConversion::ToPoint(content);
|
||||
if (HasNodeProperty(colorNode, DAE_ID_ATTRIBUTE) || HasNodeProperty(colorNode, DAE_SID_ATTRIBUTE))
|
||||
FCDAnimatedColor::Create(GetDocument(), colorNode, &value);
|
||||
else
|
||||
FCDAnimatedColor::Create(GetDocument(), parameterNode, &value);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
FUStatus FCDEffectStandard::ParseFloatTextureParameter(xmlNode* parameterNode, float& value, FCDTextureList& textureBucket)
|
||||
{
|
||||
FUStatus status;
|
||||
|
||||
// Look for <texture> elements, they pre-empt everything else
|
||||
size_t originalSize = textureBucket.size();
|
||||
ParseSimpleTextureParameter(parameterNode, textureBucket);
|
||||
if (originalSize < textureBucket.size()) { value = 1.0f; return status; }
|
||||
|
||||
// Next, look for a <float> element
|
||||
// COLLADA 1.3 backward compatibility: also look for the value directly inside the parameter node.
|
||||
xmlNode* floatNode = FindChildByType(parameterNode, DAE_FXSTD_FLOAT_ELEMENT);
|
||||
const char* content = ReadNodeContentDirect(floatNode);
|
||||
if (content == NULL || *content == 0) content = ReadNodeContentDirect(parameterNode);
|
||||
|
||||
// Parse the value and register it for an animation.
|
||||
value = FUStringConversion::ToFloat(content);
|
||||
if (HasNodeProperty(floatNode, DAE_ID_ATTRIBUTE) || HasNodeProperty(floatNode, DAE_SID_ATTRIBUTE))
|
||||
FCDAnimatedFloat::Create(GetDocument(), floatNode, &value);
|
||||
else
|
||||
FCDAnimatedFloat::Create(GetDocument(), parameterNode, &value);
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
FUStatus FCDEffectStandard::ParseSimpleTextureParameter(xmlNode* parameterNode, FCDTextureList& textureBucket)
|
||||
{
|
||||
FUStatus status;
|
||||
|
||||
// Parse in all the <texture> elements as standard effect samplers
|
||||
xmlNodeList samplerNodes;
|
||||
FindChildrenByType(parameterNode, DAE_FXSTD_SAMPLER_ELEMENT, samplerNodes);
|
||||
if (!samplerNodes.empty())
|
||||
{
|
||||
for (xmlNodeList::iterator itS = samplerNodes.begin(); itS != samplerNodes.end(); ++itS)
|
||||
{
|
||||
// Parse in the texture element and bucket them
|
||||
FCDTexture* texture = new FCDTexture(GetDocument());
|
||||
status.AppendStatus(texture->LoadFromTextureXML(*itS));
|
||||
if (status) textureBucket.push_back(texture);
|
||||
else { SAFE_DELETE(texture); }
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
415
Extras/FCollada/FCDocument/FCDEffectStandard.h
Normal file
415
Extras/FCollada/FCDocument/FCDEffectStandard.h
Normal file
@@ -0,0 +1,415 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDEffectStandard.h
|
||||
This file contains the FCDEffectStandard class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_MATERIAL_STANDARD_H_
|
||||
#define _FCD_MATERIAL_STANDARD_H_
|
||||
|
||||
#include "FUtils/FUDaeEnum.h"
|
||||
#include "FCDocument/FCDEffectProfile.h"
|
||||
|
||||
class FCDocument;
|
||||
class FCDEffect;
|
||||
class FCDEffectParameter;
|
||||
class FCDTexture;
|
||||
class FCDEffectParameterList;
|
||||
|
||||
/** A dynamically-sized array of texture objects. */
|
||||
typedef vector<FCDTexture*> FCDTextureList;
|
||||
|
||||
/**
|
||||
A COMMON profile effect description.
|
||||
|
||||
The COMMON effect profile holds the information necessary
|
||||
to render your polygon sets using the well-defined lighting models.
|
||||
|
||||
COLLADA supports four lighting models: constant, Lambert, Phong and Blinn.
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectStandard : public FCDEffectProfile
|
||||
{
|
||||
public:
|
||||
/** The list of the lighting models supported by the COMMON profile of COLLADA. */
|
||||
enum LightingType
|
||||
{
|
||||
/** The constant lighting model.
|
||||
This lighting model uses the emissive color everywhere, without
|
||||
any complex lighting calculations. It also uses the translucency
|
||||
factor and the translucency color, by multiplying them together
|
||||
and applying them to your standard alpha channel according to the
|
||||
final lighting color.*/
|
||||
CONSTANT,
|
||||
|
||||
/** The Lambert lighting model.
|
||||
This lighting model improves on the constant lighting model by
|
||||
using the dot-product between the normalized light vectors and the
|
||||
polygon normals to determine how much light should affect each polygon.
|
||||
This value is multiplied to the diffuse color and (1 + the ambient color). */
|
||||
LAMBERT,
|
||||
|
||||
/** The Phong lighting model.
|
||||
This lighting model improves on the Lambert lighting model by
|
||||
calculating how much light is reflected by the polygons into the viewer's eye.
|
||||
For this calculation, the shininess, the specular color and the reflectivity is used. */
|
||||
PHONG,
|
||||
|
||||
/** The Blinn lighting model.
|
||||
This lighting model improves on the Lambert lighting model by
|
||||
calculating how much light is reflected by the polygons into the viewer's eye.
|
||||
For this calculation, the shininess, the specular color and the reflectivity is used. */
|
||||
BLINN,
|
||||
|
||||
/** Not a valid lighting model. */
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
private:
|
||||
LightingType type;
|
||||
FCDTextureList* textureBuckets;
|
||||
|
||||
// Common material parameter: Emission
|
||||
FMVector3 emissionColor;
|
||||
float emissionFactor; // Max-specific
|
||||
|
||||
// Common material parameter: Translucency
|
||||
FMVector3 translucencyColor;
|
||||
float translucencyFactor;
|
||||
|
||||
// Lambert material parameters
|
||||
FMVector3 diffuseColor;
|
||||
FMVector3 ambientColor;
|
||||
|
||||
// Phong material parameters: Specular
|
||||
FMVector3 specularColor;
|
||||
float specularFactor; // Max-specific
|
||||
float shininess;
|
||||
|
||||
// Phong material parameter: Reflectivity
|
||||
FMVector3 reflectivityColor; // Maya-specific
|
||||
float reflectivityFactor; // Maya-specific
|
||||
|
||||
// Geometry modifier
|
||||
bool isFaceted; // Max-specific
|
||||
bool isDoubleSided; // Max-specific for now
|
||||
bool isWireframe; // Max-specific
|
||||
bool isFaceMap; // Max-specific
|
||||
bool isEmissionFactor; // Max-specific
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly. Instead, use the FCDEffect::AddProfile function
|
||||
with the FUDaeProfileType::COMMON parameter.
|
||||
@param document The COLLADA document that owns this effect profile.
|
||||
@param parent The effect that contains this profile. */
|
||||
FCDEffectStandard(FCDocument* document, FCDEffect* parent);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffect::ReleaseProfile function. */
|
||||
virtual ~FCDEffectStandard();
|
||||
|
||||
/** Retrieves the lighting model to be used for this profile.
|
||||
@return The lighting model. */
|
||||
inline LightingType GetLightingType() const { return type; }
|
||||
|
||||
/** Sets the lighting model to be used for this profile.
|
||||
Note that which parameters are exported depends on the lighting model.
|
||||
@param _type The lighting model. */
|
||||
inline void SetLightingType(LightingType _type) { type = _type; }
|
||||
|
||||
/** Retrieves the profile type for this effect.
|
||||
This function is a part of the FCDEffectProfile interface and allows you
|
||||
to up-cast an effect profile pointer safely to this class.
|
||||
@return The profile type: COMMON. */
|
||||
virtual FUDaeProfileType::Type GetType() const { return FUDaeProfileType::COMMON; }
|
||||
|
||||
/** Retrieves the list of textures belonging to a specific channel.
|
||||
@param bucket A texture channel index. This index should match one
|
||||
of the values in the FUDaeTextureChannel enum.
|
||||
@return The list of textures for this channel. */
|
||||
const FCDTextureList& GetTextureBucket(uint32 bucket) const;
|
||||
|
||||
/** Retrieves the number of textures belonging to a specific channel.
|
||||
@param bucket A texture channel index. This index should match one
|
||||
of the values in the FUDaeTextureChannel enum.
|
||||
@return The number of textures in that channel. */
|
||||
size_t GetTextureCount(uint32 bucket) const { FUAssert(bucket < FUDaeTextureChannel::COUNT, return 0); return textureBuckets[bucket].size(); }
|
||||
|
||||
/** Retrieves a texture
|
||||
@param bucket A texture channel index. This index should match one
|
||||
of the values in the FUDaeTextureChannel enum.
|
||||
@param index The index of a texture within this channel.
|
||||
@return The texture. This pointer will be NULL if either the bucket or the index is out-of-bounds. */
|
||||
inline FCDTexture* GetTexture(uint32 bucket, size_t index) { FUAssert(index < GetTextureCount(bucket), return NULL); return textureBuckets[bucket].at(index); }
|
||||
inline const FCDTexture* GetTexture(uint32 bucket, size_t index) const { FUAssert(index < GetTextureCount(bucket), return NULL); return textureBuckets[bucket].at(index); } /**< See above. */
|
||||
|
||||
/** Adds a texture to a specific channel.
|
||||
@param bucket A texture channel index. This index should match one
|
||||
of the values in the FUDaeTextureChannel enum.
|
||||
@return The new texture. This pointer will be NULL if the bucket is out-of-bounds. */
|
||||
FCDTexture* AddTexture(uint32 bucket);
|
||||
|
||||
/** Releases a texture contained within this effect profile.
|
||||
@param texture The texture to release. */
|
||||
void ReleaseTexture(FCDTexture* texture);
|
||||
|
||||
/** Retrieves the base translucency color.
|
||||
This value must be multiplied with the translucency factor
|
||||
to get the real translucency color.
|
||||
This value is used in all lighting models.
|
||||
@return The base translucency color. */
|
||||
inline const FMVector3& GetTranslucencyColor() const { return translucencyColor; }
|
||||
|
||||
/** Sets the base translucency color.
|
||||
@param color The base translucency color. */
|
||||
inline void SetTranslucencyColor(const FMVector3& color) { translucencyColor = color; }
|
||||
|
||||
/** Retrieves the translucency factor.
|
||||
This value must be multiplied with the translucency color
|
||||
to get the real translucency color.
|
||||
This value is used in all lighting models.
|
||||
@return The translucency factor. */
|
||||
inline const float& GetTranslucencyFactor() const { return translucencyFactor; }
|
||||
|
||||
/** Sets the translucency factor.
|
||||
@param factor The translucency factor. */
|
||||
inline void SetTranslucencyFactor(float factor) { translucencyFactor = factor; }
|
||||
|
||||
/** Retrieves the flat opacity.
|
||||
This is a calculated value and will not take into consideration any animations
|
||||
that affect either the base translucency color or the translucency factor.
|
||||
This value can be used in all lighting models.
|
||||
@return The flat opacity. */
|
||||
float GetOpacity() const;
|
||||
|
||||
/** Retrieves the base emission/self-illumination color.
|
||||
This value must be multiplied with the emission factor to get the real emission color.
|
||||
This value is used in all lighting models.
|
||||
@return The base emission color. */
|
||||
inline const FMVector3& GetEmissionColor() const { return emissionColor; }
|
||||
|
||||
/** Sets the base emission/self-illumination color.
|
||||
@param color The base emission color. */
|
||||
inline void SetEmissionColor(const FMVector3& color) { emissionColor = color; }
|
||||
|
||||
/** Retrieves the emission/self-illumination factor.
|
||||
This value must be multiplied with the base emission color to get the real emission color.
|
||||
@return The emission factor. */
|
||||
inline const float& GetEmissionFactor() const { return emissionFactor; }
|
||||
|
||||
/** Sets the emission/self-illumination factor.
|
||||
@param factor The emission factor. */
|
||||
inline void SetEmissionFactor(float factor) { emissionFactor = factor; }
|
||||
|
||||
/** Retrieves whether the emission factor was used, rather than the emission color.
|
||||
This value is used in conjunction with 3dsMax, in which the self-illumination color
|
||||
and the self-illumination factor are mutually exclusive.
|
||||
@return Whether the emission factor is to be used. */
|
||||
inline bool IsEmissionFactor() const { return isEmissionFactor; }
|
||||
|
||||
/** Sets whether the emission factor is to be used, rather than the emission color.
|
||||
This value is used in conjunction with 3dsMax, in which the self-illumination color
|
||||
and the self-illumination factor are mutually exclusive.
|
||||
@param useFactor Whether the emission factor should be used. */
|
||||
inline void SetIsEmissionFactor(bool useFactor) { isEmissionFactor = useFactor; }
|
||||
|
||||
/** Retrieves the diffuse color.
|
||||
This value is used in the Lambert lighting model.
|
||||
@return The diffuse color. */
|
||||
inline const FMVector3& GetDiffuseColor() const { return diffuseColor; }
|
||||
|
||||
/** Sets the diffuse color.
|
||||
@param color The diffuse color. */
|
||||
inline void SetDiffuseColor(const FMVector3& color) { diffuseColor = color; }
|
||||
|
||||
/** Retrieves the ambient color.
|
||||
This value is used in the Lambert lighting model.
|
||||
@return The ambient color. */
|
||||
inline const FMVector3& GetAmbientColor() const { return ambientColor; }
|
||||
|
||||
/** Sets the ambient color.
|
||||
@param color The ambient color. */
|
||||
inline void SetAmbientColor(const FMVector3& color) { ambientColor = color; }
|
||||
|
||||
/** Retrieves the base specular color.
|
||||
This value must be multiplied with the specular factor
|
||||
to get the real specular color.
|
||||
This value is used in the Phong and Blinn lighting models.
|
||||
@return The specular color. */
|
||||
inline const FMVector3& GetSpecularColor() const { return specularColor; }
|
||||
|
||||
/** Sets the specular color.
|
||||
@param color The specular color. */
|
||||
inline void SetSpecularColor(const FMVector3& color) { specularColor = color; }
|
||||
|
||||
/** Retrieves the specular factor.
|
||||
This value must be multiplied with the base specular color
|
||||
to get the real specular color.
|
||||
This value is used in the Phong and Blinn lighting models.
|
||||
@return The specular factor. */
|
||||
inline const float& GetSpecularFactor() const { return specularFactor; }
|
||||
|
||||
/** Sets the specular factor.
|
||||
@param factor The specular factor. */
|
||||
inline void SetSpecularFactor(float factor) { specularFactor = factor; }
|
||||
|
||||
/** Retrieves the specular shininess.
|
||||
This value represents the exponent to which you must raise
|
||||
the dot-product between the view vector and reflected light vectors:
|
||||
as such, it is usually a number greater than 1.
|
||||
This value is used in the Phong and Blinn lighting models.
|
||||
@return The specular shininess. */
|
||||
inline const float& GetShininess() const { return shininess; }
|
||||
|
||||
/** Sets the specular shininess.
|
||||
This value represents the exponent to which you must raise
|
||||
the dot-product between the view vector and reflected light vectors:
|
||||
as such, it is usually a number greater than 1.
|
||||
@param _shininess The specular shininess. */
|
||||
inline void SetShininess(float _shininess) { shininess = _shininess; }
|
||||
|
||||
/** Retrieves the base reflectivity color.
|
||||
This value must be multiplied to the reflectivity factor to
|
||||
get the real reflectivity color.
|
||||
This value is used in the Phong and Blinn lighting models.
|
||||
@return The base reflectivity color. */
|
||||
inline const FMVector3& GetReflectivityColor() const { return reflectivityColor; }
|
||||
|
||||
/** Sets the base reflectivity color.
|
||||
@param color The base reflectivity color. */
|
||||
inline void SetReflectivityColor(const FMVector3& color) { reflectivityColor = color; }
|
||||
|
||||
/** Retrieves the reflectivity factor.
|
||||
This value must be multiplied to the base reflectivity color
|
||||
to get the real reflectivity color.
|
||||
This value is used in the Phong and Blinn lighting models.
|
||||
@return The reflectivity factor. */
|
||||
inline const float& GetReflectivityFactor() const { return reflectivityFactor; }
|
||||
|
||||
/** Sets the reflectivity factor.
|
||||
@param factor The reflectivity factor. */
|
||||
inline void SetReflectivityFactor(float factor) { reflectivityFactor = factor; }
|
||||
|
||||
/** Retrieves the flat reflectivity.
|
||||
This is a calculated value and will not take into consideration any animations
|
||||
that affect either the base reflectivity color or the reflectivity factor.
|
||||
This value can be used in the Phong and Blinn lighting models.
|
||||
@return The flat reflectivity. */
|
||||
float GetReflectivity() const;
|
||||
|
||||
/** Retrieves the 'faceted' flag.
|
||||
This flag is used in conjunction with 3dsMax. It represents whether all the edges
|
||||
of the polygon sets using this effect profile should be hard. The final result
|
||||
of using this flag is a mesh where all the faces stand out.
|
||||
@return The status of the 'faceted' flag. */
|
||||
inline bool GetFacetedFlag() const { return isFaceted; }
|
||||
|
||||
/** Sets the 'faceted' flag.
|
||||
This flag is used in conjunction with 3dsMax. It represents whether all the edges
|
||||
of the polygon sets using this effect profile should be hard. The final result
|
||||
of using this flag is a mesh where all the faces stand out.
|
||||
@param flag The status of the 'faceted' flag. */
|
||||
inline void SetFacetedFlag(bool flag) { isFaceted = flag; }
|
||||
|
||||
/** Retrieves the 'double-sided' flag.
|
||||
This flag is used in conjunction with 3dsMax. It represents whether all the faces
|
||||
of the polygon sets should be treated as two-sided and have normals in both directions.
|
||||
@return The status of the 'double-sided' flag. */
|
||||
inline bool GetDoubleSidedFlag() const { return isDoubleSided; }
|
||||
|
||||
/** Sets the 'double-sided' flag.
|
||||
This flag is used in conjunction with 3dsMax. It represents whether all the faces
|
||||
of the polygon sets should be treated as two-sided and have normals in both directions.
|
||||
@param flag The status of the 'double-sided' flag. */
|
||||
inline bool SetDoubleSidedFlag(bool flag) { isDoubleSided = flag; }
|
||||
|
||||
/** Retrieves the 'wireframe' flag.
|
||||
This flag is used in conjunction with 3dsMax. It represents whether all the edges
|
||||
of the polygon sets should be rendered, rather than the faces.
|
||||
@return The status of the 'wireframe' flag. */
|
||||
inline bool GetWireframeFlag() const { return isWireframe; }
|
||||
|
||||
/** Sets the 'wireframe' flag.
|
||||
This flag is used in conjunction with 3dsMax. It represents whether all the edges
|
||||
of the polygon sets should be rendered, rather than the faces.
|
||||
@param flag The status of the 'wireframe' flag. */
|
||||
inline bool SetWireframeFlag(bool flag) { isWireframe = flag; }
|
||||
|
||||
/** Retrieves the 'face-map' flag.
|
||||
This is a pure 3dsMax flag and I have no idea what it does.
|
||||
@return The status of the 'face-map' flag. */
|
||||
inline bool GetFaceMapFlag() const { return isFaceMap; }
|
||||
|
||||
/** Sets the 'face-map' flag.
|
||||
This is a pure 3dsMax flag and I have no idea what it does.
|
||||
@param flag The status of the 'face-map' flag. */
|
||||
inline void SetFaceMapFlag(bool flag) { isFaceMap = flag; }
|
||||
|
||||
/** Retrieves an effect parameter.
|
||||
Looks for the effect parameter with the correct semantic, in order to bind or override its value.
|
||||
This function searches through the effect profile and the level of abstractions below.
|
||||
@param semantic The effect parameter semantic to match.
|
||||
@return The effect parameter that matches the semantic. This pointer may be
|
||||
NULL if no effect parameter matches the given semantic. */
|
||||
virtual FCDEffectParameter* FindParameterBySemantic(const string& semantic);
|
||||
|
||||
/** Retrieves a subset of the effect parameter list.
|
||||
Look for effect parameters with the correct semantic.
|
||||
This function searches through the effect profile and the level of abstractions below.
|
||||
@param semantic The effect parameter semantic to match.
|
||||
@param parameters The list of parameters to fill in. This list is not cleared. */
|
||||
virtual void FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters);
|
||||
|
||||
/** Retrieves a subset of the effect parameter list.
|
||||
Look for effect parameters with the correct reference.
|
||||
This function searches through the effect profile and the level of abstractions below.
|
||||
@param reference The effect parameter reference to match. In the case of effect
|
||||
parameter, the reference is replaced by the sub-id.
|
||||
@param parameters The list of parameters to fill in. This list is not cleared. */
|
||||
virtual void FindParametersByReference(const string& reference, FCDEffectParameterList& parameters);
|
||||
|
||||
/** [INTERNAL] Clones the COMMON profile effect.
|
||||
You will need release the cloned effect directly, by deleting the pointer.
|
||||
@param newParent The effect that contains the cloned effect profile.
|
||||
@return The cloned effect profile. You will must delete this pointer. */
|
||||
virtual FCDEffectProfile* Clone(FCDEffect* newParent);
|
||||
|
||||
/** [INTERNAL] Flattens the profile.
|
||||
Does nothing on the common profile. */
|
||||
virtual void Flatten() {}
|
||||
|
||||
/** [INTERNAL] Reads in the \<profile_COMMON\> element from a given COLLADA XML tree node.
|
||||
For COLLADA 1.3 backward-compatibility, this function can also read in \<material\> elements.
|
||||
@param baseNode The COLLADA XML tree node.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the effect profile.*/
|
||||
virtual FUStatus LoadFromXML(xmlNode* baseNode);
|
||||
|
||||
/** [INTERNAL] Writes out the \<profile_COMMON\> element to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the effect profile.
|
||||
@return The created element XML tree node. */
|
||||
virtual xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
|
||||
private:
|
||||
xmlNode* WriteColorTextureParameterToXML(xmlNode* parentNode, const char* parameterNodeName, const FMVector3& value, const FCDTextureList& textureBucket) const;
|
||||
xmlNode* WriteFloatTextureParameterToXML(xmlNode* parentNode, const char* parameterNodeName, const float& value, const FCDTextureList& textureBucket) const;
|
||||
xmlNode* WriteTextureParameterToXML(xmlNode* parentNode, const FCDTextureList& textureBucket) const;
|
||||
|
||||
FUStatus ParseColorTextureParameter(xmlNode* parameterNode, FMVector3& value, FCDTextureList& textureBucket);
|
||||
FUStatus ParseFloatTextureParameter(xmlNode* parameterNode, float& value, FCDTextureList& textureBucket);
|
||||
FUStatus ParseSimpleTextureParameter(xmlNode* parameterNode, FCDTextureList& textureBucket);
|
||||
};
|
||||
|
||||
#endif //_FCD_MATERIAL_STANDARD_H_
|
||||
|
||||
254
Extras/FCollada/FCDocument/FCDEffectTechnique.cpp
Normal file
254
Extras/FCollada/FCDocument/FCDEffectTechnique.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDocument.h"
|
||||
#include "FCDocument/FCDEffectCode.h"
|
||||
#include "FCDocument/FCDEffectPass.h"
|
||||
#include "FCDocument/FCDEffectProfileFX.h"
|
||||
#include "FCDocument/FCDEffectParameter.h"
|
||||
#include "FCDocument/FCDEffectParameterFactory.h"
|
||||
#include "FCDocument/FCDEffectParameterList.h"
|
||||
#include "FCDocument/FCDEffectTechnique.h"
|
||||
#include "FCDocument/FCDLibrary.h"
|
||||
#include "FCDocument/FCDImage.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDEffectTechnique::FCDEffectTechnique(FCDocument* document, FCDEffectProfileFX *_parent) : FCDObject(document, "FCDEffectTechnique")
|
||||
{
|
||||
parent = _parent;
|
||||
parameters = new FCDEffectParameterList(GetDocument(), true);;
|
||||
}
|
||||
|
||||
FCDEffectTechnique::~FCDEffectTechnique()
|
||||
{
|
||||
CLEAR_POINTER_VECTOR(codes);
|
||||
CLEAR_POINTER_VECTOR(passes);
|
||||
SAFE_DELETE(parameters);
|
||||
parent = NULL;
|
||||
}
|
||||
|
||||
// Adds a new pass to this effect technique.
|
||||
FCDEffectPass* FCDEffectTechnique::AddPass()
|
||||
{
|
||||
FCDEffectPass* pass = new FCDEffectPass(GetDocument(), this);
|
||||
passes.push_back(pass);
|
||||
return pass;
|
||||
}
|
||||
|
||||
// Releases a pass contaied within this effect technique.
|
||||
void FCDEffectTechnique::ReleasePass(FCDEffectPass* pass)
|
||||
{
|
||||
FCDEffectPassList::iterator it = std::find(passes.begin(), passes.end(), pass);
|
||||
if (it != passes.end())
|
||||
{
|
||||
delete *it;
|
||||
passes.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a new code inclusion to this effect profile.
|
||||
FCDEffectCode* FCDEffectTechnique::AddCode()
|
||||
{
|
||||
FCDEffectCode* code = new FCDEffectCode(GetDocument());
|
||||
codes.push_back(code);
|
||||
return code;
|
||||
}
|
||||
|
||||
// Releases a code inclusion contained within this effect profile.
|
||||
void FCDEffectTechnique::ReleaseCode(FCDEffectCode* code)
|
||||
{
|
||||
FCDEffectCodeList::iterator itC = std::find(codes.begin(), codes.end(), code);
|
||||
if (itC != codes.end())
|
||||
{
|
||||
delete *itC;
|
||||
codes.erase(itC);
|
||||
}
|
||||
}
|
||||
|
||||
FCDEffectTechnique* FCDEffectTechnique::Clone(FCDEffectProfileFX* newParent)
|
||||
{
|
||||
FCDEffectTechnique* clone = new FCDEffectTechnique(GetDocument(), newParent);
|
||||
clone->name = name;
|
||||
SAFE_DELETE(clone->parameters);
|
||||
clone->parameters = parameters->Clone();
|
||||
|
||||
// Clone the codes: need to happen before the passes are cloned
|
||||
clone->codes.reserve(codes.size());
|
||||
for (FCDEffectCodeList::const_iterator itC = codes.begin(); itC != codes.end(); ++itC)
|
||||
{
|
||||
clone->codes.push_back((*itC)->Clone());
|
||||
}
|
||||
|
||||
// Clone the passes
|
||||
for (FCDEffectPassList::iterator itP = passes.begin(); itP != passes.end(); ++itP)
|
||||
{
|
||||
clone->passes.push_back((*itP)->Clone(clone));
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
const string& FCDEffectTechnique::GetDaeId() const
|
||||
{
|
||||
return parent->GetDaeId();
|
||||
}
|
||||
|
||||
void FCDEffectTechnique::AddParameter(FCDEffectParameter* parameter)
|
||||
{
|
||||
parameters->push_back(parameter);
|
||||
}
|
||||
|
||||
// Flatten this effect technique: merge the parameter modifiers and generators
|
||||
void FCDEffectTechnique::Flatten()
|
||||
{
|
||||
for (FCDEffectParameterList::iterator itP = parameters->begin(); itP != parameters->end();)
|
||||
{
|
||||
FCDEffectParameterList generators(GetDocument());
|
||||
if ((*itP)->IsModifier())
|
||||
{
|
||||
// Overwrite the generators
|
||||
FindParametersByReference((*itP)->GetReference(), generators);
|
||||
for (FCDEffectParameterList::iterator itQ = generators.begin(); itQ != generators.end(); ++itQ)
|
||||
{
|
||||
if ((*itQ)->IsGenerator())
|
||||
{
|
||||
(*itP)->Overwrite(*itQ);
|
||||
}
|
||||
}
|
||||
SAFE_DELETE(*itP);
|
||||
parameters->erase(itP);
|
||||
}
|
||||
else
|
||||
{
|
||||
++itP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FUStatus FCDEffectTechnique::LoadFromXML(xmlNode* techniqueNode, xmlNode* profileNode)
|
||||
{
|
||||
FUStatus status;
|
||||
if (!IsEquivalent(techniqueNode->name, DAE_TECHNIQUE_ELEMENT))
|
||||
{
|
||||
return status.Warning(FS("Technique contains unknown element."), techniqueNode->line);
|
||||
}
|
||||
|
||||
string techniqueName = ReadNodeProperty(techniqueNode, DAE_SID_ATTRIBUTE);
|
||||
name = TO_FSTRING(techniqueName);
|
||||
|
||||
// Look for the pass and parameter elements
|
||||
SAFE_DELETE(parameters);
|
||||
parameters = new FCDEffectParameterList(GetDocument(), true);
|
||||
for (xmlNode* child = techniqueNode->children; child != NULL; child = child->next)
|
||||
{
|
||||
if (child->type != XML_ELEMENT_NODE) continue;
|
||||
|
||||
if (IsEquivalent(child->name, DAE_PASS_ELEMENT))
|
||||
{
|
||||
FCDEffectPass* pass = AddPass();
|
||||
status.AppendStatus(pass->LoadFromXML(child, techniqueNode, profileNode));
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_NEWPARAM_ELEMENT) || IsEquivalent(child->name, DAE_FXCMN_SETPARAM_ELEMENT))
|
||||
{
|
||||
AddParameter(FCDEffectParameterFactory::LoadFromXML(GetDocument(), child, &status));
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_FXCMN_CODE_ELEMENT) || IsEquivalent(child->name, DAE_FXCMN_INCLUDE_ELEMENT))
|
||||
{
|
||||
FCDEffectCode* code = new FCDEffectCode(GetDocument());
|
||||
codes.push_back(code);
|
||||
status.AppendStatus(code->LoadFromXML(child));
|
||||
}
|
||||
else if (IsEquivalent(child->name, DAE_IMAGE_ELEMENT))
|
||||
{
|
||||
FCDImage* image = GetDocument()->GetImageLibrary()->AddEntity();
|
||||
status.AppendStatus(image->LoadFromXML(child));
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Write out the effect techniques to the COLLADA xml node tree
|
||||
xmlNode* FCDEffectTechnique::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
xmlNode* techniqueNode = AddChild(parentNode, DAE_TECHNIQUE_ELEMENT);
|
||||
const_cast<FCDEffectTechnique*>(this)->name = TO_FSTRING(AddNodeSid(techniqueNode, !name.empty() ? TO_STRING(name).c_str() : "common"));
|
||||
|
||||
// Write out the code/includes
|
||||
for (FCDEffectCodeList::const_iterator itC = codes.begin(); itC != codes.end(); ++itC)
|
||||
{
|
||||
(*itC)->WriteToXML(techniqueNode);
|
||||
}
|
||||
|
||||
// Write out the effect parameters at this level
|
||||
for (FCDEffectParameterList::const_iterator itP = parameters->begin(); itP != parameters->end(); ++itP)
|
||||
{
|
||||
(*itP)->WriteToXML(techniqueNode);
|
||||
}
|
||||
|
||||
// Write out the passes.
|
||||
// In COLLADA 1.4: there should always be at least one pass.
|
||||
if (!passes.empty())
|
||||
{
|
||||
for (FCDEffectPassList::const_iterator itP = passes.begin(); itP != passes.end(); ++itP)
|
||||
{
|
||||
(*itP)->WriteToXML(techniqueNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UNUSED(xmlNode* dummyPassNode =) AddChild(techniqueNode, DAE_PASS_ELEMENT);
|
||||
}
|
||||
|
||||
return techniqueNode;
|
||||
}
|
||||
|
||||
// Look for the parameter with the given reference.
|
||||
const FCDEffectParameter* FCDEffectTechnique::FindParameter(const char* ref) const
|
||||
{
|
||||
return parameters->FindReference(ref);
|
||||
}
|
||||
|
||||
// Look for the effect parameter with the correct semantic, in order to bind/set its value
|
||||
FCDEffectParameter* FCDEffectTechnique::FindParameterBySemantic(const string& semantic)
|
||||
{
|
||||
return parameters->FindSemantic(semantic);
|
||||
}
|
||||
|
||||
void FCDEffectTechnique::FindParametersBySemantic(const string& semantic, FCDEffectParameterList& _parameters)
|
||||
{
|
||||
for (FCDEffectParameterList::iterator it = parameters->begin(); it != parameters->end(); ++it)
|
||||
{
|
||||
if ((*it)->GetSemantic() == semantic) _parameters.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void FCDEffectTechnique::FindParametersByReference(const string& reference, FCDEffectParameterList& _parameters)
|
||||
{
|
||||
for (FCDEffectParameterList::iterator it = parameters->begin(); it != parameters->end(); ++it)
|
||||
{
|
||||
if ((*it)->GetReference() == reference) _parameters.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
FCDEffectCode* FCDEffectTechnique::FindCode(const string& sid)
|
||||
{
|
||||
for (FCDEffectCodeList::iterator itC = codes.begin(); itC != codes.end(); ++itC)
|
||||
{
|
||||
if ((*itC)->GetSid() == sid) return (*itC);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
const FCDEffectCode* FCDEffectTechnique::FindCode(const string& sid) const
|
||||
{
|
||||
for (FCDEffectCodeList::const_iterator itC = codes.begin(); itC != codes.end(); ++itC)
|
||||
{
|
||||
if ((*itC)->GetSid() == sid) return (*itC);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
195
Extras/FCollada/FCDocument/FCDEffectTechnique.h
Normal file
195
Extras/FCollada/FCDocument/FCDEffectTechnique.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/**
|
||||
@file FCDEffectTechnique.h
|
||||
This file declares the FCDEffectTechnique class.
|
||||
*/
|
||||
|
||||
#ifndef _FCD_EFFECT_TECHNIQUE_H_
|
||||
#define _FCD_EFFECT_TECHNIQUE_H_
|
||||
|
||||
#include "FCDocument/FCDObject.h"
|
||||
|
||||
class FCDEffectCode;
|
||||
class FCDEffectPass;
|
||||
class FCDEffectParameter;
|
||||
class FCDEffectParameterList;
|
||||
class FCDEffectProfileFX;
|
||||
|
||||
typedef vector<FCDEffectPass*> FCDEffectPassList; /**< A dynamically-sized array of effect passes. */
|
||||
typedef vector<FCDEffectCode*> FCDEffectCodeList; /**< A dynamically-sized array of effect code inclusions. */
|
||||
|
||||
/**
|
||||
A COLLADA effect technique.
|
||||
|
||||
The COLLADA effect technique contains the passes to be used in the rendering of
|
||||
polygon sets.
|
||||
|
||||
It also contains a list of effect parameters: both generators and overrides
|
||||
and it is the lowest level of abstraction in which you can access effect parameters. For
|
||||
flattened materials, this means that all the effect parameters will be accessible at this level.
|
||||
|
||||
It also contains a list of effect code inclusions.
|
||||
|
||||
@ingroup FCDEffect
|
||||
*/
|
||||
class FCOLLADA_EXPORT FCDEffectTechnique : public FCDObject
|
||||
{
|
||||
private:
|
||||
FCDEffectProfileFX* parent;
|
||||
|
||||
fstring name;
|
||||
FCDEffectCodeList codes;
|
||||
FCDEffectPassList passes;
|
||||
FCDEffectParameterList* parameters;
|
||||
|
||||
public:
|
||||
/** Constructor: do not use directly.
|
||||
Instead, use the FCDEffectProfileFX::AddTechnique function.
|
||||
@param document The COLLADA document which owns this technique.
|
||||
@param _parent The effect profile which contains the technique. */
|
||||
FCDEffectTechnique(FCDocument* document, FCDEffectProfileFX *_parent);
|
||||
|
||||
/** Destructor: do not use directly.
|
||||
Instead, use the FCDEffectProfileFX::ReleaseTechnique function. */
|
||||
virtual ~FCDEffectTechnique();
|
||||
|
||||
/** Retrieves the effect profile that contains this technique.
|
||||
@return The parent effect profile. */
|
||||
FCDEffectProfileFX* GetParent() { return parent; }
|
||||
const FCDEffectProfileFX* GetParent() const { return parent; } /**< See above. */
|
||||
|
||||
/** Retrieves the COLLADA id of the parent effect.
|
||||
This function is mostly useful as a shortcut for debugging and reporting.
|
||||
@return The COLLADA id of the parent effect. */
|
||||
const string& GetDaeId() const;
|
||||
|
||||
/** Retrieves the sub-id of the technique.
|
||||
@return The sub-id of the technique. */
|
||||
const fstring& GetName() const { return name; }
|
||||
|
||||
/** Sets the sub-id of the technique.
|
||||
The effect technique must have a valid sub-id that is unique
|
||||
within its scope. Otherwise, one will be provided on XML export.
|
||||
@param _name A valid sub-id. */
|
||||
void SetName(const fstring& _name) { name = _name; }
|
||||
|
||||
/** Retrieves the list of passes.
|
||||
@return The list of passes. */
|
||||
FCDEffectPassList& GetPassList() { return passes; }
|
||||
const FCDEffectPassList& GetPassList() const { return passes; } /**< See above. */
|
||||
|
||||
/** Retrieves the number of passes contained within this effect technique.
|
||||
@return The number of passes. */
|
||||
size_t GetPassCount() const { return passes.size(); }
|
||||
|
||||
/** Retrieves a specific pass contained within this effect technique.
|
||||
@param index The index of the pass.
|
||||
@return The pass. This pointer will be NULL if the index is out-of-bounds. */
|
||||
FCDEffectPass* GetPass(size_t index) { FUAssert(index < GetPassCount(), return NULL); return passes.at(index); }
|
||||
const FCDEffectPass* GetPass(size_t index) const { FUAssert(index < GetPassCount(), return NULL); return passes.at(index); } /**< See above. */
|
||||
|
||||
/** Adds a new pass to this effect technique.
|
||||
@return The new pass. */
|
||||
FCDEffectPass* AddPass();
|
||||
|
||||
/** Releases a pass contaied within this effect technique.
|
||||
@param pass The pass to release. */
|
||||
void ReleasePass(FCDEffectPass* pass);
|
||||
|
||||
/** Retrieves the list of code inclusions.
|
||||
@return The list of code inclusions. */
|
||||
FCDEffectCodeList& GetCodeList() { return codes; }
|
||||
const FCDEffectCodeList& GetCodeList() const { return codes; } /**< See above. */
|
||||
|
||||
/** Retrieves the number of code inclusions contained within the effect profile.
|
||||
@return The number of code inclusions. */
|
||||
size_t GetCodeCount() const { return codes.size(); }
|
||||
|
||||
/** Retrieves a code inclusion contained within the effect profile.
|
||||
@param index The index of the code inclusion.
|
||||
@return The code inclusion. This pointer will be NULL if the index is out-of-bounds. */
|
||||
FCDEffectCode* GetCode(size_t index) { FUAssert(index < GetCodeCount(), return NULL); return codes.at(index); }
|
||||
const FCDEffectCode* GetCode(size_t index) const { FUAssert(index < GetCodeCount(), return NULL); return codes.at(index); } /**< See above. */
|
||||
|
||||
/** Retrieves the code inclusion with the given sub-id.
|
||||
@param sid A COLLADA sub-id.
|
||||
@return The code inclusion with the given sub-id. This pointer will be NULL,
|
||||
if there are no code inclusions that match the given sub-id. */
|
||||
FCDEffectCode* FindCode(const string& sid);
|
||||
const FCDEffectCode* FindCode(const string& sid) const; /**< See above. */
|
||||
|
||||
/** Adds a new code inclusion to this effect profile.
|
||||
@return The new code inclusion. */
|
||||
FCDEffectCode* AddCode();
|
||||
|
||||
/** Releases a code inclusion contained within this effect profile.
|
||||
@param code The code inclusion to release. */
|
||||
void ReleaseCode(FCDEffectCode* code);
|
||||
|
||||
/** Retrieves the list of effect parameters contained within the effect profile.
|
||||
This is the lowest level of abstraction and may contain either effect parameter
|
||||
generators or effect parameter overrides.
|
||||
@return The list of effect parameters. */
|
||||
FCDEffectParameterList* GetParameterList() { return parameters; }
|
||||
const FCDEffectParameterList* GetParameterList() const { return parameters; } /**< See above. */
|
||||
|
||||
/** [INTERNAL] Inserts an existing parameter into the list of effect parameters
|
||||
at this abstraction level. This function is used during the flattening of a material.
|
||||
@param parameter The effect parameter to insert. */
|
||||
void AddParameter(FCDEffectParameter* parameter);
|
||||
|
||||
/** Retrieves an effect parameter.
|
||||
Looks for the effect parameter with the correct reference, in order to bind or override its value.
|
||||
@param reference The reference to match. In the case of effect parameter generators,
|
||||
the sub-id is used to match.
|
||||
@return The first effect parameter that matches the reference.
|
||||
This pointer will be NULL if no effect parameter matches the given semantic. */
|
||||
const FCDEffectParameter* FindParameter(const char* reference) const;
|
||||
|
||||
/** Retrieves an effect parameter.
|
||||
Looks for the effect parameter with the correct semantic, in order to bind or override its value.
|
||||
@param semantic The effect parameter semantic to match.
|
||||
@return The first effect parameter that matches the semantic.
|
||||
This pointer will be NULL if no effect parameter matches the given semantic. */
|
||||
virtual FCDEffectParameter* FindParameterBySemantic(const string& semantic);
|
||||
|
||||
/** Retrieves a subset of the effect parameter list.
|
||||
Look for the effect parameter generators with the correct semantic.
|
||||
@param semantic The effect parameter semantic to match.
|
||||
@param parameters The list of parameters to fill in. This list is not cleared. */
|
||||
virtual void FindParametersBySemantic(const string& semantic, FCDEffectParameterList& parameters);
|
||||
|
||||
/** Retrieves a subset of the effect parameter list.
|
||||
Look for the effect parameter generators with the correct reference.
|
||||
@param reference The effect parameter reference to match. In the case of effect
|
||||
parameter generators, the reference is replaced by the sub-id.
|
||||
@param parameters The list of parameters to fill in. This list is not cleared. */
|
||||
virtual void FindParametersByReference(const string& reference, FCDEffectParameterList& parameters);
|
||||
|
||||
/** [INTERNAL] Clones the full effect technique.
|
||||
@param newParent The effect profile that will contain the cloned technique.
|
||||
@return The cloned technique. This pointer will never be NULL. */
|
||||
FCDEffectTechnique* Clone(FCDEffectProfileFX* newParent);
|
||||
|
||||
/** [INTERNAL] Flattens this effect technique.
|
||||
Merges the parameter overrides into the parameter generators. */
|
||||
void Flatten();
|
||||
|
||||
/** [INTERNAL] Reads in the effect technique from a given COLLADA XML tree node.
|
||||
@param techniqueNode The COLLADA XML tree node.
|
||||
@param profileNode X @deprecated bad interface : this dependency must be taken out.
|
||||
@return The status of the import. If the status is not successful,
|
||||
it may be dangerous to extract information from the effect technique.*/
|
||||
FUStatus LoadFromXML(xmlNode* techniqueNode, xmlNode* profileNode);
|
||||
|
||||
/** [INTERNAL] Writes out the effect technique to the given COLLADA XML tree node.
|
||||
@param parentNode The COLLADA XML parent node in which to insert the effect technique.
|
||||
@return The created element XML tree node. */
|
||||
xmlNode* WriteToXML(xmlNode* parentNode) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
127
Extras/FCollada/FCDocument/FCDEntity.cpp
Normal file
127
Extras/FCollada/FCDocument/FCDEntity.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright (C) 2005-2006 Feeling Software Inc.
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
/*
|
||||
Based on the FS Import classes:
|
||||
Copyright (C) 2005-2006 Feeling Software Inc
|
||||
Copyright (C) 2005-2006 Autodesk Media Entertainment
|
||||
MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "FCDocument/FCDEntity.h"
|
||||
#include "FCDocument/FCDExtra.h"
|
||||
#include "FCDocument/FCDSceneNode.h"
|
||||
#include "FUtils/FUDaeParser.h"
|
||||
#include "FUtils/FUDaeWriter.h"
|
||||
#include "FUtils/FUUniqueStringMap.h"
|
||||
using namespace FUDaeParser;
|
||||
using namespace FUDaeWriter;
|
||||
|
||||
FCDEntity::FCDEntity(FCDocument* document, const char* baseId) : FCDObjectWithId(document, baseId)
|
||||
{
|
||||
extra = new FCDExtra(document);
|
||||
}
|
||||
|
||||
FCDEntity::~FCDEntity()
|
||||
{
|
||||
SAFE_DELETE(extra);
|
||||
}
|
||||
|
||||
// Structure cloning
|
||||
void FCDEntity::Clone(FCDEntity* clone)
|
||||
{
|
||||
FCDObjectWithId::Clone(clone);
|
||||
clone->name = name;
|
||||
clone->note = note;
|
||||
}
|
||||
|
||||
void FCDEntity::SetName(const fstring& _name)
|
||||
{
|
||||
name = CleanName(_name);
|
||||
}
|
||||
|
||||
// Parse this entity information from the COLLADA XML document
|
||||
FUStatus FCDEntity::LoadFromXML(xmlNode* entityNode)
|
||||
{
|
||||
FUStatus status;
|
||||
|
||||
string fileId = FUDaeParser::ReadNodeId(entityNode);
|
||||
if (!fileId.empty()) SetDaeId(fileId);
|
||||
else RemoveDaeId();
|
||||
|
||||
name = TO_FSTRING(FUDaeParser::ReadNodeName(entityNode));
|
||||
if (name.empty()) name = TO_FSTRING(fileId);
|
||||
|
||||
xmlNode* extraNode = FindChildByType(entityNode, DAE_EXTRA_ELEMENT);
|
||||
if (extraNode != NULL)
|
||||
{
|
||||
extra->LoadFromXML(extraNode);
|
||||
|
||||
// Look for an extra node at this level and a Max/Maya-specific technique
|
||||
FCDETechnique* mayaTechnique = extra->FindTechnique(DAEMAYA_MAYA_PROFILE);
|
||||
FCDETechnique* maxTechnique = extra->FindTechnique(DAEMAX_MAX_PROFILE);
|
||||
|
||||
// Read in all the extra parameters
|
||||
StringList parameterNames;
|
||||
FCDENodeList parameterNodes;
|
||||
if (mayaTechnique != NULL) mayaTechnique->FindParameters(parameterNodes, parameterNames);
|
||||
if (maxTechnique != NULL) maxTechnique->FindParameters(parameterNodes, parameterNames);
|
||||
|
||||
// Look for the note and user-properties, which is the only parameter currently supported at this level
|
||||
size_t parameterCount = parameterNodes.size();
|
||||
for (size_t i = 0; i < parameterCount; ++i)
|
||||
{
|
||||
FCDENode* parameterNode = parameterNodes[i];
|
||||
const string& parameterName = parameterNames[i];
|
||||
|
||||
if (parameterName == DAEMAX_USERPROPERTIES_NODE_PARAMETER || parameterName == DAEMAYA_NOTE_PARAMETER
|
||||
|| parameterName == DAEMAX_USERPROPERTIES_NODE_PARAMETER1_3 || parameterName == DAEMAYA_MAYA_NOTE_PARAMETER1_3)
|
||||
{
|
||||
note = parameterNode->GetContent();
|
||||
parameterNode->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Look for a children with the given COLLADA Id.
|
||||
FCDEntity* FCDEntity::FindDaeId(const string& _daeId)
|
||||
{
|
||||
if (GetDaeId() == _daeId) return this;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xmlNode* FCDEntity::WriteToXML(xmlNode* parentNode) const
|
||||
{
|
||||
return WriteToEntityXML(parentNode, DAEERR_UNKNOWN_ELEMENT);
|
||||
}
|
||||
|
||||
xmlNode* FCDEntity::WriteToEntityXML(xmlNode* parentNode, const char* nodeName) const
|
||||
{
|
||||
// Create the entity node and write out the id and name attributes
|
||||
xmlNode* entityNode = AddChild(parentNode, nodeName);
|
||||
AddAttribute(entityNode, DAE_ID_ATTRIBUTE, GetDaeId());
|
||||
if (!name.empty())
|
||||
{
|
||||
AddAttribute(entityNode, DAE_NAME_ATTRIBUTE, name);
|
||||
}
|
||||
|
||||
return entityNode;
|
||||
}
|
||||
|
||||
void FCDEntity::WriteToExtraXML(xmlNode* entityNode) const
|
||||
{
|
||||
// Write out the note
|
||||
if (HasNote())
|
||||
{
|
||||
xmlNode* techniqueNode = AddExtraTechniqueChild(entityNode, DAEMAX_MAX_PROFILE);
|
||||
AddChild(techniqueNode, DAEMAX_USERPROPERTIES_NODE_PARAMETER, note);
|
||||
}
|
||||
|
||||
// Write out the user-defined extra information.
|
||||
extra->WriteToXML(entityNode);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user