summaryrefslogtreecommitdiff
path: root/Runtime/Filters/Mesh/CompressedMesh.cpp
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-14 22:50:43 +0800
committerchai <chaifix@163.com>2019-08-14 22:50:43 +0800
commit15740faf9fe9fe4be08965098bbf2947e096aeeb (patch)
treea730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Filters/Mesh/CompressedMesh.cpp
+Unity Runtime codeHEADmaster
Diffstat (limited to 'Runtime/Filters/Mesh/CompressedMesh.cpp')
-rw-r--r--Runtime/Filters/Mesh/CompressedMesh.cpp755
1 files changed, 755 insertions, 0 deletions
diff --git a/Runtime/Filters/Mesh/CompressedMesh.cpp b/Runtime/Filters/Mesh/CompressedMesh.cpp
new file mode 100644
index 0000000..02cc74c
--- /dev/null
+++ b/Runtime/Filters/Mesh/CompressedMesh.cpp
@@ -0,0 +1,755 @@
+#include "UnityPrefix.h"
+#include "CompressedMesh.h"
+#include "LodMesh.h"
+#include "Runtime/Animation/AnimationCurveUtility.h"
+
+
+#define sqr(x) ((x)*(x))
+
+void PackedFloatVector::PackFloats(float *data, int itemCountInChunk, int chunkStride, int numChunks, int bitSize, bool adjustBitSize)
+{
+ float maxf = -std::numeric_limits<float>::infinity();
+ float minf = std::numeric_limits<float>::infinity();
+ float* end = Stride (data, numChunks * chunkStride);
+ for(float* it = data; it != end; it = Stride (it, chunkStride))
+ {
+ for (int i=0; i<itemCountInChunk; ++i)
+ {
+ if(maxf < it[i])
+ maxf = it[i];
+ if(minf > it[i])
+ minf = it[i];
+ }
+ }
+
+ m_Range = maxf-minf;
+
+ if(adjustBitSize)
+ bitSize += int(ceilf(Log2(m_Range)));
+ if(bitSize > 32)
+ bitSize = 32;
+
+ m_Start = minf;
+ m_NumItems = numChunks * itemCountInChunk;
+ m_BitSize = bitSize;
+ m_Data.resize((m_NumItems * bitSize + 7)/8, 0);
+
+
+ float scale = 1.0/m_Range;
+
+ int indexPos = 0;
+ int bitPos = 0;
+
+ for(float* it = data; it != end; it = Stride (it, chunkStride))
+ {
+ for(int i=0; i<itemCountInChunk; ++i)
+ {
+ float scaled = (it[i] - m_Start) * scale;
+ if(scaled < 0) scaled = 0;
+ if(scaled > 1) scaled = 1;
+
+ UInt32 x = UInt32(scaled * ((1 << (m_BitSize)) - 1));
+
+ int bits = 0;
+ while(bits < m_BitSize)
+ {
+ m_Data[indexPos] |= (x >> bits) << bitPos;
+ int num = std::min( m_BitSize-bits, 8-bitPos);
+ bitPos += num;
+ bits += num;
+ if(bitPos == 8)
+ {
+ indexPos++;
+ bitPos = 0;
+ }
+ }
+ }
+ }
+}
+
+void PackedFloatVector::UnpackFloats(float *data, int itemCountInChunk, int chunkStride, int start, int numChunks)
+{
+ int bitPos = m_BitSize*start;
+ int indexPos = bitPos/8;
+ bitPos %= 8;
+
+ float scale = 1.0/m_Range;
+ if (numChunks == -1)
+ numChunks = m_NumItems / itemCountInChunk;
+
+ for(float* end = Stride (data, chunkStride * numChunks); data != end; data = Stride (data, chunkStride))
+ {
+ for (int i=0; i<itemCountInChunk; ++i)
+ {
+ UInt32 x = 0;
+
+ int bits = 0;
+ while(bits < m_BitSize)
+ {
+ x |= (m_Data[indexPos] >> bitPos) << bits;
+ int num = std::min( m_BitSize-bits, 8-bitPos);
+ bitPos += num;
+ bits += num;
+ if(bitPos == 8)
+ {
+ indexPos++;
+ bitPos = 0;
+ }
+ }
+ x &= (1 << m_BitSize) - 1;
+ data[i] = (x / (scale * ((1 << (m_BitSize)) - 1))) + m_Start;
+ }
+ }
+}
+
+template <class IntSize> void PackedIntVector::PackInts(IntSize *data, int numItems)
+{
+ // make sure that the intsize is an unsigned type
+ Assert( (IntSize)0 < (IntSize)-1 );
+
+ UInt32 maxi = 0;
+ for(int i=0; i<numItems; i++)
+ if(maxi < data[i])
+ maxi = data[i];
+
+ m_NumItems = numItems;
+ //Prevent overflow
+ m_BitSize = UInt8(maxi == 0xFFFFFFFF ? 32 : ceilf(Log2(maxi+1)));
+ m_Data.resize((numItems * m_BitSize + 7)/8, 0);
+
+
+ int indexPos = 0;
+ int bitPos = 0;
+ for(int i=0; i<numItems; i++)
+ {
+ int bits = 0;
+ while(bits < m_BitSize)
+ {
+ m_Data[indexPos] |= (data[i] >> bits) << bitPos;
+ int num = std::min( m_BitSize-bits, 8-bitPos);
+ bitPos += num;
+ bits += num;
+ if(bitPos == 8)
+ {
+ indexPos++;
+ bitPos = 0;
+ }
+ }
+ }
+}
+
+template <class IntSize> void PackedIntVector::UnpackInts(IntSize *data)
+{
+ int indexPos = 0;
+ int bitPos = 0;
+ for(int i=0; i<m_NumItems; i++)
+ {
+ int bits = 0;
+ data[i] = 0;
+ while(bits < m_BitSize)
+ {
+ data[i] |= (m_Data[indexPos] >> bitPos) << bits;
+ int num = std::min( m_BitSize-bits, 8-bitPos);
+ bitPos += num;
+ bits += num;
+ if(bitPos == 8)
+ {
+ indexPos++;
+ bitPos = 0;
+ }
+ }
+ data[i] &= (1ULL << m_BitSize) - 1;
+ }
+}
+
+
+void PackedQuatVector::PackQuats(Quaternionf *data, int numItems)
+{
+ m_NumItems = numItems;
+ m_Data.resize(numItems * (32/8), 0);
+
+ int indexPos = 0;
+ int bitPos = 0;
+
+ for(int i=0; i<numItems; i++)
+ {
+ Quaternionf &q = data[i];
+ UInt8 flags = q.x<0? 4:0;
+
+ float max=fabs(q.x);
+ if(fabs(q.y) > max)
+ {
+ max = fabs(q.y);
+ flags = 1;
+ if(q.y<0)
+ flags |= 4;
+ }
+ if(fabs(q.z) > max)
+ {
+ max = fabs(q.z);
+ flags = 2;
+ if(q.z<0)
+ flags |= 4;
+ }
+ if(fabs(q.w) > max)
+ {
+ max = fabs(q.w);
+ flags = 3;
+ if(q.w<0)
+ flags |= 4;
+ }
+ int bits = 0;
+ while(bits < 3)
+ {
+ m_Data[indexPos] |= (flags >> bits) << bitPos;
+ int num = std::min( 3-bits, 8-bitPos);
+ bitPos += num;
+ bits += num;
+ if(bitPos == 8)
+ {
+ indexPos++;
+ bitPos = 0;
+ }
+ }
+ for(int j=0;j<4;j++)
+ {
+ if((flags&3) != j)
+ {
+ int bitSize = (((flags&3)+1)%4 == j)?9:10;
+ float scaled = (q[j] + 1) * 0.5;
+ if(scaled < 0) scaled = 0;
+ if(scaled > 1) scaled = 1;
+
+ UInt32 x = UInt32(scaled * ((1 << bitSize) - 1));
+
+ bits = 0;
+ while(bits < bitSize)
+ {
+ m_Data[indexPos] |= (x >> bits) << bitPos;
+ int num = std::min( bitSize-bits, 8-bitPos);
+ bitPos += num;
+ bits += num;
+ if(bitPos == 8)
+ {
+ indexPos++;
+ bitPos = 0;
+ }
+ }
+ }
+ }
+ }
+}
+
+void PackedQuatVector::UnpackQuats(Quaternionf *data)
+{
+ int indexPos = 0;
+ int bitPos = 0;
+
+ for(int i=0; i<m_NumItems; i++)
+ {
+ UInt32 flags = 0;
+
+ int bits = 0;
+ while(bits < 3)
+ {
+ flags |= (m_Data[indexPos] >> bitPos) << bits;
+ int num = std::min( 3-bits, 8-bitPos);
+ bitPos += num;
+ bits += num;
+ if(bitPos == 8)
+ {
+ indexPos++;
+ bitPos = 0;
+ }
+ }
+ flags &= 7;
+
+
+ Quaternionf &q = data[i];
+ float sum = 0;
+ for(int j=0;j<4;j++)
+ {
+ if((flags&3) != j)
+ {
+ int bitSize = (((flags&3)+1)%4 == j)?9:10;
+ UInt32 x = 0;
+
+ bits = 0;
+ while(bits < bitSize)
+ {
+ x |= (m_Data[indexPos] >> bitPos) << bits;
+ int num = std::min( bitSize-bits, 8-bitPos);
+ bitPos += num;
+ bits += num;
+ if(bitPos == 8)
+ {
+ indexPos++;
+ bitPos = 0;
+ }
+ }
+ x &= (1 << bitSize) - 1;
+ q[j] = (x / (0.5 * ((1 << (bitSize)) - 1))) - 1;
+ sum += sqr(q[j]);
+ }
+ }
+
+ int lastComponent = flags&3;
+ q[lastComponent] = FastSqrt(1 - sum);
+ if(flags & 4)
+ q[lastComponent] = -q[lastComponent];
+ }
+}
+
+void CompressedMesh::Compress(Mesh &src, int compression)
+{
+ int numVertices = src.GetVertexCount();
+
+ int vertexBits = 0;
+ switch(compression)
+ {
+ case kMeshCompressionHigh: vertexBits = 10; break;
+ case kMeshCompressionMed: vertexBits = 16; break;
+ case kMeshCompressionLow: vertexBits = 20; break;
+ }
+ m_Vertices.PackFloats((float*)src.GetChannelPointer(kShaderChannelVertex), 3, src.GetStride (kShaderChannelVertex), numVertices, vertexBits, false);
+
+ //Possible optimization: use Edgebreaker algorithm
+ //for 1.8 bits per triangle connectivity information
+ //http://www.gvu.gatech.edu/~jarek/edgebreaker/eb/
+
+ int numIndices = src.m_IndexBuffer.size();
+ numIndices/=2;
+
+ m_Triangles.PackInts<UInt16>((UInt16*)&src.m_IndexBuffer[0],numIndices);
+
+ if(src.IsAvailable(kShaderChannelTexCoord0))
+ {
+ int uvBits = 0;
+ switch(compression)
+ {
+ case kMeshCompressionHigh: uvBits = 8; break;
+ case kMeshCompressionMed: uvBits = 10; break;
+ case kMeshCompressionLow: uvBits = 16; break;
+ }
+ if(src.IsAvailable(kShaderChannelTexCoord1))
+ {
+ Vector2f *uv12 = new Vector2f[numVertices*2];
+ src.ExtractUvArray(0, uv12);
+ src.ExtractUvArray(1, uv12 + numVertices);
+ m_UV.PackFloats(&uv12->x, 2, sizeof(Vector2f), numVertices*2, uvBits, true);
+ delete[] uv12;
+ }
+ else
+ m_UV.PackFloats((float*)src.GetChannelPointer (kShaderChannelTexCoord0), 2, src.GetStride (kShaderChannelTexCoord0), numVertices, uvBits, true);
+ }
+ else if(src.IsAvailable(kShaderChannelTexCoord1))
+ ErrorString( "Mesh compression doesn't work on Meshes wich only have a UV1 channel but no UV0 channel. UVs will be dropped." );
+
+ if(src.IsAvailable (kShaderChannelNormal))
+ {
+ int normalBits = 0;
+ switch(compression)
+ {
+ case kMeshCompressionHigh: normalBits = 6; break;
+ case kMeshCompressionMed: normalBits = 8; break;
+ case kMeshCompressionLow: normalBits = 8; break;
+ }
+
+ float *normals = new float[numVertices*2];
+ UInt32 *signs = new UInt32[numVertices];
+ StrideIterator<Vector3f> n = src.GetNormalBegin ();
+ for(int i=0;i<numVertices; ++i, ++n)
+ {
+ normals[i*2+0] = n->x;
+ normals[i*2+1] = n->y;
+ signs[i] = n->z>0?1:0;
+ }
+ m_Normals.PackFloats(normals, 2, sizeof (float) * 2, numVertices, normalBits, false);
+ m_NormalSigns.PackInts(signs, numVertices);
+ delete[] normals;
+ delete[] signs;
+ }
+
+ if(src.IsAvailable (kShaderChannelTangent))
+ {
+ int normalBits = 0;
+ switch(compression)
+ {
+ case kMeshCompressionHigh: normalBits = 6; break;
+ case kMeshCompressionMed: normalBits = 8; break;
+ case kMeshCompressionLow: normalBits = 8; break;
+ }
+
+ float *tangents = new float[numVertices*2];
+ UInt32 *signs = new UInt32[numVertices*2];
+ StrideIterator<Vector4f> t = src.GetTangentBegin ();
+ for(int i=0;i<numVertices; ++i, ++t)
+ {
+ tangents[i*2+0] = t->x;
+ tangents[i*2+1] = t->y;
+ signs[i*2+0] = t->z>0?1:0;
+ signs[i*2+1] = t->w>0?1:0;
+ }
+ m_Tangents.PackFloats(tangents, 2, sizeof (float) * 2, numVertices, normalBits, false);
+ m_TangentSigns.PackInts(signs, numVertices*2);
+ delete[] tangents;
+ delete[] signs;
+ }
+
+ // TODO: do an actual compression
+ if(src.IsAvailable (kShaderChannelColor))
+ {
+ dynamic_array<UInt32> tempColors (numVertices, kMemTempAlloc);
+ std::transform (src.GetColorBegin (), src.GetColorEnd (), tempColors.begin (), OpColorRGBA32ToUInt32());
+ m_Colors.PackInts<UInt32> (tempColors.data (), tempColors.size ());
+ }
+
+ BoneInfluence* influence = src.GetBoneWeights();
+ if(influence)
+ {
+ UInt32 *weights = new UInt32[numVertices*3];
+ UInt32 *indices = new UInt32[numVertices*4];
+ int weightPos = 0;
+ int boneIndexPos = 0;
+ for(int i=0;i<numVertices;i++)
+ {
+ int j;
+ int sum = 0;
+
+ //As all four bone weights always add up to 1, we can always calculate the fourth one
+ // by subtracting the other three from 1. So we don't need to store it.
+
+ //Furthermore, once the weights we stored add up to 1, we don't need to store further
+ //weights or indices, as these will necessarily be zero. This is often the case, as many
+ //vertices have only the first weight set to one, and all others to zero.
+
+ //find last non-zero entry -- we don't need to store those after this.
+ int lastNonZero;
+ for(lastNonZero=3;lastNonZero>0&&influence[i].weight[lastNonZero]==0;lastNonZero--)
+ {}
+
+
+ for(j=0;j<3 && j<=lastNonZero && sum<31;j++)
+ {
+ weights[weightPos] = UInt32(influence[i].weight[j] * 31);
+ indices[boneIndexPos++] = influence[i].boneIndex[j];
+ sum += weights[weightPos++];
+ }
+ if(lastNonZero<3)
+ {
+ //we stored less then 3 weights, but they don't add up to one, due to quantization
+ //inprecision.
+ //Add the difference, so the math works out on decompression.
+ if(sum<31)
+ weights[weightPos-1] += 31-sum;
+ }
+
+ //we stored three weights, but they don't add up to one. we don't need to store the fourth weight
+ //(as it can be calculated from the other three), but we need the bone index.
+ else if(sum<31)
+ indices[boneIndexPos++] = influence[i].boneIndex[j];
+ }
+
+ m_Weights.PackInts(weights, weightPos);
+ m_BoneIndices.PackInts(indices, boneIndexPos);
+
+ delete[] weights;
+ delete[] indices;
+ }
+}
+
+void CompressedMesh::Decompress(Mesh &src)
+{
+ int numIndices = m_Triangles.Count();
+ src.m_IndexBuffer.resize(numIndices * 2);
+ m_Triangles.UnpackInts<UInt16>((UInt16*)&src.m_IndexBuffer[0]);
+
+ int numVertices = m_Vertices.Count()/3;
+ unsigned decompressedFormat = 0;
+ if (m_Vertices.Count ()) decompressedFormat |= VERTEX_FORMAT1(Vertex);
+ if (m_Normals.Count()) decompressedFormat |= VERTEX_FORMAT1(Normal);
+ if (m_UV.Count()) decompressedFormat |= VERTEX_FORMAT1(TexCoord0);
+ if (m_UV.Count() == numVertices * 4) decompressedFormat |= VERTEX_FORMAT1(TexCoord1);
+ if (m_Tangents.Count()) decompressedFormat |= VERTEX_FORMAT1(Tangent);
+ if (m_Colors.Count()) decompressedFormat |= VERTEX_FORMAT1(Color);
+
+ src.ResizeVertices(numVertices, decompressedFormat);
+ Assert (src.GetVertexCount () == numVertices);
+
+ m_Vertices.UnpackFloats((float*)src.GetChannelPointer (kShaderChannelVertex), 3, src.GetStride (kShaderChannelVertex));
+
+ if(m_UV.Count())
+ {
+ m_UV.UnpackFloats((float*)src.GetChannelPointer (kShaderChannelTexCoord0), 2, src.GetStride (kShaderChannelTexCoord0), 0, numVertices);
+
+ if(m_UV.Count()==numVertices * 4)
+ {
+ m_UV.UnpackFloats((float*)src.GetChannelPointer (kShaderChannelTexCoord1), 2, src.GetStride (kShaderChannelTexCoord1), numVertices*2, numVertices);
+ }
+ }
+
+ // TODO: This never gets written. Unity 3.4 and 3.5 never wrote this data.
+ // Most likely no version ever did. Remove code and bindpose serialization.
+ if(m_BindPoses.Count())
+ {
+ src.m_Bindpose.resize_initialized(m_BindPoses.Count()/16);
+ m_BindPoses.UnpackFloats(src.m_Bindpose[0].m_Data, 16, sizeof(float) * 16);
+ }
+
+ if(m_Normals.Count())
+ {
+ float *normalData = new float[m_Normals.Count()];
+ UInt32 *signs = new UInt32[m_NormalSigns.Count()];
+
+ m_Normals.UnpackFloats(normalData, 2, sizeof(float) * 2);
+ m_NormalSigns.UnpackInts(signs);
+
+ StrideIterator<Vector3f> n = src.GetNormalBegin ();
+ for(int i=0;i<m_Normals.Count()/2; ++i, ++n)
+ {
+ n->x = normalData[i*2+0];
+ n->y = normalData[i*2+1];
+ float zsqr = 1 - sqr(n->x) - sqr(n->y);
+ if(zsqr >= 0)
+ n->z = FastSqrt( zsqr );
+ else
+ {
+ n->z = 0;
+ *n = Normalize(*n);
+ }
+ if(signs[i]==0)
+ n->z = -n->z;
+ }
+
+ delete[] normalData;
+ delete[] signs;
+ }
+
+ if(m_Tangents.Count())
+ {
+ float *tangentData = new float[m_Tangents.Count()];
+ UInt32 *signs = new UInt32[m_TangentSigns.Count()];
+
+ m_Tangents.UnpackFloats(tangentData, 2, sizeof(float) * 2);
+ m_TangentSigns.UnpackInts(signs);
+
+ StrideIterator<Vector4f> t = src.GetTangentBegin ();
+ for(int i=0;i<m_Tangents.Count()/2; ++i, ++t)
+ {
+ t->x = tangentData[i*2+0];
+ t->y = tangentData[i*2+1];
+ float zsqr = 1-sqr(tangentData[i*2+0])-sqr(tangentData[i*2+1]);
+ if(zsqr >= 0.0f)
+ t->z = FastSqrt( zsqr );
+ else
+ {
+ t->z = 0;
+ *(Vector3f*)(&*t) = Normalize(*(Vector3f*)(&*t));
+ }
+ if(signs[i*2+0]==0)
+ t->z = -t->z;
+
+ t->w = signs[i*2+1]?1.0:-1.0;
+ }
+
+ delete[] tangentData;
+ delete[] signs;
+ }
+
+ // TODO: do an actual compression
+ if (m_Colors.Count())
+ {
+ dynamic_array<UInt32> tempColors (m_Colors.Count (), kMemTempAlloc);
+ m_Colors.UnpackInts<UInt32> (tempColors.data ());
+ Assert (tempColors.size () == src.GetVertexCount ());
+ strided_copy ((ColorRGBA32*)tempColors.begin (), (ColorRGBA32*)tempColors.end (), src.GetColorBegin ());
+ }
+
+ if(m_Weights.Count())
+ {
+ UInt32 *weights = new UInt32[m_Weights.Count()];
+ m_Weights.UnpackInts(weights);
+ UInt32 *boneIndices = new UInt32[m_BoneIndices.Count()];
+ m_BoneIndices.UnpackInts(boneIndices);
+ src.m_Skin.resize_uninitialized(numVertices);
+ int bonePos = 0;
+ int boneIndexPos = 0;
+ int j=0;
+ int sum = 0;
+
+ for(int i=0;i<m_Weights.Count();i++)
+ {
+ //read bone index and weight.
+ src.m_Skin[bonePos].weight[j] = weights[i]/31.0;
+ src.m_Skin[bonePos].boneIndex[j] = boneIndices[boneIndexPos++];
+ j++;
+ sum += weights[i];
+
+ //the weights add up to one. fill the rest for this vertex with zero, and continue with next one.
+ if(sum >= 31)
+ {
+ for(;j<4;j++)
+ {
+ src.m_Skin[bonePos].weight[j] = 0;
+ src.m_Skin[bonePos].boneIndex[j] = 0;
+ }
+ bonePos++;
+ j = 0;
+ sum = 0;
+ }
+ //we read three weights, but they don't add up to one. calculate the fourth one, and read
+ //missing bone index. continue with next vertex.
+ else if(j==3)
+ {
+ src.m_Skin[bonePos].weight[j] = (31-sum)/31.0;
+ src.m_Skin[bonePos].boneIndex[j] = boneIndices[boneIndexPos++];
+ bonePos++;
+ j = 0;
+ sum = 0;
+ }
+ }
+
+ delete[] weights;
+ delete[] boneIndices;
+ }
+}
+
+template <class T> void CompressedAnimationCurve::CompressTimeKeys(AnimationCurveTpl<T> &src)
+{
+ int numKeys = src.GetKeyCount();
+
+ float minTime=0;
+ for(int i=0;i<numKeys;i++)
+ {
+ float t = src.GetKey(i).time;
+ if(t < minTime)
+ {
+ //negative time key. offset all keys by this, so math doesn't break - but it's still wrong.
+ minTime = t;
+ }
+ }
+
+
+ UInt32 *times = new UInt32[numKeys];
+ UInt32 t=0;
+ for(int i=0;i<numKeys;i++)
+ {
+ times[i] = UInt32((src.GetKey(i).time - minTime) * 100);
+ times[i] -= t;
+ t += times[i];
+ }
+
+ m_Times.PackInts(times, numKeys);
+
+ delete[] times;
+}
+
+template <class T> void CompressedAnimationCurve::DecompressTimeKeys(AnimationCurveTpl<T> &src)
+{
+ int numKeys = m_Times.Count();
+ UInt32 *times = new UInt32[numKeys];
+ m_Times.UnpackInts(times);
+
+ UInt32 t=0;
+
+ src.ResizeUninitialized(numKeys);
+
+ for(int i=0;i<numKeys;i++)
+ {
+ t+=times[i];
+ src.GetKey(i).time = t*0.01;
+ }
+ delete[] times;
+}
+
+void CompressedAnimationCurve::CompressQuatCurve(AnimationClip::QuaternionCurve &src)
+{
+ CompressTimeKeys(src.curve);
+ int numKeys = src.curve.GetKeyCount();
+
+ Quaternionf *qkeys = new Quaternionf[numKeys];
+ for(int i=0;i<numKeys;i++)
+ qkeys[i] = src.curve.GetKey(i).value;
+ m_Values.PackQuats(qkeys, numKeys);
+
+ delete[] qkeys;
+
+ bool same = true;
+
+ for(int i=0;i<numKeys && same;i++)
+ {
+ Quaternionf &q1 = src.curve.GetKey(i).inSlope;
+ Quaternionf &q2 = src.curve.GetKey(i).inSlope;
+ if(q1.x!=q2.x)
+ same = false;
+ if(q1.y!=q2.y)
+ same = false;
+ if(q1.z!=q2.z)
+ same = false;
+ if(q1.w!=q2.w)
+ same = false;
+ }
+
+ float *keys = new float[numKeys*8];
+ for(int i=0;i<numKeys;i++)
+ {
+ Quaternionf q = src.curve.GetKey(i).inSlope;
+ keys[i*4+0] = q.x;
+ keys[i*4+1] = q.y;
+ keys[i*4+2] = q.z;
+ keys[i*4+3] = q.w;
+ q = src.curve.GetKey(i).outSlope;
+ keys[(i+numKeys)*4+0] = q.x;
+ keys[(i+numKeys)*4+1] = q.y;
+ keys[(i+numKeys)*4+2] = q.z;
+ keys[(i+numKeys)*4+3] = q.w;
+ }
+
+ //if in and out slopes are all the same, pack only the first of the two.
+ if(same)
+ m_Slopes.PackFloats(keys, 1, sizeof(float), numKeys * 4, 6, false);
+ else
+ m_Slopes.PackFloats(keys, 1, sizeof(float), numKeys * 8, 6, false);
+
+ delete[] keys;
+
+ m_PreInfinity = src.curve.GetPreInfinityInternal();
+ m_PostInfinity = src.curve.GetPostInfinityInternal();
+ m_Path = src.path;
+}
+
+void CompressedAnimationCurve::DecompressQuatCurve(AnimationClip::QuaternionCurve &src)
+{
+ DecompressTimeKeys(src.curve);
+ int numKeys = m_Values.Count();
+
+ Quaternionf *qkeys = new Quaternionf[numKeys];
+ m_Values.UnpackQuats(qkeys);
+ for(int i=0;i<numKeys;i++)
+ src.curve.GetKey(i).value = qkeys[i];
+ delete[] qkeys;
+
+ float *keys = new float[numKeys*8];
+ m_Slopes.UnpackFloats(keys, 1, sizeof(float));
+
+ //are there seperate in and out slopes?
+ int offs = 0;
+ if(m_Slopes.Count() == numKeys*8)
+ offs = numKeys;
+ for(int i=0;i<numKeys;i++)
+ {
+ src.curve.GetKey(i).inSlope.x = keys[i*4+0];
+ src.curve.GetKey(i).inSlope.y = keys[i*4+1];
+ src.curve.GetKey(i).inSlope.z = keys[i*4+2];
+ src.curve.GetKey(i).inSlope.w = keys[i*4+3];
+ src.curve.GetKey(i).outSlope.x = keys[(i+offs)*4+0];
+ src.curve.GetKey(i).outSlope.y = keys[(i+offs)*4+1];
+ src.curve.GetKey(i).outSlope.z = keys[(i+offs)*4+2];
+ src.curve.GetKey(i).outSlope.w = keys[(i+offs)*4+3];
+ }
+ delete[] keys;
+
+ src.curve.SetPreInfinityInternal( m_PreInfinity );
+ src.curve.SetPostInfinityInternal( m_PostInfinity );
+ src.path = m_Path;
+}