using System;
using System.Collections;
namespace ColladaNET.Import{
/// <summary>
/// Summary description for GeomHelper.
/// </summary>
public class GeomHelper
{
#region Child Classes
public class Holder
{
public Group [] Groups;
}
public class Group
{
public string Material;
public ArrayList Triangles = new ArrayList(); // holds triangles
public float [][] VertPositions;
public float [][] VertNormals ;
public float [][] VertTexCoords;
}
public class Triangle
{
public int [] VertexIndices;
public float [] FaceNormal;
}
private class VertHolder
{
public VertHolder( int count )
{
Verts = new Vert[count];
}
public Vert [] Verts;
public ArrayList VertPositions = new ArrayList(); // holds float[3]'s
public ArrayList VertNormals = new ArrayList(); // holds float[3]'s
public ArrayList VertTexCoords = new ArrayList(); // holds float[2]'s;
public void Clear()
{
for ( int vertIndex = 0 ; vertIndex < Verts.Length ; vertIndex++ )
{
((Vert)(Verts[vertIndex])).Splits.Clear();
}
VertPositions.Clear();
VertNormals.Clear();
VertTexCoords.Clear();
}
}
private class Vert
{
public Vert( VertHolder parent )
{
mParent = parent;
}
private VertHolder mParent;
public int CDIndex;
public float [] Position;
public int PositionIndex;
public ArrayList Splits = new ArrayList(); // Holds SplitVerts
public SplitVert FindSplit( int normalIndex , int texCoordIndex , float [][] normals , float [][] texCoords , float [] faceNormal )
{
for ( int splitIndex = 0 ; splitIndex < Splits.Count ; splitIndex++ )
{
SplitVert vert = ((SplitVert)(Splits[splitIndex]));
if ( ( vert.NormalIndex == normalIndex )
&&( vert.TexCoordIndex == texCoordIndex ) )
{
return vert; // --- early return ----
}
}
SplitVert split = new SplitVert();
split.NormalIndex = normalIndex;
split.TexCoordIndex = texCoordIndex;
split.ResultVertIndex = mParent.VertPositions.Count;
Splits.Add( split );
mParent.VertPositions.Add( Position );
if ( normalIndex > 0 )
{
mParent.VertNormals.Add( normals[normalIndex] );
}
else
{
mParent.VertNormals.Add( faceNormal );
}
if ( texCoordIndex > 0 )
{
mParent.VertTexCoords.Add( texCoords[texCoordIndex] );
}
else
{
mParent.VertTexCoords.Add( new float[2]{0,0} );
}
return split;
}
}
private class SplitVert
{
public int ResultVertIndex;
public int NormalIndex;
public int TexCoordIndex;
}
#endregion
public static Holder UnpackGeomData( Geometry cdGeometry )
{
Holder geomData = new Holder();
//
// NOTE: Collada uses a single vertex list for all submeshes, while
// RF uses separate vertex lists. Also, RF needs multiple instances
// of a vertex if the vertex is shared by multiple polygons having
// different texture or normal values
//
Mesh mesh = cdGeometry.Mesh.Value;
float [][] cdVertices = mesh.Vertices;
VertHolder sourceVerts = new VertHolder(cdVertices.Length);
for ( int cdVertIndex = 0 ; cdVertIndex < cdVertices.Length ; cdVertIndex++ )
{
Vert vert = new Vert( sourceVerts );
vert.CDIndex = cdVertIndex;
vert.PositionIndex = cdVertIndex;
vert.Position = cdVertices[cdVertIndex];
sourceVerts.Verts[cdVertIndex] = vert;
}
geomData.Groups = new Group[mesh.PolygonGroups.Length];
for ( int groupIndex = 0 ; groupIndex < mesh.PolygonGroups.Length ; groupIndex++ )
{
PolygonGroup cdPolygonGroup = mesh.PolygonGroups[ groupIndex ];
int [][] cdFaceVertexIndices = cdPolygonGroup.GetPolygonIndexData( Collada.kCommon_Input_VERTEX );
int [][] cdFaceNormalIndices = cdPolygonGroup.GetPolygonIndexData( Collada.kCommon_Input_NORMAL );
int [][] cdFaceTexCoordIndices= cdPolygonGroup.GetPolygonIndexData( Collada.kCommon_Input_TEXCOORD );
float [][] cdNormals = cdPolygonGroup.Normals;
float [][] cdTexCoords = cdPolygonGroup.TexCoords;
sourceVerts.Clear();
geomData.Groups[groupIndex] = new Group();
geomData.Groups[groupIndex].Material = cdPolygonGroup.MaterialUrl;
for ( int faceIndex = 0 ; faceIndex < cdFaceVertexIndices.Length ; faceIndex++ )
{
int [] cdFaceIndices = cdFaceVertexIndices[ faceIndex ];
#region Compute faceNormal
float [] c0_pos = cdVertices[ cdFaceIndices[0] ];
float [] c1_pos = cdVertices[ cdFaceIndices[1] ];
float [] c2_pos = cdVertices[ cdFaceIndices[2] ];
float [] faceNormal = ComputeFaceNormal( c0_pos , c1_pos , c2_pos );
#endregion
#region Split the face into triangles
for ( int triangleIndex = 1 ; triangleIndex < cdFaceIndices.Length - 1 ; triangleIndex++ )
{
#region Find the indices within the face of the corners of the triangle
int c0 = 0;
int c1 = triangleIndex;
int c2 = triangleIndex + 1;
#endregion
#region Extract the Normal and TexCoord indices for the corners of the triangle
int [] cornerNormalIndices = new int[3];
if ( ( cdFaceNormalIndices.Length == 0 )
||( cdFaceNormalIndices[faceIndex].Length == 0 ) )
{
cornerNormalIndices[0] = -1; // unavailable, use face normal
cornerNormalIndices[1] = -1; // unavailable, use face normal
cornerNormalIndices[2] = -1; // unavailable, use face normal
}
else
{
cornerNormalIndices[0] = cdFaceNormalIndices[faceIndex][c0];
cornerNormalIndices[1] = cdFaceNormalIndices[faceIndex][c1];
cornerNormalIndices[2] = cdFaceNormalIndices[faceIndex][c2];
}
int [] cornerTexCoordIndices = new int[3];
if ( ( cdFaceTexCoordIndices.Length == 0 )
||( cdFaceTexCoordIndices[faceIndex].Length == 0 ) )
{
cornerTexCoordIndices[0] = -1; // unavailable, use 0,0
cornerTexCoordIndices[1] = -1; // unavailable, use 0,0
cornerTexCoordIndices[2] = -1; // unavailable, use 0,0
}
else
{
cornerTexCoordIndices[0] = cdFaceTexCoordIndices[faceIndex][c0];
cornerTexCoordIndices[1] = cdFaceTexCoordIndices[faceIndex][c1];
cornerTexCoordIndices[2] = cdFaceTexCoordIndices[faceIndex][c2];
}
#endregion
#region Find the split vertex indices (instances of the vertices with the appropriate normal and texcoord values)
SplitVert s0 = sourceVerts.Verts[ cdFaceIndices[c0] ].FindSplit( cornerNormalIndices[0] , cornerTexCoordIndices[0] , cdNormals , cdTexCoords , faceNormal );
SplitVert s1 = sourceVerts.Verts[ cdFaceIndices[c1] ].FindSplit( cornerNormalIndices[1] , cornerTexCoordIndices[1] , cdNormals , cdTexCoords , faceNormal );
SplitVert s2 = sourceVerts.Verts[ cdFaceIndices[c2] ].FindSplit( cornerNormalIndices[2] , cornerTexCoordIndices[2] , cdNormals , cdTexCoords , faceNormal );
#endregion
#region Construct the Triangle
Triangle tri = new Triangle();
tri.VertexIndices = new int[3]{ s0.ResultVertIndex , s1.ResultVertIndex , s2.ResultVertIndex };
tri.FaceNormal = faceNormal;
#endregion
geomData.Groups[groupIndex].Triangles.Add( tri );
}
#endregion
}
#region Construct the vertex data buffers
geomData.Groups[groupIndex].VertPositions = new float [sourceVerts.VertPositions.Count][];
geomData.Groups[groupIndex].VertNormals = new float [sourceVerts.VertNormals.Count][];
geomData.Groups[groupIndex].VertTexCoords = new float [sourceVerts.VertTexCoords.Count][];
sourceVerts.VertPositions.CopyTo( geomData.Groups[groupIndex].VertPositions );
sourceVerts.VertNormals.CopyTo( geomData.Groups[groupIndex].VertNormals );
sourceVerts.VertTexCoords.CopyTo( geomData.Groups[groupIndex].VertTexCoords );
#endregion
}
return geomData;
}
private static float [] ComputeFaceNormal( float [] p0 , float [] p1 , float [] p2 )
{
float [] result = new float[3];
result[0] = (p1[1]-p0[1])*(p2[2]-p0[2]) - (p1[2]-p0[2])*(p2[1]-p0[1]);
result[1] = (p1[2]-p0[2])*(p2[0]-p0[0]) - (p1[0]-p0[0])*(p2[2]-p0[2]);
result[2] = (p1[0]-p0[0])*(p2[1]-p0[1]) - (p1[1]-p0[1])*(p2[0]-p0[0]);
return result;
}
}
}
|