00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "LampBasic.h"
00026 #include "Animation/RotationInterpolator/RotationInterpolationCompressor.h"
00027 #include "Animation/RotationInterpolator/QuaternionArrayInterpolator.h"
00028 #include "Animation/RotationInterpolator/EulerArrayInterpolator.h"
00029 #include "Animation/RotationInterpolator/RotationConstantInterpolator.h"
00030 #include "Animation/RotationInterpolator/QuaternionLinearInterpolator.h"
00031 #include "Core/Container/Deque.h"
00032
00033 namespace Lamp{
00034
00035
00036
00037
00038
00039 RotationInterpolationCompressor::RotationInterpolationCompressor() :
00040 tolerance_(0.f), length_(0.f), sourceKeyCount_(0), compressedKeyCount_(0),
00041 compressedKeySize_(0){
00042 }
00043
00044
00045 RotationInterpolationCompressor::~RotationInterpolationCompressor(){
00046 }
00047
00048
00049
00050
00051 RotationInterpolator* RotationInterpolationCompressor::compress(
00052 EulerArrayInterpolator* source, float tolerance){
00053
00054 QuaternionArrayInterpolator* interpolator =
00055 source->convertQuaternionArrayInterpolator();
00056 RotationInterpolator* result = compress(interpolator, tolerance);
00057 delete interpolator;
00058 return result;
00059 }
00060
00061
00062 RotationInterpolator* RotationInterpolationCompressor::compress(
00063 QuaternionArrayInterpolator* source, float tolerance){
00064
00065 compressSetup(source, tolerance);
00066 RotationInterpolator* result = NULL;
00067
00068
00069 result = compressConstant(source);
00070 if(result != NULL){ return result; }
00071
00072
00073 result = compressLinear(source);
00074 if(result != NULL){ return result; }
00075
00076
00077
00078
00079
00080 result = source->duplicate();
00081 setCompressedData(getSourceKeyCount(), sourceKeySize_);
00082
00083 return result;
00084 }
00085
00086
00087 void RotationInterpolationCompressor::compressSetup(
00088 QuaternionArrayInterpolator* source, float tolerance){
00089 Assert(source != NULL);
00090 Assert((tolerance >= 0.f) && (tolerance < Math::halfPI));
00091 tolerance_ = tolerance;
00092 length_ = source->getLength();
00093 sourceKeyCount_ = source->getSize();
00094 Assert(sourceKeyCount_ > 1);
00095 }
00096
00097
00098 RotationInterpolator* RotationInterpolationCompressor::compressConstant(
00099 QuaternionArrayInterpolator* source){
00100
00101 const Quaternion& targetValue = source->getValue(0);
00102 Assert(targetValue.isUnit());
00103
00104
00105 float toleranceCos = Math::cos(getTolerance());
00106 for(int i = 0; i < sourceKeyCount_; i++){
00107 const Quaternion& sourceValue = source->getValue(i);
00108 Assert(sourceValue.isUnit());
00109
00110 if(targetValue.dotProduct(sourceValue) < toleranceCos){ return NULL; }
00111 }
00112
00113
00114 RotationConstantInterpolator* result = new RotationConstantInterpolator();
00115 result->setLength(getLength());
00116 result->setQuaternion(targetValue);
00117 setCompressedData(1, sizeof(Quaternion) + sizeof(float));
00118 return result;
00119 }
00120
00121
00122 RotationInterpolator* RotationInterpolationCompressor::compressLinear(
00123 QuaternionArrayInterpolator* source){
00124
00125
00126
00127 int sourceKeyCount = getSourceKeyCount();
00128 Deque<LinearKey> keys_(sourceKeyCount);
00129 for(int i = 0; i < sourceKeyCount; i++){
00130 LinearKey key;
00131 key.value_ = source->getValue(i);
00132 key.time_ = (float)i;
00133 keys_.pushBack(key);
00134 }
00135
00136
00137 int keyCount = keys_.getCount();
00138 int maxKeyCount = keyCount - 1;
00139
00140 keys_[0].errorCos_ = 1.f;
00141 keys_[maxKeyCount].errorCos_ = 1.f;
00142 Assert(keys_[0].time_ == 0.f)
00143 Assert(keys_[maxKeyCount].time_ == getLength());
00144 Assert(keys_[0].value_.dotProduct(keys_[1].value_) >= 0.f);
00145 for(int i = 1; i < maxKeyCount; i++){
00146 LinearKey& key = keys_[i];
00147 LinearKey& preKey = keys_[i - 1];
00148 LinearKey& postKey = keys_[i + 1];
00149 Assert(key.value_.dotProduct(postKey.value_) >= 0.f);
00150
00151 Quaternion value =
00152 Quaternion::slerp(preKey.value_, postKey.value_, 0.5f);
00153 key.errorCos_ = key.value_.dotProduct(value);
00154 }
00155
00156
00157 float toleranceCos = Math::cos(getTolerance());
00158 while(keys_.getCount() > 2){
00159
00160 int targetIndex = 0;
00161 float targetErrorCos = -1.f;
00162 maxKeyCount = keys_.getCount() - 1;
00163 for(int i = 1; i < maxKeyCount; i++){
00164
00165
00166
00167 if((keys_[i].errorCos_ > targetErrorCos) &&
00168 (keys_[i - 1].value_.dotProduct(keys_[i + 1].value_) >= 0.f)){
00169 targetErrorCos = keys_[i].errorCos_;
00170 targetIndex = i;
00171 }
00172 }
00173
00174
00175 if(targetIndex == 0){ break; }
00176
00177 if(targetErrorCos < toleranceCos){ break; }
00178
00179
00180 keys_.remove(targetIndex);
00181
00182 if((targetIndex - 1) > 0){
00183 recalcLinearError(source, keys_[targetIndex - 2],
00184 keys_[targetIndex - 1], keys_[targetIndex]);
00185 }
00186
00187 if(targetIndex < (keys_.getCount() - 1)){
00188 recalcLinearError(source, keys_[targetIndex - 1],
00189 keys_[targetIndex], keys_[targetIndex + 1]);
00190 }
00191 }
00192
00193
00194 keyCount = keys_.getCount();
00195 int keySize = sizeof(Quaternion) + sizeof(float);
00196 if((keyCount * keySize) >= getSourceSize()){ return NULL; }
00197
00198
00199 QuaternionLinearInterpolator* result = new QuaternionLinearInterpolator();
00200 result->setKeyCount(keyCount);
00201 for(int i = 0; i < keyCount; i++){
00202 LinearKey& key = keys_[i];
00203 result->setKey(i, key.time_, key.value_);
00204 }
00205 setCompressedData(keyCount, keySize);
00206 return result;
00207 }
00208
00209
00210 void RotationInterpolationCompressor::recalcLinearError(
00211 QuaternionArrayInterpolator* source,
00212 LinearKey& preKey, LinearKey& key, LinearKey& postKey){
00213 int preTime = (int)preKey.time_;
00214 Quaternion preValue = preKey.value_;
00215 int postTime = (int)postKey.time_;
00216 Quaternion postValue = postKey.value_;
00217 int timeRange = postTime - preTime;
00218
00219
00220 float maxErrorCos = 1.f;
00221 for(int i = 1; i < timeRange; i++){
00222 int time = preTime + i;
00223 Quaternion sourceValue = source->getValue(time);
00224 float rate = (float)i / (float)timeRange;
00225 Quaternion targetValue = Quaternion::slerp(preValue, postValue, rate);
00226 float errorCos = sourceValue.dotProduct(targetValue);
00227 if(errorCos < maxErrorCos){ maxErrorCos = errorCos; }
00228 }
00229 key.errorCos_ = maxErrorCos;
00230 }
00231
00232
00233
00234
00235 String RotationInterpolationCompressor::getResultString() const{
00236 String result;
00237 result.format(
00238 "%.2f%% Key %d/%d Size %.2f/%.2fKb Length %.0f",
00239 getCompressionRate() * 100.f,
00240 getCompressedKeyCount(), getSourceKeyCount(),
00241 (float)getCompressedSize() / 1024.f, (float)getSourceSize() / 1024.f,
00242 getLength());
00243 return result;
00244 }
00245
00246 }
00247