@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
214 lines (190 loc) • 6.48 kB
JavaScript
// IDCT constants (20.12 fixed point format)
const dctCos1 = 4017; // cos(pi/16)
const dctSin1 = 799; // sin(pi/16)
const dctCos3 = 3406; // cos(3*pi/16)
const dctSin3 = 2276; // sin(3*pi/16)
const dctCos6 = 1567; // cos(6*pi/16)
const dctSin6 = 3784; // sin(6*pi/16)
const dctSqrt2 = 5793; // sqrt(2)
const dctSqrt1d2 = 2896; // sqrt(2) / 2
/**
* Used internally for transformation
* @type {Int32Array}
*/
const p = new Int32Array(64);
/**
* Decode 8x8 block quantized DCT coefficients and inverse DCT transform.
* This is a fixed-point implementation of the IDCT algorithm.
*
* This IDCT algorithm is taken from:
* Y. A. Reznik, A. T. Hinds, L. Yu, Z. Ni, and C-X. Zhang,
* "Efficient fixed-point approximations of the 8x8 inverse discrete
* cosine transform" (invited paper), Proc. SPIE Vol. 6696, Sep. 24, 2007.
*
* which is based on:
* Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
* "Practical Fast 1-D DCT Algorithms with 11 Multiplications",
* IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
* 988-991.
*
* The stage numbers mentioned in the comments refer to Figure 1 in the Loeffler paper.
*
* @param {Int32Array} qt quantization table
* @param {Int32Array} zz zigzag-ordered coefficients
* @param {Uint8Array|Uint8ClampedArray} dataOut
*/
export function idct8x8_fixed(
qt,
zz,
dataOut,
) {
// TODO check https://github.com/ONLYOFFICE/core/blob/f6c835668482d70e59202394434314c8863fc1cf/PdfFile/lib/xpdf/Stream.cc#L3582
let v0, v1, v2, v3, v4, v5, v6, v7, t;
let i;
// dequant
for (i = 0; i < 64; i++) {
p[i] = zz[i] * qt[i];
}
// inverse DCT on rows
for (i = 0; i < 8; ++i) {
const row = 8 * i;
// check for all-zero AC coefficients
if (p[1 + row] === 0
&& p[2 + row] === 0
&& p[3 + row] === 0
&& p[4 + row] === 0
&& p[5 + row] === 0
&& p[6 + row] === 0
&& p[7 + row] === 0
) {
t = (dctSqrt2 * p[0 + row] + 512) >> 10;
p[0 + row] = t;
p[1 + row] = t;
p[2 + row] = t;
p[3 + row] = t;
p[4 + row] = t;
p[5 + row] = t;
p[6 + row] = t;
p[7 + row] = t;
continue;
}
// stage 4
v0 = (dctSqrt2 * p[0 + row] + 128) >> 8;
v1 = (dctSqrt2 * p[4 + row] + 128) >> 8;
v2 = p[2 + row];
v3 = p[6 + row];
v4 = (dctSqrt1d2 * (p[1 + row] - p[7 + row]) + 128) >> 8;
v7 = (dctSqrt1d2 * (p[1 + row] + p[7 + row]) + 128) >> 8;
v5 = p[3 + row] << 4;
v6 = p[5 + row] << 4;
// stage 3
t = (v0 - v1 + 1) >> 1;
v0 = (v0 + v1 + 1) >> 1;
v1 = t;
t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
v3 = t;
t = (v4 - v6 + 1) >> 1;
v4 = (v4 + v6 + 1) >> 1;
v6 = t;
t = (v7 + v5 + 1) >> 1;
v5 = (v7 - v5 + 1) >> 1;
v7 = t;
// stage 2
t = (v0 - v3 + 1) >> 1;
v0 = (v0 + v3 + 1) >> 1;
v3 = t;
t = (v1 - v2 + 1) >> 1;
v1 = (v1 + v2 + 1) >> 1;
v2 = t;
t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
v7 = t;
t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
v6 = t;
// stage 1
p[0 + row] = v0 + v7;
p[7 + row] = v0 - v7;
p[1 + row] = v1 + v6;
p[6 + row] = v1 - v6;
p[2 + row] = v2 + v5;
p[5 + row] = v2 - v5;
p[3 + row] = v3 + v4;
p[4 + row] = v3 - v4;
}
// inverse DCT on columns
for (i = 0; i < 8; ++i) {
const col = i;
// check for all-zero AC coefficients
if (p[1 * 8 + col] === 0
&& p[2 * 8 + col] === 0
&& p[3 * 8 + col] === 0
&& p[4 * 8 + col] === 0
&& p[5 * 8 + col] === 0
&& p[6 * 8 + col] === 0
&& p[7 * 8 + col] === 0
) {
t = (dctSqrt2 * p[i + 0] + 8192) >> 14;
p[0 * 8 + col] = t;
p[1 * 8 + col] = t;
p[2 * 8 + col] = t;
p[3 * 8 + col] = t;
p[4 * 8 + col] = t;
p[5 * 8 + col] = t;
p[6 * 8 + col] = t;
p[7 * 8 + col] = t;
continue;
}
// stage 4
v0 = (dctSqrt2 * p[0 * 8 + col] + 2048) >> 12;
v1 = (dctSqrt2 * p[4 * 8 + col] + 2048) >> 12;
v2 = p[2 * 8 + col];
v3 = p[6 * 8 + col];
v4 = (dctSqrt1d2 * (p[1 * 8 + col] - p[7 * 8 + col]) + 2048) >> 12;
v7 = (dctSqrt1d2 * (p[1 * 8 + col] + p[7 * 8 + col]) + 2048) >> 12;
v5 = p[3 * 8 + col];
v6 = p[5 * 8 + col];
// stage 3
t = (v0 - v1 + 1) >> 1;
v0 = (v0 + v1 + 1) >> 1;
v1 = t;
t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
v3 = t;
t = (v4 - v6 + 1) >> 1;
v4 = (v4 + v6 + 1) >> 1;
v6 = t;
t = (v7 + v5 + 1) >> 1;
v5 = (v7 - v5 + 1) >> 1;
v7 = t;
// stage 2
t = (v0 - v3 + 1) >> 1;
v0 = (v0 + v3 + 1) >> 1;
v3 = t;
t = (v1 - v2 + 1) >> 1;
v1 = (v1 + v2 + 1) >> 1;
v2 = t;
t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
v7 = t;
t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
v6 = t;
// stage 1
p[0 * 8 + col] = v0 + v7;
p[7 * 8 + col] = v0 - v7;
p[1 * 8 + col] = v1 + v6;
p[6 * 8 + col] = v1 - v6;
p[2 * 8 + col] = v2 + v5;
p[5 * 8 + col] = v2 - v5;
p[3 * 8 + col] = v3 + v4;
p[4 * 8 + col] = v3 - v4;
}
// convert to 8-bit integers
for (i = 0; i < 64; ++i) {
const q = p[i];
// clip to 8-bit range
dataOut[i] = (q <= -2056) ? 0 : (q >= 2024) ? 255 : (q + 2056) >> 4;
}
}