aboutsummaryrefslogtreecommitdiff
path: root/common/dct.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'common/dct.cpp')
-rw-r--r--common/dct.cpp208
1 files changed, 208 insertions, 0 deletions
diff --git a/common/dct.cpp b/common/dct.cpp
new file mode 100644
index 0000000000..6525c727ae
--- /dev/null
+++ b/common/dct.cpp
@@ -0,0 +1,208 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+// 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 "common/cosinetables.h"
+#include "common/dct.h"
+
+namespace Common {
+
+DCT::DCT(int bits, TransformType trans) : _bits(bits), _trans(trans), _rdft(0) {
+ int n = 1 << _bits;
+
+ _tCos = getCosineTable(_bits + 2);
+
+ _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;
+ }
+}
+
+/* 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.5 * (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.5;
+
+ 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.5;
+
+ data[i ] = tmp1 + s;
+ data[n - i - 1] = tmp1 - s;
+ }
+
+ _rdft->calc(data);
+
+ float next = data[1] * 0.5;
+
+ 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.0 / 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.5;
+
+ data[i ] = s + tmp1;
+ data[n - i] = s - tmp1;
+ }
+
+ data[n / 2] *= 2;
+
+ _rdft->calc(data);
+
+ data[0] *= 0.5;
+
+ 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 Common