mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 21:59:17 +00:00
210 lines
4.1 KiB
C++
210 lines
4.1 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
// Based on eos' (I)RDFT code which is in turn
|
|
// Based upon the (I)DCT code in FFmpeg
|
|
// Copyright (c) 2009 Peter Ross <pross@xvid.org>
|
|
// Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
|
|
// Copyright (c) 2010 Vitor Sessak
|
|
|
|
#include "math/dct.h"
|
|
#include "math/rdft.h"
|
|
|
|
namespace Math {
|
|
|
|
DCT::DCT(int bits, TransformType trans) : _bits(bits), _cos(1 << (_bits + 2) ), _trans(trans), _rdft(nullptr) {
|
|
int n = 1 << _bits;
|
|
|
|
_tCos = _cos.getTable();
|
|
|
|
_csc2 = new float[n / 2];
|
|
|
|
_rdft = new RDFT(_bits, (_trans == DCT_III) ? RDFT::IDFT_C2R : RDFT::DFT_R2C);
|
|
|
|
for (int i = 0; i < (n / 2); i++)
|
|
_csc2[i] = 0.5 / sin((M_PI / (2 * n) * (2 * i + 1)));
|
|
}
|
|
|
|
DCT::~DCT() {
|
|
delete _rdft;
|
|
delete[] _csc2;
|
|
}
|
|
|
|
void DCT::calc(float *data) {
|
|
switch (_trans) {
|
|
case DCT_I:
|
|
calcDCTI(data);
|
|
break;
|
|
case DCT_II:
|
|
calcDCTII(data);
|
|
break;
|
|
case DCT_III:
|
|
calcDCTIII(data);
|
|
break;
|
|
case DST_I:
|
|
calcDSTI(data);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* sin((M_PI * x / (2*n)) */
|
|
#define SIN(n,x) (_tCos[(n) - (x)])
|
|
/* cos((M_PI * x / (2*n)) */
|
|
#define COS(n,x) (_tCos[x])
|
|
|
|
void DCT::calcDCTI(float *data) {
|
|
int n = 1 << _bits;
|
|
|
|
float next = -0.5f * (data[0] - data[n]);
|
|
|
|
for (int i = 0; i < (n / 2); i++) {
|
|
float tmp1 = data[i ];
|
|
float tmp2 = data[n - i];
|
|
|
|
float s = SIN(n, 2 * i);
|
|
float c = COS(n, 2 * i);
|
|
|
|
c *= tmp1 - tmp2;
|
|
s *= tmp1 - tmp2;
|
|
|
|
next += c;
|
|
|
|
tmp1 = (tmp1 + tmp2) * 0.5f;
|
|
|
|
data[i ] = tmp1 - s;
|
|
data[n - i] = tmp1 + s;
|
|
}
|
|
|
|
_rdft->calc(data);
|
|
|
|
data[n] = data[1];
|
|
data[1] = next;
|
|
|
|
for (int i = 3; i <= n; i += 2)
|
|
data[i] = data[i - 2] - data[i];
|
|
}
|
|
|
|
void DCT::calcDCTII(float *data) {
|
|
int n = 1 << _bits;
|
|
|
|
for (int i = 0; i < (n / 2); i++) {
|
|
float tmp1 = data[i ];
|
|
float tmp2 = data[n - i - 1];
|
|
|
|
float s = SIN(n, 2 * i + 1);
|
|
|
|
s *= tmp1 - tmp2;
|
|
|
|
tmp1 = (tmp1 + tmp2) * 0.5f;
|
|
|
|
data[i ] = tmp1 + s;
|
|
data[n - i - 1] = tmp1 - s;
|
|
}
|
|
|
|
_rdft->calc(data);
|
|
|
|
float next = data[1] * 0.5f;
|
|
|
|
data[1] *= -1;
|
|
|
|
for (int i = n - 2; i >= 0; i -= 2) {
|
|
float inr = data[i ];
|
|
float ini = data[i + 1];
|
|
|
|
float c = COS(n, i);
|
|
float s = SIN(n, i);
|
|
|
|
data[i ] = c * inr + s * ini;
|
|
data[i + 1] = next;
|
|
|
|
next += s * inr - c * ini;
|
|
}
|
|
}
|
|
|
|
void DCT::calcDCTIII(float *data) {
|
|
int n = 1 << _bits;
|
|
|
|
float next = data[n - 1];
|
|
float inv_n = 1.0f / n;
|
|
|
|
for (int i = n - 2; i >= 2; i -= 2) {
|
|
float val1 = data[i ];
|
|
float val2 = data[i - 1] - data[i + 1];
|
|
|
|
float c = COS(n, i);
|
|
float s = SIN(n, i);
|
|
|
|
data[i ] = c * val1 + s * val2;
|
|
data[i + 1] = s * val1 - c * val2;
|
|
}
|
|
|
|
data[1] = 2 * next;
|
|
|
|
_rdft->calc(data);
|
|
|
|
for (int i = 0; i < (n / 2); i++) {
|
|
float tmp1 = data[i ] * inv_n;
|
|
float tmp2 = data[n - i - 1] * inv_n;
|
|
|
|
float csc = _csc2[i] * (tmp1 - tmp2);
|
|
|
|
tmp1 += tmp2;
|
|
|
|
data[i ] = tmp1 + csc;
|
|
data[n - i - 1] = tmp1 - csc;
|
|
}
|
|
}
|
|
|
|
void DCT::calcDSTI(float *data) {
|
|
int n = 1 << _bits;
|
|
|
|
data[0] = 0;
|
|
|
|
for (int i = 1; i < (n / 2); i++) {
|
|
float tmp1 = data[i ];
|
|
float tmp2 = data[n - i];
|
|
float s = SIN(n, 2 * i);
|
|
|
|
s *= tmp1 + tmp2;
|
|
tmp1 = (tmp1 - tmp2) * 0.5f;
|
|
|
|
data[i ] = s + tmp1;
|
|
data[n - i] = s - tmp1;
|
|
}
|
|
|
|
data[n / 2] *= 2;
|
|
|
|
_rdft->calc(data);
|
|
|
|
data[0] *= 0.5f;
|
|
|
|
for (int i = 1; i < (n - 2); i += 2) {
|
|
data[i + 1] += data[i - 1];
|
|
data[i ] = -data[i + 2];
|
|
}
|
|
|
|
data[n - 1] = 0;
|
|
}
|
|
|
|
} // End of namespace Math
|