metaforce/DataSpec/DNACommon/ANIM.cpp

527 lines
17 KiB
C++
Raw Normal View History

2016-03-04 23:04:53 +00:00
#include "zeus/Math.hpp"
2015-08-11 23:32:02 +00:00
#include "ANIM.hpp"
#define DUMP_KEYS 0
2016-02-13 09:02:47 +00:00
namespace DataSpec
2015-08-11 23:32:02 +00:00
{
namespace DNAANIM
{
size_t ComputeBitstreamSize(size_t keyFrameCount, const std::vector<Channel>& channels)
{
size_t bitsPerKeyFrame = 0;
for (const Channel& chan : channels)
{
switch (chan.type)
{
2015-11-21 01:16:07 +00:00
case Channel::Type::Rotation:
2015-08-13 21:29:07 +00:00
bitsPerKeyFrame += 1;
2015-11-21 01:16:07 +00:00
case Channel::Type::Translation:
case Channel::Type::Scale:
2015-08-11 23:32:02 +00:00
bitsPerKeyFrame += chan.q[0];
bitsPerKeyFrame += chan.q[1];
bitsPerKeyFrame += chan.q[2];
break;
2015-11-21 01:16:07 +00:00
case Channel::Type::KfHead:
2015-09-26 03:12:08 +00:00
bitsPerKeyFrame += 1;
break;
2015-11-21 01:16:07 +00:00
case Channel::Type::RotationMP3:
2015-09-26 03:12:08 +00:00
bitsPerKeyFrame += chan.q[0];
bitsPerKeyFrame += chan.q[1];
bitsPerKeyFrame += chan.q[2];
bitsPerKeyFrame += chan.q[3];
break;
2015-08-11 23:32:02 +00:00
default: break;
}
}
return (bitsPerKeyFrame * keyFrameCount + 31) / 32 * 4;
}
static inline QuantizedRot QuantizeRotation(const Value& quat, atUint32 div)
{
2016-04-15 03:02:21 +00:00
float q = M_PIF / 2.0f / float(div);
2015-08-11 23:32:02 +00:00
return
{
{
atInt32(std::asin(quat.v4.vec[1]) / q),
atInt32(std::asin(quat.v4.vec[2]) / q),
atInt32(std::asin(quat.v4.vec[3]) / q),
2015-08-11 23:32:02 +00:00
},
2016-03-04 23:04:53 +00:00
(quat.v4.vec[0] < 0.f) ? true : false
2015-08-11 23:32:02 +00:00
};
}
2015-09-26 03:12:08 +00:00
2015-08-11 23:32:02 +00:00
static inline Value DequantizeRotation(const QuantizedRot& v, atUint32 div)
{
2016-04-15 03:02:21 +00:00
float q = M_PIF / 2.0f / float(div);
2015-08-11 23:32:02 +00:00
Value retval =
{
2016-03-04 23:04:53 +00:00
0.0f,
std::sin(v.v[0] * q),
std::sin(v.v[1] * q),
std::sin(v.v[2] * q),
2015-08-11 23:32:02 +00:00
};
2016-03-04 23:04:53 +00:00
retval.v4.vec[0] = std::sqrt(std::max((1.0f -
2015-08-13 21:29:07 +00:00
(retval.v4.vec[1] * retval.v4.vec[1] +
retval.v4.vec[2] * retval.v4.vec[2] +
2016-03-04 23:04:53 +00:00
retval.v4.vec[3] * retval.v4.vec[3])), 0.0f));
2015-08-13 21:29:07 +00:00
retval.v4.vec[0] = v.w ? -retval.v4.vec[0] : retval.v4.vec[0];
2015-08-11 23:32:02 +00:00
return retval;
}
2015-09-27 21:49:18 +00:00
static inline Value DequantizeRotation_3(const QuantizedRot& v, atUint32 div)
2015-09-26 03:12:08 +00:00
{
2016-03-04 23:04:53 +00:00
float q = 1.0f / float(div);
2015-09-26 03:12:08 +00:00
Value retval =
{
2016-03-04 23:04:53 +00:00
0.0f,
2015-09-26 03:12:08 +00:00
v.v[0] * q,
v.v[1] * q,
v.v[2] * q,
};
2016-03-04 23:04:53 +00:00
retval.v4.vec[0] = std::sqrt(std::max((1.0f -
2015-09-27 21:49:18 +00:00
(retval.v4.vec[1] * retval.v4.vec[1] +
retval.v4.vec[2] * retval.v4.vec[2] +
2016-03-04 23:04:53 +00:00
retval.v4.vec[3] * retval.v4.vec[3])), 0.0f));
2015-09-27 21:49:18 +00:00
retval.v4.vec[0] = v.w ? -retval.v4.vec[0] : retval.v4.vec[0];
2015-09-26 03:12:08 +00:00
return retval;
}
2015-08-13 21:29:07 +00:00
bool BitstreamReader::dequantizeBit(const atUint8* data)
{
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
2016-03-04 23:04:53 +00:00
atUint32 tempBuf = hecl::SBig(*reinterpret_cast<const atUint32*>(data + byteCur)) >> bitRem;
2015-08-13 21:29:07 +00:00
/* That's it */
m_bitCur += 1;
return tempBuf & 0x1;
}
atInt32 BitstreamReader::dequantize(const atUint8* data, atUint8 q)
2015-08-11 23:32:02 +00:00
{
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
2016-03-04 23:04:53 +00:00
atUint32 tempBuf = hecl::SBig(*reinterpret_cast<const atUint32*>(data + byteCur)) >> bitRem;
2015-08-11 23:32:02 +00:00
/* If this shift underflows the value, buffer the next 32 bits */
/* And tack onto shifted buffer */
if ((bitRem + q) > 32)
{
2016-03-04 23:04:53 +00:00
atUint32 tempBuf2 = hecl::SBig(*reinterpret_cast<const atUint32*>(data + byteCur + 4));
2015-08-11 23:32:02 +00:00
tempBuf |= (tempBuf2 << (32 - bitRem));
}
2015-09-27 02:24:03 +00:00
/* Mask it */
atUint32 mask = (1 << q) - 1;
tempBuf &= mask;
/* Sign extend */
2015-08-11 23:32:02 +00:00
atUint32 sign = (tempBuf >> (q - 1)) & 0x1;
if (sign)
2016-05-21 21:46:46 +00:00
tempBuf |= ~0u << q;
2015-08-11 23:32:02 +00:00
/* Return delta value */
m_bitCur += q;
2015-09-27 02:24:03 +00:00
return atInt32(tempBuf);
2015-08-11 23:32:02 +00:00
}
std::vector<std::vector<Value>>
BitstreamReader::read(const atUint8* data,
size_t keyFrameCount,
const std::vector<Channel>& channels,
atUint32 rotDiv,
float transMult,
float scaleMult)
2015-08-11 23:32:02 +00:00
{
m_bitCur = 0;
std::vector<std::vector<Value>> chanKeys;
std::vector<QuantizedValue> chanAccum;
chanKeys.reserve(channels.size());
chanAccum.reserve(channels.size());
for (const Channel& chan : channels)
{
2015-09-27 02:24:03 +00:00
chanAccum.push_back(chan.i);
2015-08-11 23:32:02 +00:00
chanKeys.emplace_back();
std::vector<Value>& keys = chanKeys.back();
keys.reserve(keyFrameCount);
switch (chan.type)
{
2015-11-21 01:16:07 +00:00
case Channel::Type::Rotation:
2015-08-11 23:32:02 +00:00
{
QuantizedRot qr = {{chan.i[0], chan.i[1], chan.i[2]}, false};
keys.emplace_back(DequantizeRotation(qr, rotDiv));
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::Translation:
2015-08-11 23:32:02 +00:00
{
keys.push_back({chan.i[0] * transMult, chan.i[1] * transMult, chan.i[2] * transMult});
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::Scale:
2015-08-11 23:32:02 +00:00
{
keys.push_back({chan.i[0] * scaleMult, chan.i[1] * scaleMult, chan.i[2] * scaleMult});
2015-08-11 23:32:02 +00:00
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::KfHead:
2015-09-26 03:12:08 +00:00
{
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::RotationMP3:
2015-09-26 03:12:08 +00:00
{
2015-09-27 02:24:03 +00:00
QuantizedRot qr = {{chan.i[1], chan.i[2], chan.i[3]}, bool(chan.i[0] & 0x1)};
2015-09-27 21:49:18 +00:00
keys.emplace_back(DequantizeRotation_3(qr, rotDiv));
2015-09-26 03:12:08 +00:00
break;
}
2015-08-11 23:32:02 +00:00
default: break;
}
}
2015-08-11 23:32:02 +00:00
for (size_t f=0 ; f<keyFrameCount ; ++f)
{
#if DUMP_KEYS
fprintf(stderr, "\nFRAME %" PRISize " %u %u\n", f, (m_bitCur / 32) * 4, m_bitCur % 32);
int lastId = -1;
#endif
2015-08-11 23:32:02 +00:00
auto kit = chanKeys.begin();
auto ait = chanAccum.begin();
for (const Channel& chan : channels)
{
#if DUMP_KEYS
if (chan.id != lastId)
{
lastId = chan.id;
fprintf(stderr, "\n");
}
#endif
2015-08-11 23:32:02 +00:00
QuantizedValue& p = *ait;
switch (chan.type)
{
2015-11-21 01:16:07 +00:00
case Channel::Type::Rotation:
2015-08-11 23:32:02 +00:00
{
2015-08-13 21:29:07 +00:00
bool wBit = dequantizeBit(data);
2015-08-11 23:32:02 +00:00
p[0] += dequantize(data, chan.q[0]);
p[1] += dequantize(data, chan.q[1]);
p[2] += dequantize(data, chan.q[2]);
QuantizedRot qr = {{p[0], p[1], p[2]}, wBit};
kit->emplace_back(DequantizeRotation(qr, rotDiv));
#if DUMP_KEYS
fprintf(stderr, "%d R: %d %d %d %d\t", chan.id, wBit, p[0], p[1], p[2]);
#endif
2015-08-11 23:32:02 +00:00
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::Translation:
2015-08-11 23:32:02 +00:00
{
atInt32 val1 = dequantize(data, chan.q[0]);
2015-09-27 02:24:03 +00:00
p[0] += val1;
atInt32 val2 = dequantize(data, chan.q[1]);
2015-09-27 02:24:03 +00:00
p[1] += val2;
atInt32 val3 = dequantize(data, chan.q[2]);
2015-09-27 02:24:03 +00:00
p[2] += val3;
2015-08-11 23:32:02 +00:00
kit->push_back({p[0] * transMult, p[1] * transMult, p[2] * transMult});
#if DUMP_KEYS
fprintf(stderr, "%d T: %d %d %d\t", chan.id, p[0], p[1], p[2]);
#endif
2015-08-11 23:32:02 +00:00
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::Scale:
2015-08-11 23:32:02 +00:00
{
p[0] += dequantize(data, chan.q[0]);
2015-08-15 04:12:15 +00:00
p[1] += dequantize(data, chan.q[1]);
p[2] += dequantize(data, chan.q[2]);
kit->push_back({p[0] * scaleMult, p[1] * scaleMult, p[2] * scaleMult});
#if DUMP_KEYS
fprintf(stderr, "%d S: %d %d %d\t", chan.id, p[0], p[1], p[2]);
#endif
2015-08-11 23:32:02 +00:00
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::KfHead:
2015-09-26 03:12:08 +00:00
{
bool aBit = dequantizeBit(data);
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::RotationMP3:
2015-09-26 03:12:08 +00:00
{
atInt32 val1 = dequantize(data, chan.q[0]);
2015-09-27 02:24:03 +00:00
p[0] += val1;
atInt32 val2 = dequantize(data, chan.q[1]);
2015-09-27 02:24:03 +00:00
p[1] += val2;
atInt32 val3 = dequantize(data, chan.q[2]);
2015-09-27 02:24:03 +00:00
p[2] += val3;
atInt32 val4 = dequantize(data, chan.q[3]);
2015-09-27 02:24:03 +00:00
p[3] += val4;
QuantizedRot qr = {{p[1], p[2], p[3]}, bool(p[0] & 0x1)};
2015-09-27 21:49:18 +00:00
kit->emplace_back(DequantizeRotation_3(qr, rotDiv));
2015-09-26 03:12:08 +00:00
break;
}
2015-08-11 23:32:02 +00:00
default: break;
}
++kit;
++ait;
}
#if DUMP_KEYS
fprintf(stderr, "\n");
#endif
2015-08-11 23:32:02 +00:00
}
2015-08-11 23:32:02 +00:00
return chanKeys;
}
2015-08-13 21:29:07 +00:00
void BitstreamWriter::quantizeBit(atUint8* data, bool val)
{
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
*(atUint32*)(data + byteCur) =
2016-03-04 23:04:53 +00:00
hecl::SBig(hecl::SBig(*(atUint32*)(data + byteCur)) | (val << bitRem));
2015-08-13 21:29:07 +00:00
m_bitCur += 1;
}
void BitstreamWriter::quantize(atUint8* data, atUint8 q, atInt32 val)
2015-08-11 23:32:02 +00:00
{
atUint32 byteCur = (m_bitCur / 32) * 4;
atUint32 bitRem = m_bitCur % 32;
atUint32 masked = val & ((1 << q) - 1);
/* Fill 32 bit buffer with region containing bits */
/* Make them least significant */
*(atUint32*)(data + byteCur) =
2016-03-04 23:04:53 +00:00
hecl::SBig(hecl::SBig(*(atUint32*)(data + byteCur)) | (masked << bitRem));
2015-08-11 23:32:02 +00:00
/* If this shift underflows the value, buffer the next 32 bits */
/* And tack onto shifted buffer */
if ((bitRem + q) > 32)
{
*(atUint32*)(data + byteCur + 4) =
2016-03-04 23:04:53 +00:00
hecl::SBig(hecl::SBig(*(atUint32*)(data + byteCur + 4)) | (masked >> (32 - bitRem)));
2015-08-11 23:32:02 +00:00
}
m_bitCur += q;
}
std::unique_ptr<atUint8[]>
BitstreamWriter::write(const std::vector<std::vector<Value>>& chanKeys,
size_t keyFrameCount, std::vector<Channel>& channels,
atUint32 quantRange,
2015-08-11 23:32:02 +00:00
atUint32& rotDivOut,
float& transMultOut,
float& scaleMultOut,
2015-08-11 23:32:02 +00:00
size_t& sizeOut)
{
m_bitCur = 0;
rotDivOut = quantRange; /* Normalized range of values */
float quantRangeF = float(quantRange);
2015-08-11 23:32:02 +00:00
/* Pre-pass to calculate translation multiplier */
2016-03-04 23:04:53 +00:00
float maxTransDiff = 0.0f;
float maxScaleDiff = 0.0f;
2015-08-11 23:32:02 +00:00
auto kit = chanKeys.begin();
for (Channel& chan : channels)
{
switch (chan.type)
{
2015-11-21 01:16:07 +00:00
case Channel::Type::Translation:
2015-08-11 23:32:02 +00:00
{
const Value* last = &(*kit)[0];
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
const Value* current = &*it;
2015-09-26 03:12:08 +00:00
maxTransDiff = std::max(maxTransDiff, current->v3.vec[0] - last->v3.vec[0]);
maxTransDiff = std::max(maxTransDiff, current->v3.vec[1] - last->v3.vec[1]);
maxTransDiff = std::max(maxTransDiff, current->v3.vec[2] - last->v3.vec[2]);
2015-08-11 23:32:02 +00:00
last = current;
}
break;
}
case Channel::Type::Scale:
{
const Value* last = &(*kit)[0];
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
const Value* current = &*it;
maxScaleDiff = std::max(maxScaleDiff, current->v3.vec[0] - last->v3.vec[0]);
maxScaleDiff = std::max(maxScaleDiff, current->v3.vec[1] - last->v3.vec[1]);
maxScaleDiff = std::max(maxScaleDiff, current->v3.vec[2] - last->v3.vec[2]);
last = current;
}
break;
}
2015-08-11 23:32:02 +00:00
default: break;
}
++kit;
}
transMultOut = maxTransDiff / quantRangeF;
scaleMultOut = maxScaleDiff / quantRangeF;
2015-08-11 23:32:02 +00:00
/* Output channel inits */
2016-08-29 00:28:53 +00:00
std::vector<QuantizedValue> initVals;
initVals.reserve(channels.size());
2015-08-11 23:32:02 +00:00
kit = chanKeys.begin();
for (Channel& chan : channels)
{
chan.q[0] = 1;
chan.q[1] = 1;
chan.q[2] = 1;
switch (chan.type)
{
2015-11-21 01:16:07 +00:00
case Channel::Type::Rotation:
2015-08-11 23:32:02 +00:00
{
QuantizedRot qr = QuantizeRotation((*kit)[0], rotDivOut);
chan.i = qr.v;
2016-08-29 00:28:53 +00:00
initVals.push_back(chan.i);
2015-08-11 23:32:02 +00:00
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::Translation:
2015-08-11 23:32:02 +00:00
{
chan.i = {atInt32((*kit)[0].v3.vec[0] / transMultOut),
atInt32((*kit)[0].v3.vec[1] / transMultOut),
atInt32((*kit)[0].v3.vec[2] / transMultOut)};
2016-08-29 00:28:53 +00:00
initVals.push_back(chan.i);
2015-08-11 23:32:02 +00:00
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::Scale:
2015-08-11 23:32:02 +00:00
{
chan.i = {atInt32((*kit)[0].v3.vec[0] / scaleMultOut),
atInt32((*kit)[0].v3.vec[1] / scaleMultOut),
atInt32((*kit)[0].v3.vec[2] / scaleMultOut)};
2016-08-29 00:28:53 +00:00
initVals.push_back(chan.i);
2015-08-11 23:32:02 +00:00
break;
}
default: break;
}
++kit;
}
/* Pre-pass to analyze quantization factors for channels */
2016-08-29 00:28:53 +00:00
std::vector<QuantizedValue> lastVals = initVals;
2015-08-11 23:32:02 +00:00
kit = chanKeys.begin();
2016-08-29 00:28:53 +00:00
auto vit = lastVals.begin();
2015-08-11 23:32:02 +00:00
for (Channel& chan : channels)
{
2016-08-29 00:28:53 +00:00
QuantizedValue& last = *vit++;
2015-08-11 23:32:02 +00:00
switch (chan.type)
{
2015-11-21 01:16:07 +00:00
case Channel::Type::Rotation:
2015-08-11 23:32:02 +00:00
{
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
QuantizedRot qrCur = QuantizeRotation(*it, rotDivOut);
2016-08-29 00:28:53 +00:00
chan.q[0] = std::max(chan.q[0], atUint8(ceilf(log2f(qrCur.v[0] - last.v[0]))));
chan.q[1] = std::max(chan.q[1], atUint8(ceilf(log2f(qrCur.v[1] - last.v[1]))));
chan.q[2] = std::max(chan.q[2], atUint8(ceilf(log2f(qrCur.v[2] - last.v[2]))));
last = qrCur.v;
2015-08-11 23:32:02 +00:00
}
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::Translation:
2015-08-11 23:32:02 +00:00
{
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
QuantizedValue cur = {atInt32(it->v3.vec[0] / transMultOut),
atInt32(it->v3.vec[1] / transMultOut),
atInt32(it->v3.vec[2] / transMultOut)};
2015-09-26 03:12:08 +00:00
chan.q[0] = std::max(chan.q[0], atUint8(ceilf(log2f(cur[0] - last[0]))));
chan.q[1] = std::max(chan.q[1], atUint8(ceilf(log2f(cur[1] - last[1]))));
chan.q[2] = std::max(chan.q[2], atUint8(ceilf(log2f(cur[2] - last[2]))));
2015-08-11 23:32:02 +00:00
last = cur;
}
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::Scale:
2015-08-11 23:32:02 +00:00
{
for (auto it=kit->begin() + 1;
it != kit->end();
++it)
{
QuantizedValue cur = {atInt32(it->v3.vec[0] / scaleMultOut),
atInt32(it->v3.vec[1] / scaleMultOut),
atInt32(it->v3.vec[2] / scaleMultOut)};
2015-09-26 03:12:08 +00:00
chan.q[0] = std::max(chan.q[0], atUint8(ceilf(log2f(cur[0] - last[0]))));
chan.q[1] = std::max(chan.q[1], atUint8(ceilf(log2f(cur[1] - last[1]))));
chan.q[2] = std::max(chan.q[2], atUint8(ceilf(log2f(cur[2] - last[2]))));
2015-08-11 23:32:02 +00:00
last = cur;
}
break;
}
default: break;
}
++kit;
}
/* Generate Bitstream */
sizeOut = ComputeBitstreamSize(keyFrameCount, channels);
std::unique_ptr<atUint8[]> newData(new atUint8[sizeOut]);
2016-08-29 00:28:53 +00:00
lastVals = initVals;
2015-08-11 23:32:02 +00:00
for (size_t f=0 ; f<keyFrameCount ; ++f)
{
kit = chanKeys.begin();
2016-08-29 00:28:53 +00:00
vit = lastVals.begin();
2015-08-11 23:32:02 +00:00
for (const Channel& chan : channels)
{
const Value& val = (*kit++)[f];
2016-08-29 00:28:53 +00:00
QuantizedValue& last = *vit++;
2015-08-11 23:32:02 +00:00
switch (chan.type)
{
2015-11-21 01:16:07 +00:00
case Channel::Type::Rotation:
2015-08-11 23:32:02 +00:00
{
2016-08-29 00:28:53 +00:00
QuantizedRot qrCur = QuantizeRotation(val, rotDivOut);
quantizeBit(newData.get(), qrCur.w);
quantize(newData.get(), chan.q[0], qrCur.v[0] - last.v[0]);
quantize(newData.get(), chan.q[1], qrCur.v[1] - last.v[1]);
quantize(newData.get(), chan.q[2], qrCur.v[2] - last.v[2]);
last = qrCur.v;
2015-08-11 23:32:02 +00:00
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::Translation:
2015-08-11 23:32:02 +00:00
{
2016-08-29 00:28:53 +00:00
QuantizedValue cur = {atInt32(val.v3.vec[0] / transMultOut),
atInt32(val.v3.vec[1] / transMultOut),
atInt32(val.v3.vec[2] / transMultOut)};
quantize(newData.get(), chan.q[0], cur[0] - last[0]);
quantize(newData.get(), chan.q[1], cur[1] - last[1]);
quantize(newData.get(), chan.q[2], cur[2] - last[2]);
last = cur;
2015-08-11 23:32:02 +00:00
break;
}
2015-11-21 01:16:07 +00:00
case Channel::Type::Scale:
2015-08-11 23:32:02 +00:00
{
2016-08-29 00:28:53 +00:00
QuantizedValue cur = {atInt32(val.v3.vec[0] / scaleMultOut),
atInt32(val.v3.vec[1] / scaleMultOut),
atInt32(val.v3.vec[2] / scaleMultOut)};
quantize(newData.get(), chan.q[0], cur[0] - last[0]);
quantize(newData.get(), chan.q[1], cur[1] - last[1]);
quantize(newData.get(), chan.q[2], cur[2] - last[2]);
last = cur;
2015-08-11 23:32:02 +00:00
break;
}
default: break;
}
}
}
return newData;
2015-08-11 23:32:02 +00:00
}
}
}