diff --git a/encode_dxa.cpp b/encode_dxa.cpp index e0ed2bb9..a3858fd2 100644 --- a/encode_dxa.cpp +++ b/encode_dxa.cpp @@ -60,6 +60,7 @@ class DxaEncoder { void m13blockDelta(byte *frame, int x, int y, int x2, int y2, DiffStruct &diff); bool m13motionVector(byte *frame, int x, int y, int w, int h, int &mx, int &my); int m13countColors(byte *block, byte *pixels, unsigned long &code, int &codeSize); + uLong m12encode(byte *frame, byte *outbuf); uLong m13encode(byte *frame, byte *outbuf); public: @@ -196,6 +197,57 @@ void DxaEncoder::writeFrame(byte *frame, byte *palette) { delete[] outbuf2; delete[] xorbuf; + break; + } + case 12: + { + uLong outsize1 = _width * _workheight; + uLong outsize2 = outsize1; + uLong outsize3 = outsize1*2; + uLong outsize4 = outsize1; + uLong outsize; + uint8 *outbuf; + uint8 *outbuf1 = new uint8[outsize1]; + uint8 *outbuf2 = new uint8[outsize2]; + uint8 *outbuf3 = new uint8[outsize3]; + uint8 *outbuf4 = new uint8[outsize4]; + uint8 *xorbuf = new uint8[_width * _workheight]; + + for (int i = 0; i < _width * _workheight; i++) + xorbuf[i] = _prevframe[i] ^ frame[i]; + + compress2(outbuf1, &outsize1, xorbuf, _width * _workheight, 9); + compress2(outbuf2, &outsize2, frame, _width * _workheight, 9); + if (outsize1 < outsize2) { + compType = 3; + outsize = outsize1; + outbuf = outbuf1; + } else { + compType = 2; + outsize = outsize2; + outbuf = outbuf2; + } + + outsize3 = m12encode(frame, outbuf3); + + compress2(outbuf4, &outsize4, outbuf3, outsize3, 9); + + if (outsize4 < outsize) { + compType = 12; + outsize = outsize4; + outbuf = outbuf4; + } + + _dxa.writeByte(compType); + _dxa.writeUint32BE(outsize); + _dxa.write(outbuf, outsize); + + delete[] outbuf1; + delete[] outbuf2; + delete[] outbuf3; + delete[] outbuf4; + delete[] xorbuf; + break; } case 13: @@ -382,6 +434,86 @@ void DxaEncoder::grabBlock(byte *frame, int x, int y, int blockw, int blockh, by } } +uLong DxaEncoder::m12encode(byte *frame, byte *outbuf) { + byte *outb = outbuf; + byte color; + int mx, my; + DiffStruct diff; + + for (int by = 0; by < _workheight; by += BLOCKH) { + for (int bx = 0; bx < _width; bx += BLOCKW) { + if (m13blocksAreEqual(frame, bx, by, bx, by, BLOCKW, BLOCKH)) { + *outb++ = 0; + continue; + } + + if (m13blockIsSolidColor(frame, bx, by, BLOCKW, BLOCKH, color)) { + *outb++ = 2; + *outb++ = color; + continue; + } + + if (m13motionVector(frame, bx, by, BLOCKW, BLOCKH, mx, my)) { + byte mbyte = 0; + if (mx < 0) mbyte |= 0x80; + mbyte |= (abs(mx) & 7) << 4; + if (my < 0) mbyte |= 0x08; + mbyte |= abs(my) & 7; + *outb++ = 4; + *outb++ = mbyte; + continue; + } + + m13blockDelta(frame, bx, by, bx, by, diff); + + if (diff.count >= 14) { + // in this case we store all 16 pixels + *outb++ = 3; + byte *b2 = (byte*)frame + bx + by * _width; + for (int yc = 0; yc < BLOCKH; yc++) { + memcpy(outb, b2, BLOCKW); + b2 += _width; + outb += BLOCKW; + } + continue; + } else { + static const struct { uint16 mask; uint8 sh1, sh2; } maskTbl[6] = { + {0xFF00, 0, 0}, + {0x0FF0, 8, 0}, + {0x00FF, 8, 8}, + {0x0F0F, 8, 4}, + {0xF0F0, 4, 0}, + {0xF00F, 4, 4} + }; + + bool smallMask = false; + + // here we check if the difference bitmap can be stored in only one byte + for (int m = 0; m < 6; m++) { + if ((diff.map & maskTbl[m].mask) == 0) { + smallMask = true; + *outb++ = 10 + m; + *outb++ = ((diff.map >> maskTbl[m].sh1) & 0xF0) | ((diff.map >> maskTbl[m].sh2) & 0x0F); + break; + } + } + + if (!smallMask) { + *outb++ = 1; + WRITE_BE_UINT16(outb, diff.map); + outb += 2; + } + + memcpy(outb, diff.pixels, diff.count); + outb += diff.count; + continue; + } + } + } + + return outb - outbuf; +} + uLong DxaEncoder::m13encode(byte *frame, byte *outbuf) { byte *codeB = _codeBuf;