You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2622 lines
131 KiB
2622 lines
131 KiB
/****************************************************************************/
|
|
/* abcapi.cpp */
|
|
/* */
|
|
/* Bitmap Compressor API functions. */
|
|
/* */
|
|
/* Copyright(c) Microsoft, PictureTel 1992-1997 */
|
|
/* Copyright(c) Microsoft 1997-1999 */
|
|
/****************************************************************************/
|
|
|
|
#ifdef DLL_DISP
|
|
|
|
#include <adcg.h>
|
|
#include <adcs.h>
|
|
#include <abcapi.h>
|
|
#include <abcdata.c>
|
|
|
|
#define _pShm pddShm
|
|
|
|
#else
|
|
|
|
#include <as_conf.hpp>
|
|
|
|
#define _pShm m_pShm
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef COMP_STATS
|
|
/****************************************************************************/
|
|
/* Define some globals for storing useful stats data. */
|
|
/****************************************************************************/
|
|
UINT32 ulPreCompData = 0;
|
|
UINT32 ulTotalCompTime = 0;
|
|
UINT32 ulCompRate = 0;
|
|
#endif
|
|
|
|
#ifdef DC_DEBUG
|
|
// compression testing
|
|
#include <abdapi.h>
|
|
#endif
|
|
|
|
#ifdef Unused
|
|
// Restore this instead of macro if data added to abcdata.c
|
|
/****************************************************************************/
|
|
/* API FUNCTION: BC_Init */
|
|
/* */
|
|
/* Initializes the Bitmap Compressor. */
|
|
/****************************************************************************/
|
|
void RDPCALL SHCLASS BC_Init(void)
|
|
{
|
|
DC_BEGIN_FN("BC_Init");
|
|
|
|
#define DC_INIT_DATA
|
|
#include <abcdata.c>
|
|
#undef DC_INIT_DATA
|
|
|
|
DC_END_FN();
|
|
}
|
|
#endif
|
|
|
|
|
|
/****************************************************************************/
|
|
/* API FUNCTION: BC_CompressBitmap */
|
|
/* */
|
|
/* Compresses the supplied bitmap into the supplied memory buffer. */
|
|
/* */
|
|
/* PARAMETERS: */
|
|
/* */
|
|
/* pSrcBitmap - a pointer to the source bitmap data bits. */
|
|
/* */
|
|
/* pDstBuffer - a pointer to the destination memory buffer (where the */
|
|
/* compressed data will be written). */
|
|
/* */
|
|
/* dstBufferSize - the size in bytes of the destination buffer */
|
|
/* */
|
|
/* pCompressedDataSize - pointer to variable that receives the compressed */
|
|
/* data size */
|
|
/* */
|
|
/* bitmapWidth - width of the src bitmap in pels, should be divisible by 4. */
|
|
/* */
|
|
/* bitmapHeight - the height of the source bitmap in pels. */
|
|
/* */
|
|
/* RETURNS: */
|
|
/* */
|
|
/* TRUE - the bitmap data was successfully compressed. */
|
|
/* *pCompressedDataSize is updated */
|
|
/* */
|
|
/* FALSE - the bitmap data could not be compressed. */
|
|
/****************************************************************************/
|
|
#ifdef DC_HICOLOR
|
|
BOOL RDPCALL SHCLASS BC_CompressBitmap(
|
|
PBYTE pSrcBitmap,
|
|
PBYTE pDstBuffer,
|
|
PBYTE pBCWorkingBuffer,
|
|
unsigned dstBufferSize,
|
|
unsigned *pCompressedDataSize,
|
|
unsigned bitmapWidth,
|
|
unsigned bitmapHeight,
|
|
unsigned bpp)
|
|
#else
|
|
BOOL RDPCALL SHCLASS BC_CompressBitmap(
|
|
PBYTE pSrcBitmap,
|
|
PBYTE pDstBuffer,
|
|
unsigned dstBufferSize,
|
|
unsigned *pCompressedDataSize,
|
|
unsigned bitmapWidth,
|
|
unsigned bitmapHeight)
|
|
#endif
|
|
{
|
|
BOOL rc;
|
|
PTS_CD_HEADER_UA pCompDataHeader;
|
|
unsigned cbUncompressedDataSize;
|
|
unsigned cbCompMainBodySize;
|
|
|
|
#ifdef COMP_STATS
|
|
UINT32 ulStartCompTime;
|
|
UINT32 ulEndCompTime;
|
|
#endif
|
|
|
|
DC_BEGIN_FN("BC_CompressBitmap");
|
|
|
|
#ifdef COMP_STATS
|
|
/************************************************************************/
|
|
/* Record the start time. */
|
|
/************************************************************************/
|
|
COM_GETTICKCOUNT(ulStartCompTime);
|
|
#endif
|
|
|
|
TRC_ASSERT(((bitmapWidth & 3) == 0),(TB,"Width not divisible by 4"));
|
|
TRC_ASSERT((dstBufferSize > 0),(TB,"No destination space!"));
|
|
|
|
// Trace the important parameters.
|
|
TRC_DBG((TB, "pSrc(%p) pDst(%p) dstBufferSize(%#x)",
|
|
pSrcBitmap, pDstBuffer, dstBufferSize));
|
|
TRC_DBG((TB, "width(%u) height(%u)", bitmapWidth, bitmapHeight));
|
|
|
|
// Calculate the size of the uncompressed src data. Make sure it
|
|
// is within our allowed size.
|
|
#ifdef DC_HICOLOR
|
|
cbUncompressedDataSize = bitmapWidth * bitmapHeight * ((bpp + 7) / 8);
|
|
#else
|
|
cbUncompressedDataSize = bitmapWidth * bitmapHeight;
|
|
#endif
|
|
TRC_ASSERT((cbUncompressedDataSize <= MAX_UNCOMPRESSED_DATA_SIZE || pBCWorkingBuffer),
|
|
(TB,"Bitmap size > max: size=%u, max=%u",
|
|
cbUncompressedDataSize, MAX_UNCOMPRESSED_DATA_SIZE));
|
|
|
|
// Do we send the bitmap compression header?
|
|
if (_pShm->bc.noBitmapCompressionHdr)
|
|
{
|
|
#ifdef DC_HICOLOR
|
|
switch (bpp)
|
|
{
|
|
case 32:
|
|
{
|
|
TRC_DBG((TB, "Compress 32 bpp"));
|
|
cbCompMainBodySize = CompressV2Int32(pSrcBitmap,
|
|
pDstBuffer,
|
|
cbUncompressedDataSize,
|
|
bitmapWidth * 4,
|
|
dstBufferSize,
|
|
pBCWorkingBuffer ? pBCWorkingBuffer :
|
|
_pShm->bc.xor_buffer,
|
|
_pShm->bc.match);
|
|
}
|
|
break;
|
|
|
|
case 24:
|
|
{
|
|
TRC_DBG((TB, "Compress 24 bpp"));
|
|
cbCompMainBodySize = CompressV2Int24(pSrcBitmap,
|
|
pDstBuffer,
|
|
cbUncompressedDataSize,
|
|
bitmapWidth * 3,
|
|
dstBufferSize,
|
|
pBCWorkingBuffer ? pBCWorkingBuffer :
|
|
_pShm->bc.xor_buffer,
|
|
_pShm->bc.match);
|
|
}
|
|
break;
|
|
|
|
case 16:
|
|
{
|
|
TRC_DBG((TB, "Compress 16bpp"));
|
|
cbCompMainBodySize = CompressV2Int16(pSrcBitmap,
|
|
pDstBuffer,
|
|
cbUncompressedDataSize,
|
|
bitmapWidth * 2,
|
|
dstBufferSize,
|
|
pBCWorkingBuffer ? pBCWorkingBuffer :
|
|
_pShm->bc.xor_buffer,
|
|
_pShm->bc.match);
|
|
}
|
|
break;
|
|
|
|
case 15:
|
|
{
|
|
TRC_DBG((TB, "Compress 15bpp"));
|
|
cbCompMainBodySize = CompressV2Int15(pSrcBitmap,
|
|
pDstBuffer,
|
|
cbUncompressedDataSize,
|
|
bitmapWidth * 2,
|
|
dstBufferSize,
|
|
pBCWorkingBuffer ? pBCWorkingBuffer :
|
|
_pShm->bc.xor_buffer,
|
|
_pShm->bc.match);
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
default:
|
|
{
|
|
TRC_DBG((TB, "Compress 8bpp"));
|
|
cbCompMainBodySize = CompressV2Int(pSrcBitmap,
|
|
pDstBuffer,
|
|
cbUncompressedDataSize,
|
|
bitmapWidth,
|
|
dstBufferSize,
|
|
pBCWorkingBuffer ? pBCWorkingBuffer :
|
|
_pShm->bc.xor_buffer);
|
|
}
|
|
break;
|
|
}
|
|
#else
|
|
cbCompMainBodySize = CompressV2Int(pSrcBitmap,
|
|
pDstBuffer,
|
|
cbUncompressedDataSize,
|
|
bitmapWidth,
|
|
dstBufferSize,
|
|
_pShm->bc.xor_buffer);
|
|
#endif
|
|
if (cbCompMainBodySize != 0) {
|
|
// Write back the new (compressed) packet size.
|
|
*pCompressedDataSize = cbCompMainBodySize;
|
|
|
|
TRC_DBG((TB, "*pCompressedDataSize(%u)",
|
|
*pCompressedDataSize));
|
|
rc = TRUE;
|
|
}
|
|
else {
|
|
TRC_NRM((TB, "Failed to compress main body"));
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
if (dstBufferSize > sizeof(TS_CD_HEADER)) {
|
|
// Compress the bitmap data.
|
|
#ifdef DC_HICOLOR
|
|
switch (bpp)
|
|
{
|
|
case 32:
|
|
{
|
|
TRC_DBG((TB, "Compress 32 bpp"));
|
|
cbCompMainBodySize = CompressV2Int32(pSrcBitmap,
|
|
pDstBuffer + sizeof(TS_CD_HEADER),
|
|
cbUncompressedDataSize,
|
|
bitmapWidth * 4,
|
|
dstBufferSize - sizeof(TS_CD_HEADER),
|
|
pBCWorkingBuffer ? pBCWorkingBuffer :
|
|
_pShm->bc.xor_buffer,
|
|
_pShm->bc.match);
|
|
}
|
|
break;
|
|
|
|
case 24:
|
|
{
|
|
TRC_DBG((TB, "Compress 24 bpp"));
|
|
cbCompMainBodySize = CompressV2Int24(pSrcBitmap,
|
|
pDstBuffer + sizeof(TS_CD_HEADER),
|
|
cbUncompressedDataSize,
|
|
bitmapWidth * 3,
|
|
dstBufferSize - sizeof(TS_CD_HEADER),
|
|
pBCWorkingBuffer ? pBCWorkingBuffer :
|
|
_pShm->bc.xor_buffer,
|
|
_pShm->bc.match);
|
|
}
|
|
break;
|
|
|
|
case 16:
|
|
{
|
|
TRC_DBG((TB, "Compress 16bpp"));
|
|
cbCompMainBodySize = CompressV2Int16(pSrcBitmap,
|
|
pDstBuffer + sizeof(TS_CD_HEADER),
|
|
cbUncompressedDataSize,
|
|
bitmapWidth * 2,
|
|
dstBufferSize - sizeof(TS_CD_HEADER),
|
|
pBCWorkingBuffer ? pBCWorkingBuffer :
|
|
_pShm->bc.xor_buffer,
|
|
_pShm->bc.match);
|
|
}
|
|
break;
|
|
|
|
case 15:
|
|
{
|
|
TRC_DBG((TB, "Compress 15bpp"));
|
|
cbCompMainBodySize = CompressV2Int15(pSrcBitmap,
|
|
pDstBuffer + sizeof(TS_CD_HEADER),
|
|
cbUncompressedDataSize,
|
|
bitmapWidth * 2,
|
|
dstBufferSize - sizeof(TS_CD_HEADER),
|
|
pBCWorkingBuffer ? pBCWorkingBuffer :
|
|
_pShm->bc.xor_buffer,
|
|
_pShm->bc.match);
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
default:
|
|
{
|
|
TRC_DBG((TB, "Compress 8bpp"));
|
|
cbCompMainBodySize = CompressV2Int(pSrcBitmap,
|
|
pDstBuffer + sizeof(TS_CD_HEADER),
|
|
cbUncompressedDataSize,
|
|
bitmapWidth,
|
|
dstBufferSize - sizeof(TS_CD_HEADER),
|
|
pBCWorkingBuffer ? pBCWorkingBuffer :
|
|
_pShm->bc.xor_buffer);
|
|
}
|
|
break;
|
|
}
|
|
#else
|
|
cbCompMainBodySize = CompressV2Int(pSrcBitmap,
|
|
pDstBuffer + sizeof(TS_CD_HEADER),
|
|
cbUncompressedDataSize,
|
|
bitmapWidth,
|
|
dstBufferSize - sizeof(TS_CD_HEADER),
|
|
_pShm->bc.xor_buffer);
|
|
#endif
|
|
if (cbCompMainBodySize != 0) {
|
|
// Fill in the compressed data header.
|
|
// FirstRowSize is 0 by historical convention.
|
|
pCompDataHeader = (PTS_CD_HEADER_UA)pDstBuffer;
|
|
pCompDataHeader->cbCompFirstRowSize = 0;
|
|
pCompDataHeader->cbCompMainBodySize =
|
|
(UINT16)cbCompMainBodySize;
|
|
|
|
if (bpp > 8) {
|
|
pCompDataHeader->cbScanWidth = TS_BYTES_IN_SCANLINE(bitmapWidth, bpp);
|
|
}
|
|
else {
|
|
pCompDataHeader->cbScanWidth = (UINT16)bitmapWidth;
|
|
}
|
|
|
|
pCompDataHeader->cbUncompressedSize =
|
|
(UINT16)cbUncompressedDataSize;
|
|
|
|
// Write back the new (compressed) packet size.
|
|
*pCompressedDataSize = sizeof(TS_CD_HEADER) +
|
|
cbCompMainBodySize;
|
|
|
|
TRC_DBG((TB, "*pCompressedDataSize(%u)",
|
|
*pCompressedDataSize));
|
|
rc = TRUE;
|
|
}
|
|
else {
|
|
TRC_NRM((TB, "Failed to compress main body"));
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
TRC_NRM((TB, "Not enough buffer space for header: %u",
|
|
dstBufferSize));
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
/************************************************************************/
|
|
/* Check that the compressed output decompresses to the same thing */
|
|
/************************************************************************/
|
|
if (cbCompMainBodySize)
|
|
{
|
|
HRESULT hr;
|
|
hr = BD_DecompressBitmap(
|
|
#ifndef DLL_DISP
|
|
m_pTSWd,
|
|
#endif
|
|
pDstBuffer + (_pShm->bc.noBitmapCompressionHdr ? 0 : 8),
|
|
_pShm->bc.decompBuffer,
|
|
cbCompMainBodySize,
|
|
TRUE,
|
|
(BYTE)bpp,
|
|
(UINT16)bitmapWidth,
|
|
(UINT16)bitmapHeight);
|
|
|
|
if (FAILED(hr) || memcmp(pSrcBitmap, _pShm->bc.decompBuffer,cbUncompressedDataSize))
|
|
{
|
|
// TRC_ASSERT(FALSE, (TB, "Decompression failure"));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef COMP_STATS
|
|
/************************************************************************/
|
|
/* Work out how long the compression took, in ms. */
|
|
/************************************************************************/
|
|
COM_GETTICKCOUNT(ulEndCompTime);
|
|
ulTotalCompTime += (ulEndCompTime - ulStartCompTime) / 10000;
|
|
if (ulTotalCompTime != 0)
|
|
ulCompRate = ulPreCompData / ulTotalCompTime;
|
|
#endif
|
|
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Bitmap Compression core code. */
|
|
/* */
|
|
/* A cunning multidimensional RLE compression scheme, particularly suitable */
|
|
/* for compressing bitmaps containing captured images of Windows */
|
|
/* applications. For images which use lots of different colors intermixed */
|
|
/* (full-color pictures, etc.) this compression sceme will be inefficient. */
|
|
/* */
|
|
/* These functions and macros encode a bitmap according to the codes */
|
|
/* defined in abcapi.h. Although there are some complexities in the */
|
|
/* encoding, the encodings should be self-explanatory. abcapi.h describes */
|
|
/* some nuances of the encoding scheme. */
|
|
/****************************************************************************/
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Utility macros for encoding orders */
|
|
/****************************************************************************/
|
|
|
|
/****************************************************************************/
|
|
/* Encode an order for a standard run */
|
|
/****************************************************************************/
|
|
#define ENCODE_ORDER_MEGA(buffer, \
|
|
order_code, \
|
|
length, \
|
|
mega_order_code, \
|
|
DEF_LENGTH_ORDER, \
|
|
DEF_LENGTH_LONG_ORDER) \
|
|
if (length <= DEF_LENGTH_ORDER) { \
|
|
*buffer++ = (BYTE)((BYTE)order_code | (BYTE)length); \
|
|
} \
|
|
else if (length <= DEF_LENGTH_LONG_ORDER) { \
|
|
*buffer++ = (BYTE)order_code; \
|
|
*buffer++ = (BYTE)(length - DEF_LENGTH_ORDER - 1); \
|
|
} \
|
|
else { \
|
|
*buffer++ = (BYTE)mega_order_code; \
|
|
*(PUINT16_UA)(buffer) = (UINT16)length; \
|
|
buffer += 2; \
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Encode a special FGBG image */
|
|
/****************************************************************************/
|
|
#define ENCODE_ORDER_MEGA_FGBG(buffer, \
|
|
order_code, \
|
|
length, \
|
|
mega_order_code, \
|
|
DEF_LENGTH_ORDER, \
|
|
DEF_LENGTH_LONG_ORDER) \
|
|
if ((length & 0x0007) == 0 && length <= DEF_LENGTH_ORDER) { \
|
|
*buffer++ = (BYTE)((BYTE)order_code | (BYTE)(length / 8)); \
|
|
} \
|
|
else if (length <= DEF_LENGTH_LONG_ORDER) { \
|
|
*buffer++ = (BYTE)order_code; \
|
|
*buffer++ = (BYTE)(length-1); \
|
|
} \
|
|
else { \
|
|
*buffer++ = (BYTE)mega_order_code; \
|
|
*(PUINT16_UA)(buffer) = (UINT16)length; \
|
|
buffer += 2; \
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* RunSingle */
|
|
/* */
|
|
/* Determine the length of the current run */
|
|
/* */
|
|
/* RunSingle may only be called if the buffer has at least four */
|
|
/* consecutive identical bytes from the start position */
|
|
/****************************************************************************/
|
|
#define RUNSINGLE(buffer, length, result) \
|
|
{ \
|
|
BYTE *buf = buffer + 4; \
|
|
BYTE *endbuf = buffer + length - 4; \
|
|
while (buf < endbuf && \
|
|
(*(PUINT32_UA)(buf) == *(PUINT32_UA)(buf - 4))) \
|
|
buf += 4; \
|
|
endbuf += 4; \
|
|
while (buf < endbuf && *buf == *(buf - 1)) \
|
|
buf++; \
|
|
result = (unsigned)(buf - (buffer)); \
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// RunDouble
|
|
//
|
|
// Determine the length of the current run of dithered bytes. Assumes that
|
|
// the dither pattern resides in the first 2 bytes of buffer.
|
|
/****************************************************************************/
|
|
#define RunDouble(buffer, length, result) \
|
|
{ \
|
|
int len = ((int)length) - 2; \
|
|
BYTE *buf = (buffer) + 2; \
|
|
UINT16 Pattern = *(PUINT16_UA)(buffer); \
|
|
result = 2; \
|
|
while (len > 1) { \
|
|
if (*(PUINT16_UA)buf != Pattern) \
|
|
break; \
|
|
buf += 2; \
|
|
result += 2; \
|
|
len -= 2; \
|
|
} \
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// RUNFGBG
|
|
//
|
|
// Determine the length of the run of bytes that consist only of black (0x00)
|
|
// or a single FG color. We exit the loop when
|
|
// - the next character is not a fg or bg color
|
|
// - we hit a run of 24 of the FG or BG color
|
|
// Example compression calculations:
|
|
// Lookahead KBytes* Comp CPU ("hits")
|
|
// 24 54846 148497
|
|
// 20 54885 151827
|
|
// 16 54967 156809
|
|
// * = KBytes server->client WinBench98 Graphics WinMark minus CorelDRAW,
|
|
// measured in NetMon on Ethernet.
|
|
/****************************************************************************/
|
|
#define RUNFGBG(buffer, length, result, work) \
|
|
{ \
|
|
BYTE *buf = buffer; \
|
|
BYTE *endbuf = buffer + length; \
|
|
result = 0; \
|
|
work = *buf; \
|
|
while (TRUE) { \
|
|
buf++; \
|
|
result++; \
|
|
if (buf < endbuf) { \
|
|
if (*buf != work && *buf != 0) \
|
|
break; \
|
|
\
|
|
if ((result & 0x0007) == 0) { \
|
|
if ((*buf == *(buf + 1)) && \
|
|
(*(PUINT16_UA)(buf) == *(PUINT16_UA)(buf + 2)) && \
|
|
(*(PUINT32_UA)(buf) == *(PUINT32_UA)(buf + 4)) && \
|
|
(*(PUINT32_UA)(buf) == *(PUINT32_UA)(buf + 8)) && \
|
|
(*(PUINT32_UA)(buf) == *(PUINT32_UA)(buf + 12)) && \
|
|
(*(PUINT32_UA)(buf) == *(PUINT32_UA)(buf + 16)) && \
|
|
(*(PUINT32_UA)(buf) == *(PUINT32_UA)(buf + 20))) \
|
|
{ \
|
|
break; \
|
|
} \
|
|
} \
|
|
} \
|
|
else { \
|
|
break; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// Determine whether a run is better than any previous run.
|
|
// For efficiency we take the run if over a threshold. Threshold comparisons:
|
|
// Threshold KBytes* Comp CPU ("hits")
|
|
// 32 54846 148497
|
|
// 28 54817 145085
|
|
// 24 54825 144366
|
|
// 20 54852 143662
|
|
// 16 54858 146343
|
|
// * = KBytes server->client WinBench98 Graphics WinMark minus CorelDRAW,
|
|
// measured in NetMon on Ethernet.
|
|
/****************************************************************************/
|
|
#define CHECK_BEST_RUN(run_type, run_length, bestrun_length, bestrun_type) \
|
|
if (run_length > bestrun_length) { \
|
|
bestrun_length = run_length; \
|
|
bestrun_type = run_type; \
|
|
if (bestrun_length >= 20) \
|
|
break; \
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* SETFGCHAR */
|
|
/* */
|
|
/* Set up a new value in fgChar and recalculate the shift */
|
|
/****************************************************************************/
|
|
#define SETFGCHAR(newchar, curchar, curshift) \
|
|
curchar = newchar; \
|
|
{ \
|
|
BYTE workchar = curchar; \
|
|
curshift = 0; \
|
|
while ((workchar & 0x01) == 0) { \
|
|
curshift++; \
|
|
workchar = (BYTE)(workchar >> 1); \
|
|
} \
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* ENCODEFGBG */
|
|
/* */
|
|
/* Encode 8 bytes of FG and black into a one byte bitmap representation */
|
|
/* */
|
|
/* The FgChar will always be non-zero, and therefore must have at least one */
|
|
/* bit set. */
|
|
/* */
|
|
/* We arrange that all bytes have this bit in their lowest position */
|
|
/* The zero pels will still have a 0 in the lowest bit. */
|
|
/* */
|
|
/* Getting the result is a 4 stage process */
|
|
/* */
|
|
/* 1) Get the wanted bits into bit 0 of each byte */
|
|
/* */
|
|
/* <***************work1*****************> */
|
|
/* 31 0 */
|
|
/* 0000 000d 0000 000c 0000 000b 0000 000a */
|
|
/* ^ ^ ^ ^ */
|
|
/* <***************work2*****************> */
|
|
/* 31 0 */
|
|
/* 0000 000h 0000 000g 0000 000f 0000 000e */
|
|
/* ^ ^ ^ ^ */
|
|
/* */
|
|
/* a..h = bits that we want to output */
|
|
/* */
|
|
/* We just need to collect the indicated bits and squash them into a single */
|
|
/* byte. */
|
|
/* */
|
|
/* 2) Compress down to 32 bits */
|
|
/* */
|
|
/* <***************work1*****************> */
|
|
/* 31 0 */
|
|
/* 000h 000d 000g 000c 000f 000b 000e 000a */
|
|
/* ^ ^ ^ ^ ^ ^ ^ ^ */
|
|
/* */
|
|
/* 3) Compress down to 16 bits */
|
|
/* */
|
|
/* <******work*******> */
|
|
/* 15 0 */
|
|
/* 0h0f 0d0b 0g0e 0c0a */
|
|
/* ^ ^ ^ ^ ^ ^ ^ ^ */
|
|
/* */
|
|
/* 4) Compress down to 8 bits */
|
|
/* */
|
|
/* hgfedcba */
|
|
/****************************************************************************/
|
|
#define ENCODEFGBG(result) \
|
|
{ \
|
|
UINT32 work1; \
|
|
UINT32 work2; \
|
|
unsigned work; \
|
|
\
|
|
work1 = ((*(PUINT32_UA)(xorbuf + EncodeSrcOffset)) >> fgShift) & \
|
|
0x01010101; \
|
|
work2 = ((*(PUINT32_UA)(xorbuf + EncodeSrcOffset + 4)) >> fgShift) & \
|
|
0x01010101; \
|
|
work1 = (work2 << 4) | work1; \
|
|
work = work1 | (work1 >> 14); \
|
|
result = ((BYTE)(((BYTE)(work >> 7)) | ((BYTE)work))); \
|
|
}
|
|
|
|
|
|
#ifndef DC_HICOLOR
|
|
/****************************************************************************/
|
|
// The following structure contains the results of our intermediate scan of
|
|
// the buffer.
|
|
/****************************************************************************/
|
|
typedef struct {
|
|
unsigned length;
|
|
BYTE type;
|
|
BYTE fgChar;
|
|
} MATCH;
|
|
#endif
|
|
|
|
|
|
/****************************************************************************/
|
|
// Critical minimum limit on a run size -- magic number that determines
|
|
// color run search characteristics. Minimum is 4 for hard-coded DWORD-size
|
|
// checks below. Comparisons of values:
|
|
// MinRunSize KBytes* Comp CPU ("hits")
|
|
// 4 52487 115842
|
|
// 5 52697 115116
|
|
// 6 52980 120565
|
|
// 7 53306 123680
|
|
// * = KBytes server->client WinBench98 Graphics WinMark minus CorelDRAW,
|
|
// measured in NetMon on Ethernet.
|
|
/****************************************************************************/
|
|
#define MinRunSize 5
|
|
|
|
|
|
/****************************************************************************/
|
|
// CompressV2Int
|
|
//
|
|
// Compresses a bitmap in one call, returning the size of the space used in
|
|
// the destination buffer or zero if the buffer was not large enough.
|
|
//
|
|
// Implementation notes: We use a length-2 array of MATCH elements as a
|
|
// running lookbehind buffer, allowing us to combine current run analysis
|
|
// results with previous entries before encoding into the destination buffer.
|
|
/****************************************************************************/
|
|
#ifdef DC_HICOLOR
|
|
unsigned RDPCALL SHCLASS CompressV2Int(
|
|
PBYTE pSrc,
|
|
PBYTE pDst,
|
|
unsigned numPels,
|
|
unsigned rowDelta,
|
|
unsigned dstBufferSize,
|
|
BYTE *xorbuf)
|
|
{
|
|
unsigned srcOffset;
|
|
unsigned EncodeSrcOffset;
|
|
unsigned bestRunLength;
|
|
unsigned nextRunLength;
|
|
unsigned runLength;
|
|
unsigned bestFGRunLength;
|
|
unsigned scanCount;
|
|
unsigned saveNumPels;
|
|
BOOLEAN inColorRun = FALSE;
|
|
BOOLEAN bEncodeAllMatches;
|
|
BYTE bestRunType = 0;
|
|
BYTE fgPel = 0xFF;
|
|
BYTE fgPelWork = 0xFF;
|
|
BYTE fgShift = 0;
|
|
BYTE EncodeFGPel;
|
|
PBYTE destbuf = pDst;
|
|
unsigned compressedLength = 0;
|
|
MATCH match[2];
|
|
|
|
DC_BEGIN_FN("CompressV2Int");
|
|
|
|
/************************************************************************/
|
|
// Validate params.
|
|
/************************************************************************/
|
|
TRC_ASSERT((numPels >= rowDelta),(TB,"numPels < rowDelta"));
|
|
TRC_ASSERT((!(rowDelta & 0x3)),(TB,"rowDelta not multiple of 4"));
|
|
TRC_ASSERT((!(numPels & 0x3)),(TB,"numPels not multiple of 4"));
|
|
TRC_ASSERT((!((UINT_PTR)pSrc & 0x3)),
|
|
(TB, "Possible unaligned access, pSrc = %p", pSrc));
|
|
|
|
/************************************************************************/
|
|
// Create XOR buffer - first row is copied from src, succeeding rows
|
|
// are the corresponding src row XOR'd with the next src row.
|
|
/************************************************************************/
|
|
memcpy(xorbuf, pSrc, rowDelta);
|
|
{
|
|
BYTE *srcbuf = pSrc + rowDelta;
|
|
unsigned srclen = numPels - rowDelta;
|
|
UINT32 *dwdest = (UINT32 *)(xorbuf + rowDelta);
|
|
|
|
while (srclen >= 8) {
|
|
*dwdest++ = *((PUINT32)srcbuf) ^ *((PUINT32)(srcbuf -
|
|
(int)rowDelta));
|
|
srcbuf += 4;
|
|
*dwdest++ = *((PUINT32)srcbuf) ^ *((PUINT32)(srcbuf -
|
|
(int)rowDelta));
|
|
srcbuf += 4;
|
|
srclen -= 8;
|
|
}
|
|
if (srclen) {
|
|
// Since we're 4-byte aligned we can only have a single DWORD
|
|
// remaining.
|
|
*dwdest = *((PUINT32)srcbuf) ^ *((PUINT32)(srcbuf -
|
|
(int)rowDelta));
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
// Set up encoding state variables.
|
|
/************************************************************************/
|
|
srcOffset = 0; // Offset in src buf where we are analyzing.
|
|
EncodeSrcOffset = 0; // Offset in src buf from where we are encoding.
|
|
EncodeFGPel = 0xFF; // Foreground color for encoding.
|
|
bEncodeAllMatches = FALSE; // Used to force encoding of all matches.
|
|
match[0].type = 0; // Initially no match types.
|
|
match[1].type = 0;
|
|
saveNumPels = numPels;
|
|
numPels = rowDelta;
|
|
|
|
/************************************************************************/
|
|
// Loop processing the input.
|
|
// We perform the loop twice, the first time for the non-XOR first line
|
|
// of the buffer and the second for the XOR portion, adjusting numPels
|
|
// to the needed value for each pass.
|
|
/************************************************************************/
|
|
for (scanCount = 0; ; scanCount++) {
|
|
while (srcOffset < numPels) {
|
|
/****************************************************************/
|
|
/* Start a while loop to allow a more structured break when we */
|
|
/* hit the first run type we want to encode (We can't afford */
|
|
/* the overheads of a function call to provide the scope here.) */
|
|
/****************************************************************/
|
|
while (TRUE) {
|
|
bestRunLength = 0;
|
|
bestFGRunLength = 0;
|
|
|
|
/************************************************************/
|
|
// If we are hitting the end of the buffer then just take
|
|
// color characters now. We will only hit this condition if
|
|
// we break out of a run just before the end of the buffer,
|
|
// so this should not be too common a situation, which is
|
|
// good given that we are encoding the final MinRunSize bytes
|
|
// uncompressed.
|
|
/************************************************************/
|
|
if ((srcOffset + MinRunSize) < numPels) {
|
|
goto ContinueScan;
|
|
}
|
|
else {
|
|
bestRunType = IMAGE_COLOR;
|
|
bestRunLength = numPels - srcOffset;
|
|
break;
|
|
}
|
|
ContinueScan:
|
|
|
|
/************************************************************/
|
|
// First do the scans on the XOR buffer. Look for a
|
|
// character run or a BG run.
|
|
// We must do the test independent of how long the run
|
|
// might be because even for a 1 pel BG run our later logic
|
|
// requires that we detect it seperately. This code is
|
|
// absolute main path so fastpath as much as possible. In
|
|
// particular detect short bg runs early and allow
|
|
// RunSingle to presuppose at least 4 matching bytes.
|
|
/************************************************************/
|
|
if (xorbuf[srcOffset] == 0x00) {
|
|
if ((srcOffset + 1) >= numPels ||
|
|
xorbuf[srcOffset + 1] != 0x00) {
|
|
bestRunType = RUN_BG;
|
|
bestRunLength = 1;
|
|
if (!inColorRun)
|
|
break;
|
|
}
|
|
else {
|
|
if ((srcOffset + 2) >= numPels ||
|
|
xorbuf[srcOffset + 2] != 0x00) {
|
|
bestRunType = RUN_BG;
|
|
bestRunLength = 2;
|
|
if (!inColorRun)
|
|
break;
|
|
}
|
|
else {
|
|
if ((srcOffset + 3) >= numPels ||
|
|
xorbuf[srcOffset + 3] != 0x00) {
|
|
bestRunType = RUN_BG;
|
|
bestRunLength = 3;
|
|
if (!inColorRun)
|
|
break;
|
|
}
|
|
else {
|
|
RUNSINGLE(xorbuf + srcOffset,
|
|
numPels - srcOffset,
|
|
bestFGRunLength);
|
|
CHECK_BEST_RUN(RUN_BG,
|
|
bestFGRunLength,
|
|
bestRunLength,
|
|
bestRunType);
|
|
if (!inColorRun)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/********************************************************/
|
|
// No point in starting if FG run less than 4 bytes so
|
|
// check the first dword as quickly as possible.
|
|
/********************************************************/
|
|
if (xorbuf[srcOffset] == xorbuf[srcOffset + 1] &&
|
|
*(PUINT16_UA)(xorbuf + srcOffset) ==
|
|
*(PUINT16_UA)(xorbuf + srcOffset + 2))
|
|
{
|
|
RUNSINGLE(xorbuf+srcOffset,
|
|
numPels-srcOffset,
|
|
bestFGRunLength);
|
|
|
|
/****************************************************/
|
|
// Don't permit a short FG run to prevent a FGBG
|
|
// image from starting up.
|
|
/****************************************************/
|
|
if (bestFGRunLength >= MinRunSize) {
|
|
CHECK_BEST_RUN(RUN_FG,
|
|
bestFGRunLength,
|
|
bestRunLength,
|
|
bestRunType);
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************/
|
|
// Look for solid or dithered sequences in the normal
|
|
// (non-XOR) buffer.
|
|
/************************************************************/
|
|
if ( (pSrc[srcOffset] == pSrc[srcOffset + 2]) &&
|
|
(pSrc[srcOffset + 1] == pSrc[srcOffset + 3])) {
|
|
/********************************************************/
|
|
// Now do the scan on the normal buffer for a character
|
|
// run. Don't bother if first line because we will have
|
|
// found it already in the XOR buffer, since we just
|
|
// copy pSrc to xorbuf for the first line. We insist on
|
|
// a run of at least MinRunSize pixels.
|
|
/********************************************************/
|
|
if (*(pSrc + srcOffset) == *(pSrc + srcOffset + 1)) {
|
|
if (srcOffset >= rowDelta) {
|
|
RUNSINGLE(pSrc + srcOffset,
|
|
numPels - srcOffset,
|
|
nextRunLength);
|
|
if (nextRunLength >= MinRunSize) {
|
|
CHECK_BEST_RUN(RUN_COLOR,
|
|
nextRunLength,
|
|
bestRunLength,
|
|
bestRunType);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/****************************************************/
|
|
// Look for a dither on the nrm buffer. Dithers are
|
|
// not very efficient for short runs so only take
|
|
// if 8 or longer. Note that our check against
|
|
// numPels above for MinRunSize will be overrun here
|
|
// so we need to make sure we don't go over the
|
|
// end of the buffer.
|
|
/****************************************************/
|
|
if (((numPels - srcOffset) > 8) &&
|
|
(*(PUINT32_UA)(pSrc + srcOffset) ==
|
|
*(PUINT32_UA)(pSrc + srcOffset + 4))) {
|
|
RunDouble(pSrc + srcOffset + 6,
|
|
numPels - srcOffset - 6,
|
|
nextRunLength);
|
|
nextRunLength += 6;
|
|
CHECK_BEST_RUN(RUN_DITHER,
|
|
nextRunLength,
|
|
bestRunLength,
|
|
bestRunType);
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************/
|
|
// If nothing so far then look for a FGBG run.
|
|
/************************************************************/
|
|
if (bestRunLength < MinRunSize) {
|
|
// Check this is not a single FG bit breaking up a BG
|
|
// run. If so then encode a BG_PEL run. Careful of the
|
|
// enforced BG run break across the first line
|
|
// non-XOR/XOR boundary.
|
|
if (*(PUINT32_UA)(xorbuf + srcOffset + 1) != 0 ||
|
|
*(xorbuf + srcOffset) != fgPel ||
|
|
match[1].type != RUN_BG ||
|
|
srcOffset == rowDelta) {
|
|
// If we have not found a run then look for a FG/BG
|
|
// image. Bandwidth/CPU comparisons:
|
|
// chkFGBGLen* KBytes** Comp CPU ("hits")
|
|
// 48/16/8 54856 140178
|
|
// 32/16/8 53177 129343
|
|
// 24/8/8 53020 130583
|
|
// 16/8/8 52874 126454
|
|
// 8/8/0 52980 120565
|
|
// no check 59753 101091
|
|
// * = minimum run length for checking best:
|
|
// start val / subtract for workchar==fgPel /
|
|
// subtract for nextRunLen divisible by 8
|
|
// ** = KBytes server->client WinBench98 Graphics
|
|
// WinMark minus CorelDRAW, measured in NetMon
|
|
// on Ethernet.
|
|
RUNFGBG(xorbuf + srcOffset, numPels - srcOffset,
|
|
nextRunLength, fgPelWork);
|
|
|
|
if (fgPelWork == fgPel || nextRunLength >= 8) {
|
|
CHECK_BEST_RUN(IMAGE_FGBG,
|
|
nextRunLength,
|
|
bestRunLength,
|
|
bestRunType);
|
|
}
|
|
}
|
|
else {
|
|
RUNSINGLE(xorbuf + srcOffset + 1,
|
|
numPels - srcOffset - 1,
|
|
nextRunLength);
|
|
nextRunLength++;
|
|
CHECK_BEST_RUN(RUN_BG_PEL,
|
|
nextRunLength,
|
|
bestRunLength,
|
|
bestRunType);
|
|
}
|
|
}
|
|
|
|
/************************************************************/
|
|
/* If nothing useful so far then allow a short run. */
|
|
/* Don't do this if we are accumulating a color run because */
|
|
/* it will really mess up GDC compression if we allow lots */
|
|
/* of little runs. Also require that it is a regular short */
|
|
/* run, rather than one that disturbs the fgPel */
|
|
/************************************************************/
|
|
if (!inColorRun) {
|
|
if (bestRunLength < MinRunSize) {
|
|
if (bestFGRunLength >= MinRunSize &&
|
|
xorbuf[srcOffset] == fgPel) {
|
|
/************************************************/
|
|
/* We mustn't merge with the previous code */
|
|
/* if we have just crossed the non-XOR/XOR */
|
|
/* boundary. */
|
|
/************************************************/
|
|
if (match[1].type == RUN_FG &&
|
|
srcOffset != rowDelta) {
|
|
match[1].length += bestFGRunLength;
|
|
srcOffset += bestFGRunLength;
|
|
continue;
|
|
}
|
|
else {
|
|
bestRunLength = bestFGRunLength;
|
|
bestRunType = RUN_FG;
|
|
}
|
|
}
|
|
else {
|
|
/************************************************/
|
|
/* If we decided to take a run earlier then */
|
|
/* allow it now. (May be a short BG run, for */
|
|
/* example) If nothing so far then take color */
|
|
/* image) */
|
|
/************************************************/
|
|
if (bestRunLength == 0) {
|
|
bestRunType = IMAGE_COLOR;
|
|
bestRunLength = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// We're in a color run. Keep small runs of other types
|
|
// from breaking up the color run and increasing the
|
|
// encoded size.
|
|
if (bestRunLength < (unsigned)(bestRunType == RUN_BG ?
|
|
MinRunSize : (MinRunSize + 2))) {
|
|
bestRunType = IMAGE_COLOR;
|
|
bestRunLength = 1;
|
|
}
|
|
}
|
|
|
|
// Get out of the loop after all checks are completed.
|
|
break;
|
|
}
|
|
|
|
/****************************************************************/
|
|
/* When we get here we have found the best run. Now check for */
|
|
/* various amalgamation conditions with the previous run type. */
|
|
/* Note that we may already have done amalgamation of short */
|
|
/* runs, but we had to do multiple samples for the longer runs */
|
|
/* so we repeat the checks here */
|
|
/****************************************************************/
|
|
|
|
/****************************************************************/
|
|
// If we are encoding a color run then combine it with an
|
|
// existing run if possible.
|
|
/****************************************************************/
|
|
if (bestRunType != IMAGE_COLOR) {
|
|
/************************************************************/
|
|
/* We are no longer encoding a COLOR_IMAGE of any kind */
|
|
/************************************************************/
|
|
inColorRun = FALSE;
|
|
|
|
// If we can amalgamate the entry then do so without creating
|
|
// a new array entry. Our search for FGBG runs is dependent
|
|
// upon that type of run being amalgamated because we break
|
|
// every 64 characters so that our mode switch detection
|
|
// works OK.
|
|
//
|
|
// Take care not to merge across the non-xor/xor boundary.
|
|
if (srcOffset != rowDelta) {
|
|
// Bump srcOffset and try a merge.
|
|
srcOffset += bestRunLength;
|
|
|
|
switch (bestRunType) {
|
|
case RUN_BG:
|
|
// BG runs merge with BG and BG_PEL runs.
|
|
if (match[1].type == RUN_BG ||
|
|
match[1].type == RUN_BG_PEL) {
|
|
match[1].length += bestRunLength;
|
|
TRC_DBG((TB, "Merged BG with preceding, "
|
|
"giving %u", match[1].length));
|
|
continue;
|
|
}
|
|
|
|
// Deliberate fallthrough to BG_PEL.
|
|
|
|
case RUN_BG_PEL:
|
|
// If it is a BG run following a FGBG run then
|
|
// merge in the pels to make the FGBG length a
|
|
// multiple of 8. If the remaining BG run is <= 8
|
|
// (which would translate to one extra byte in
|
|
// the previous FGBG as well as one byte of BG),
|
|
// merge it in also, otherwise just write the
|
|
// shortened BG run. Note that for RUN_BG_PEL,
|
|
// FG color will be the same as for the
|
|
// FGBG, no need to check.
|
|
if (match[1].type == IMAGE_FGBG &&
|
|
match[1].length & 0x0007) {
|
|
unsigned mergelen = 8 - (match[1].length &
|
|
0x0007);
|
|
|
|
if (mergelen > bestRunLength)
|
|
mergelen = bestRunLength;
|
|
match[1].length += mergelen;
|
|
bestRunLength -= mergelen;
|
|
TRC_DBG((TB,"Add %u pels to FGBG giving %u "
|
|
"leaving %u",
|
|
mergelen, match[1].length,
|
|
bestRunLength));
|
|
|
|
if (bestRunLength <= 8) {
|
|
match[1].length += bestRunLength;
|
|
TRC_DBG((TB,"Merge BG with prev FGBG "
|
|
"gives %u", match[1].length));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case RUN_FG:
|
|
// Keep track of the FG color. Remember to
|
|
// subtract bestRunLength since we incremented
|
|
// it before the switch statement.
|
|
fgPel = xorbuf[srcOffset - bestRunLength];
|
|
|
|
// FG run merges with previous FG if FG color is same.
|
|
if (match[1].type == RUN_FG &&
|
|
match[1].fgPel == fgPel) {
|
|
match[1].length += bestRunLength;
|
|
TRC_DBG((TB, "Merged FG with preceding, giving %u",
|
|
match[1].length));
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
|
|
case IMAGE_FGBG:
|
|
// FGBG leaves the foreground character in
|
|
// fgPelWork.
|
|
fgPel = fgPelWork;
|
|
|
|
// FGBG merges with previous if the FG colors are
|
|
// the same.
|
|
if (match[1].type == IMAGE_FGBG &&
|
|
match[1].fgPel == fgPel) {
|
|
match[1].length += bestRunLength;
|
|
TRC_DBG((TB, "Merged FGBG with preceding "
|
|
"FGBG, giving %u", match[1].length));
|
|
continue;
|
|
}
|
|
|
|
// FGBG merges with with small BG runs.
|
|
if (match[1].type == RUN_BG &&
|
|
match[1].length < 8) {
|
|
match[1].type = IMAGE_FGBG;
|
|
match[1].length += bestRunLength;
|
|
match[1].fgPel = fgPel;
|
|
TRC_DBG((TB, "Merged FGBG with preceding "
|
|
"BG run -> %u", match[1].length));
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
// Keep track of the FG color. The macro that searches for
|
|
// FGBG runs leaves the character in fgPelWork.
|
|
// Note this code is inlined into the merging code
|
|
// before.
|
|
if (bestRunType == RUN_FG)
|
|
fgPel = xorbuf[srcOffset];
|
|
else if (bestRunType == IMAGE_FGBG)
|
|
fgPel = fgPelWork;
|
|
|
|
// We're at the end of the first line. Just bump the
|
|
// source offset.
|
|
srcOffset += bestRunLength;
|
|
}
|
|
}
|
|
else {
|
|
/************************************************************/
|
|
/* Flag that we are within a color run */
|
|
/************************************************************/
|
|
inColorRun = TRUE;
|
|
|
|
srcOffset += bestRunLength;
|
|
|
|
/************************************************************/
|
|
// Merge the color run immediately, if possible. Note color
|
|
// runs are not restricted by the non-XOR/XOR boundary.
|
|
/************************************************************/
|
|
if (match[1].type == IMAGE_COLOR) {
|
|
match[1].length += bestRunLength;
|
|
continue;
|
|
}
|
|
if (match[0].type == IMAGE_COLOR && match[1].length == 1) {
|
|
// If it is a color run spanning any kind of single pel
|
|
// entity then merge all three runs into one.
|
|
// We have to create a special match queue condition
|
|
// here -- the single merged entry needs to be placed
|
|
// in the match[1] position and a null entry into [0]
|
|
// to allow the rest of the code to continue to
|
|
// be hardcoded to merge with [1].
|
|
match[1].length = match[0].length +
|
|
bestRunLength + 1;
|
|
match[1].type = IMAGE_COLOR;
|
|
match[0].type = 0;
|
|
|
|
TRC_DBG((TB, "Merged color with preceding color gives %u",
|
|
match[1].length));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/****************************************************************/
|
|
// The current run could not be merged with a previous match
|
|
// queue entry, We have to encode the [0] slot then add the
|
|
// current run the the queue.
|
|
/****************************************************************/
|
|
TRC_DBG((TB, "Best run of type %u has length %u", bestRunType,
|
|
bestRunLength));
|
|
|
|
DoEncoding:
|
|
|
|
// First check for our approaching the end of the destination
|
|
// buffer and get out if this is the case. We allow for the
|
|
// largest general run order (a mega-mega set run = 4 bytes).
|
|
// Orders which may be larger are checked within the case arm
|
|
if ((unsigned)(destbuf - pDst + 4) <= dstBufferSize)
|
|
goto ContinueEncoding;
|
|
else
|
|
DC_QUIT;
|
|
ContinueEncoding:
|
|
|
|
switch (match[0].type) {
|
|
case 0:
|
|
// Unused entry.
|
|
break;
|
|
|
|
case RUN_BG:
|
|
case RUN_BG_PEL:
|
|
// Note that for BG_PEL we utilize the code sequence
|
|
// BG,BG which would not otherwise appear as a special
|
|
// case meaning insert one current FG char between
|
|
// the two runs.
|
|
ENCODE_ORDER_MEGA(destbuf,
|
|
CODE_BG_RUN,
|
|
match[0].length,
|
|
CODE_MEGA_MEGA_BG_RUN,
|
|
MAX_LENGTH_ORDER,
|
|
MAX_LENGTH_LONG_ORDER);
|
|
TRC_DBG((TB, "BG RUN %u",match[0].length));
|
|
EncodeSrcOffset += match[0].length;
|
|
break;
|
|
|
|
case RUN_FG:
|
|
// If the fg value is different from the current
|
|
// then encode a set+run code.
|
|
if (EncodeFGPel != match[0].fgPel) {
|
|
SETFGCHAR((BYTE)match[0].fgPel, EncodeFGPel, fgShift);
|
|
ENCODE_ORDER_MEGA(destbuf,
|
|
CODE_SET_FG_FG_RUN,
|
|
match[0].length,
|
|
CODE_MEGA_MEGA_SET_FG_RUN,
|
|
MAX_LENGTH_ORDER_LITE,
|
|
MAX_LENGTH_LONG_ORDER_LITE);
|
|
*destbuf++ = EncodeFGPel;
|
|
TRC_DBG((TB, "SET_FG_FG_RUN %u", match[0].length));
|
|
}
|
|
else {
|
|
ENCODE_ORDER_MEGA(destbuf,
|
|
CODE_FG_RUN,
|
|
match[0].length,
|
|
CODE_MEGA_MEGA_FG_RUN,
|
|
MAX_LENGTH_ORDER,
|
|
MAX_LENGTH_LONG_ORDER);
|
|
TRC_DBG((TB, "FG_RUN %u", match[0].length));
|
|
}
|
|
EncodeSrcOffset += match[0].length;
|
|
break;
|
|
|
|
case IMAGE_FGBG:
|
|
runLength = match[0].length;
|
|
|
|
// Check for our approaching the end of the destination
|
|
// buffer and get out if this is the case.
|
|
if ((destbuf - pDst + (runLength + 7)/8 + 4) <=
|
|
dstBufferSize)
|
|
goto ContinueFGBG;
|
|
else
|
|
DC_QUIT;
|
|
ContinueFGBG:
|
|
|
|
// We need to convert FGBG runs into the pixel form.
|
|
if (EncodeFGPel != match[0].fgPel) {
|
|
SETFGCHAR((BYTE)match[0].fgPel, EncodeFGPel, fgShift);
|
|
ENCODE_ORDER_MEGA_FGBG(destbuf,
|
|
CODE_SET_FG_FG_BG,
|
|
runLength,
|
|
CODE_MEGA_MEGA_SET_FGBG,
|
|
MAX_LENGTH_FGBG_ORDER_LITE,
|
|
MAX_LENGTH_LONG_FGBG_ORDER);
|
|
*destbuf++ = EncodeFGPel;
|
|
TRC_DBG((TB, "SET_FG_FG_BG %u", match[0].length));
|
|
while (runLength >= 8) {
|
|
ENCODEFGBG(*destbuf);
|
|
destbuf++;
|
|
EncodeSrcOffset += 8;
|
|
runLength -= 8;
|
|
}
|
|
if (runLength) {
|
|
ENCODEFGBG(*destbuf);
|
|
|
|
// Keep the final partial byte clean to help GDC
|
|
// packing.
|
|
*destbuf &= ((0x01 << runLength) - 1);
|
|
destbuf++;
|
|
EncodeSrcOffset += runLength;
|
|
}
|
|
}
|
|
else {
|
|
if (runLength == 8) {
|
|
BYTE fgbgChar;
|
|
|
|
// See if it is one of the high probability bytes.
|
|
ENCODEFGBG(fgbgChar);
|
|
|
|
// Check for single byte encoding of FGBG images.
|
|
switch (fgbgChar) {
|
|
case SPECIAL_FGBG_CODE_1:
|
|
*destbuf++ = CODE_SPECIAL_FGBG_1;
|
|
break;
|
|
case SPECIAL_FGBG_CODE_2:
|
|
*destbuf++ = CODE_SPECIAL_FGBG_2;
|
|
break;
|
|
default:
|
|
ENCODE_ORDER_MEGA_FGBG(destbuf,
|
|
CODE_FG_BG_IMAGE,
|
|
runLength,
|
|
CODE_MEGA_MEGA_FGBG,
|
|
MAX_LENGTH_FGBG_ORDER,
|
|
MAX_LENGTH_LONG_FGBG_ORDER);
|
|
*destbuf++ = fgbgChar;
|
|
break;
|
|
}
|
|
EncodeSrcOffset += 8;
|
|
}
|
|
else {
|
|
// Encode as standard FGBG.
|
|
ENCODE_ORDER_MEGA_FGBG(destbuf,
|
|
CODE_FG_BG_IMAGE,
|
|
runLength,
|
|
CODE_MEGA_MEGA_FGBG,
|
|
MAX_LENGTH_FGBG_ORDER,
|
|
MAX_LENGTH_LONG_FGBG_ORDER);
|
|
TRC_DBG((TB, "FG_BG %u", match[0].length));
|
|
while (runLength >= 8) {
|
|
ENCODEFGBG(*destbuf);
|
|
destbuf++;
|
|
EncodeSrcOffset += 8;
|
|
runLength -= 8;
|
|
}
|
|
if (runLength) {
|
|
ENCODEFGBG(*destbuf);
|
|
*destbuf &= ((0x01 << runLength) - 1);
|
|
destbuf++;
|
|
EncodeSrcOffset += runLength;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case RUN_COLOR:
|
|
ENCODE_ORDER_MEGA(destbuf,
|
|
CODE_COLOR_RUN,
|
|
match[0].length,
|
|
CODE_MEGA_MEGA_COLOR_RUN,
|
|
MAX_LENGTH_ORDER,
|
|
MAX_LENGTH_LONG_ORDER);
|
|
TRC_DBG((TB, "COLOR_RUN %u", match[0].length));
|
|
*destbuf++ = pSrc[EncodeSrcOffset];
|
|
EncodeSrcOffset += match[0].length;
|
|
break;
|
|
|
|
case RUN_DITHER:
|
|
{
|
|
unsigned ditherlen = match[0].length / 2;
|
|
ENCODE_ORDER_MEGA(destbuf,
|
|
CODE_DITHERED_RUN,
|
|
ditherlen,
|
|
CODE_MEGA_MEGA_DITHER,
|
|
MAX_LENGTH_ORDER_LITE,
|
|
MAX_LENGTH_LONG_ORDER_LITE);
|
|
TRC_DBG((TB, "DITHERED_RUN %u", match[0].length));
|
|
|
|
// First check for our approaching the end of the
|
|
// destination buffer and get out if this is the case.
|
|
if ((unsigned)(destbuf - pDst + 2) <= dstBufferSize) {
|
|
*destbuf++ = pSrc[EncodeSrcOffset];
|
|
*destbuf++ = pSrc[EncodeSrcOffset + 1];
|
|
EncodeSrcOffset += match[0].length;
|
|
}
|
|
else {
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IMAGE_COLOR:
|
|
// Length 1 can possibly be encoded as a single BLACK/WHITE.
|
|
if (match[0].length == 1) {
|
|
if (pSrc[EncodeSrcOffset] == 0x00) {
|
|
*destbuf++ = CODE_BLACK;
|
|
EncodeSrcOffset++;
|
|
break;
|
|
}
|
|
if (pSrc[EncodeSrcOffset] == 0xFF) {
|
|
*destbuf++ = CODE_WHITE;
|
|
EncodeSrcOffset++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Store the data in non-compressed form.
|
|
ENCODE_ORDER_MEGA(destbuf,
|
|
CODE_COLOR_IMAGE,
|
|
match[0].length,
|
|
CODE_MEGA_MEGA_CLR_IMG,
|
|
MAX_LENGTH_ORDER,
|
|
MAX_LENGTH_LONG_ORDER);
|
|
TRC_DBG((TB, "COLOR_IMAGE %u", match[0].length));
|
|
|
|
// First check for our approaching the end of the
|
|
// destination buffer and get out if this is the case.
|
|
if ((destbuf - pDst + (UINT_PTR)match[0].length) <=
|
|
dstBufferSize) {
|
|
// Now just copy the data over.
|
|
memcpy(destbuf, pSrc+EncodeSrcOffset, match[0].length);
|
|
destbuf += match[0].length;
|
|
EncodeSrcOffset += match[0].length;
|
|
}
|
|
else {
|
|
DC_QUIT;
|
|
}
|
|
|
|
break;
|
|
|
|
#ifdef DC_DEBUG
|
|
default:
|
|
TRC_ERR((TB, "Invalid run type %u",match[0].type));
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************/
|
|
// Done encoding, what we do next is determined by whether we're
|
|
// flushing the match queue after everything is scanned.
|
|
/****************************************************************/
|
|
match[0] = match[1];
|
|
if (!bEncodeAllMatches) {
|
|
// Push the current run into the top of the queue.
|
|
match[1].type = bestRunType;
|
|
match[1].length = bestRunLength;
|
|
match[1].fgPel = fgPel;
|
|
}
|
|
else {
|
|
// We need to check to see if we're really finished. Since
|
|
// our maximum queue depth is 2, if we're done then the only
|
|
// remaining entry has an encoding type of 0.
|
|
if (match[0].type == 0) {
|
|
goto PostScan;
|
|
}
|
|
else {
|
|
match[1].type = 0;
|
|
goto DoEncoding;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (scanCount == 0) {
|
|
// If we have just done our scan of the first line then now do the
|
|
// rest of the buffer. Reset our saved pel count.
|
|
numPels = saveNumPels;
|
|
}
|
|
else {
|
|
// When we are done with the second pass (we've reached the end of
|
|
// the buffer) we have to force the remaining items in the match
|
|
// queue to be encoded. Yes this is similar to old BASIC
|
|
// code in using gotos, but we cannot place the encoding code into
|
|
// a function because of the number of params required, and
|
|
// we cannot duplicate it because it is too big. This code is
|
|
// some of the most used in the system so the cost is worth it.
|
|
bEncodeAllMatches = TRUE;
|
|
goto DoEncoding;
|
|
}
|
|
}
|
|
|
|
PostScan:
|
|
// Success, calculate the amount of space we used.
|
|
compressedLength = (unsigned)(destbuf - pDst);
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return compressedLength;
|
|
}
|
|
#else
|
|
unsigned RDPCALL SHCLASS CompressV2Int(
|
|
PBYTE pSrc,
|
|
PBYTE pDst,
|
|
unsigned numPels,
|
|
unsigned rowDelta,
|
|
unsigned dstBufferSize,
|
|
BYTE *xorbuf)
|
|
{
|
|
unsigned srcOffset;
|
|
unsigned EncodeSrcOffset;
|
|
unsigned bestRunLength;
|
|
unsigned nextRunLength;
|
|
unsigned runLength;
|
|
unsigned bestFGRunLength;
|
|
unsigned scanCount;
|
|
unsigned saveNumPels;
|
|
BOOLEAN inColorRun = FALSE;
|
|
BOOLEAN bEncodeAllMatches;
|
|
BYTE bestRunType = 0;
|
|
BYTE fgChar = 0xFF;
|
|
BYTE fgCharWork = 0xFF;
|
|
BYTE fgShift = 0;
|
|
BYTE EncodeFGChar;
|
|
PBYTE destbuf = pDst;
|
|
unsigned compressedLength = 0;
|
|
MATCH match[2];
|
|
|
|
DC_BEGIN_FN("CompressV2Int");
|
|
|
|
/************************************************************************/
|
|
// Validate params.
|
|
/************************************************************************/
|
|
TRC_ASSERT((numPels >= rowDelta),(TB,"numPels < rowDelta"));
|
|
TRC_ASSERT((!(rowDelta & 0x3)),(TB,"rowDelta not multiple of 4"));
|
|
TRC_ASSERT((!(numPels & 0x3)),(TB,"numPels not multiple of 4"));
|
|
TRC_ASSERT((!((UINT_PTR)pSrc & 0x3)),
|
|
(TB, "Possible unaligned access, pSrc = %p", pSrc));
|
|
|
|
/************************************************************************/
|
|
// Create XOR buffer - first row is copied from src, succeeding rows
|
|
// are the corresponding src row XOR'd with the next src row.
|
|
/************************************************************************/
|
|
memcpy(xorbuf, pSrc, rowDelta);
|
|
{
|
|
BYTE *srcbuf = pSrc + rowDelta;
|
|
unsigned srclen = numPels - rowDelta;
|
|
UINT32 *dwdest = (UINT32 *)(xorbuf + rowDelta);
|
|
|
|
while (srclen >= 8) {
|
|
*dwdest++ = *((PUINT32)srcbuf) ^ *((PUINT32)(srcbuf -
|
|
(int)rowDelta));
|
|
srcbuf += 4;
|
|
*dwdest++ = *((PUINT32)srcbuf) ^ *((PUINT32)(srcbuf -
|
|
(int)rowDelta));
|
|
srcbuf += 4;
|
|
srclen -= 8;
|
|
}
|
|
if (srclen) {
|
|
// Since we're 4-byte aligned we can only have a single DWORD
|
|
// remaining.
|
|
*dwdest = *((PUINT32)srcbuf) ^ *((PUINT32)(srcbuf -
|
|
(int)rowDelta));
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
// Set up encoding state variables.
|
|
/************************************************************************/
|
|
srcOffset = 0; // Offset in src buf where we are analyzing.
|
|
EncodeSrcOffset = 0; // Offset in src buf from where we are encoding.
|
|
EncodeFGChar = 0xFF; // Foreground color for encoding.
|
|
bEncodeAllMatches = FALSE; // Used to force encoding of all matches.
|
|
match[0].type = 0; // Initially no match types.
|
|
match[1].type = 0;
|
|
saveNumPels = numPels;
|
|
numPels = rowDelta;
|
|
|
|
/************************************************************************/
|
|
// Loop processing the input.
|
|
// We perform the loop twice, the first time for the non-XOR first line
|
|
// of the buffer and the second for the XOR portion, adjusting numPels
|
|
// to the needed value for each pass.
|
|
/************************************************************************/
|
|
for (scanCount = 0; ; scanCount++) {
|
|
while (srcOffset < numPels) {
|
|
/****************************************************************/
|
|
/* Start a while loop to allow a more structured break when we */
|
|
/* hit the first run type we want to encode (We can't afford */
|
|
/* the overheads of a function call to provide the scope here.) */
|
|
/****************************************************************/
|
|
while (TRUE) {
|
|
bestRunLength = 0;
|
|
bestFGRunLength = 0;
|
|
|
|
/************************************************************/
|
|
// If we are hitting the end of the buffer then just take
|
|
// color characters now. We will only hit this condition if
|
|
// we break out of a run just before the end of the buffer,
|
|
// so this should not be too common a situation, which is
|
|
// good given that we are encoding the final MinRunSize bytes
|
|
// uncompressed.
|
|
/************************************************************/
|
|
if ((srcOffset + MinRunSize) < numPels) {
|
|
goto ContinueScan;
|
|
}
|
|
else {
|
|
bestRunType = IMAGE_COLOR;
|
|
bestRunLength = numPels - srcOffset;
|
|
break;
|
|
}
|
|
ContinueScan:
|
|
|
|
/************************************************************/
|
|
// First do the scans on the XOR buffer. Look for a
|
|
// character run or a BG run.
|
|
// We must do the test independent of how long the run
|
|
// might be because even for a 1 pel BG run our later logic
|
|
// requires that we detect it seperately. This code is
|
|
// absolute main path so fastpath as much as possible. In
|
|
// particular detect short bg runs early and allow
|
|
// RunSingle to presuppose at least 4 matching bytes.
|
|
/************************************************************/
|
|
if (xorbuf[srcOffset] == 0x00) {
|
|
if ((srcOffset + 1) >= numPels ||
|
|
xorbuf[srcOffset + 1] != 0x00) {
|
|
bestRunType = RUN_BG;
|
|
bestRunLength = 1;
|
|
if (!inColorRun)
|
|
break;
|
|
}
|
|
else {
|
|
if ((srcOffset + 2) >= numPels ||
|
|
xorbuf[srcOffset + 2] != 0x00) {
|
|
bestRunType = RUN_BG;
|
|
bestRunLength = 2;
|
|
if (!inColorRun)
|
|
break;
|
|
}
|
|
else {
|
|
if ((srcOffset + 3) >= numPels ||
|
|
xorbuf[srcOffset + 3] != 0x00) {
|
|
bestRunType = RUN_BG;
|
|
bestRunLength = 3;
|
|
if (!inColorRun)
|
|
break;
|
|
}
|
|
else {
|
|
RUNSINGLE(xorbuf + srcOffset,
|
|
numPels - srcOffset,
|
|
bestFGRunLength);
|
|
CHECK_BEST_RUN(RUN_BG,
|
|
bestFGRunLength,
|
|
bestRunLength,
|
|
bestRunType);
|
|
if (!inColorRun)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/********************************************************/
|
|
// No point in starting if FG run less than 4 bytes so
|
|
// check the first dword as quickly as possible.
|
|
/********************************************************/
|
|
if (xorbuf[srcOffset] == xorbuf[srcOffset + 1] &&
|
|
*(PUINT16_UA)(xorbuf + srcOffset) ==
|
|
*(PUINT16_UA)(xorbuf + srcOffset + 2))
|
|
{
|
|
RUNSINGLE(xorbuf + srcOffset,
|
|
numPels - srcOffset,
|
|
bestFGRunLength);
|
|
|
|
/****************************************************/
|
|
// Don't permit a short FG run to prevent a FGBG
|
|
// image from starting up.
|
|
/****************************************************/
|
|
if (bestFGRunLength >= MinRunSize) {
|
|
CHECK_BEST_RUN(RUN_FG,
|
|
bestFGRunLength,
|
|
bestRunLength,
|
|
bestRunType);
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************/
|
|
// Look for solid or dithered sequences in the normal
|
|
// (non-XOR) buffer.
|
|
/************************************************************/
|
|
if ( (pSrc[srcOffset] == pSrc[srcOffset + 2]) &&
|
|
(pSrc[srcOffset + 1] == pSrc[srcOffset + 3])) {
|
|
/********************************************************/
|
|
// Now do the scan on the normal buffer for a character
|
|
// run. Don't bother if first line because we will have
|
|
// found it already in the XOR buffer, since we just
|
|
// copy pSrc to xorbuf for the first line. We insist on
|
|
// a run of at least MinRunSize pixels.
|
|
/********************************************************/
|
|
if (*(pSrc + srcOffset) == *(pSrc + srcOffset + 1)) {
|
|
if (srcOffset >= rowDelta) {
|
|
RUNSINGLE(pSrc + srcOffset,
|
|
numPels - srcOffset,
|
|
nextRunLength);
|
|
if (nextRunLength >= MinRunSize) {
|
|
CHECK_BEST_RUN(RUN_COLOR,
|
|
nextRunLength,
|
|
bestRunLength,
|
|
bestRunType);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/****************************************************/
|
|
/* Look for a dither on the nrm buffer Dithers are */
|
|
/* not very efficient for short runs so only take */
|
|
/* if 8 or longer */
|
|
/****************************************************/
|
|
if (*(PUINT32_UA)(pSrc + srcOffset) ==
|
|
*(PUINT32_UA)(pSrc + srcOffset + 4)) {
|
|
RunDouble(pSrc + srcOffset + 6,
|
|
numPels - srcOffset - 6,
|
|
nextRunLength);
|
|
nextRunLength += 6;
|
|
CHECK_BEST_RUN(RUN_DITHER,
|
|
nextRunLength,
|
|
bestRunLength,
|
|
bestRunType);
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************/
|
|
// If nothing so far then look for a FGBG run.
|
|
/************************************************************/
|
|
if (bestRunLength < MinRunSize) {
|
|
// Check this is not a single FG bit breaking up a BG
|
|
// run. If so then encode a BG_PEL run. Careful of the
|
|
// enforced BG run break across the first line
|
|
// non-XOR/XOR boundary.
|
|
if (*(PUINT32_UA)(xorbuf + srcOffset + 1) != 0 ||
|
|
*(xorbuf + srcOffset) != fgChar ||
|
|
match[1].type != RUN_BG ||
|
|
srcOffset == rowDelta) {
|
|
// If we have not found a run then look for a FG/BG
|
|
// image. Bandwidth/CPU comparisons:
|
|
// chkFGBGLen* KBytes** Comp CPU ("hits")
|
|
// 48/16/8 54856 140178
|
|
// 32/16/8 53177 129343
|
|
// 24/8/8 53020 130583
|
|
// 16/8/8 52874 126454
|
|
// 8/8/0 52980 120565
|
|
// no check 59753 101091
|
|
// * = minimum run length for checking best:
|
|
// start val / subtract for workchar==fgChar /
|
|
// subtract for nextRunLen divisible by 8
|
|
// ** = KBytes server->client WinBench98 Graphics
|
|
// WinMark minus CorelDRAW, measured in NetMon
|
|
// on Ethernet.
|
|
RUNFGBG(xorbuf + srcOffset, numPels - srcOffset,
|
|
nextRunLength, fgCharWork);
|
|
|
|
if (fgCharWork == fgChar || nextRunLength >= 8) {
|
|
CHECK_BEST_RUN(IMAGE_FGBG,
|
|
nextRunLength,
|
|
bestRunLength,
|
|
bestRunType);
|
|
}
|
|
}
|
|
else {
|
|
RUNSINGLE(xorbuf + srcOffset + 1,
|
|
numPels - srcOffset - 1,
|
|
nextRunLength);
|
|
nextRunLength++;
|
|
CHECK_BEST_RUN(RUN_BG_PEL,
|
|
nextRunLength,
|
|
bestRunLength,
|
|
bestRunType);
|
|
}
|
|
}
|
|
|
|
/************************************************************/
|
|
/* If nothing useful so far then allow a short run. */
|
|
/* Don't do this if we are accumulating a color run because */
|
|
/* it will really mess up GDC compression if we allow lots */
|
|
/* of little runs. Also require that it is a regular short */
|
|
/* run, rather than one that disturbs the fgChar */
|
|
/************************************************************/
|
|
if (!inColorRun) {
|
|
if (bestRunLength < MinRunSize) {
|
|
if (bestFGRunLength >= MinRunSize &&
|
|
xorbuf[srcOffset] == fgChar) {
|
|
/************************************************/
|
|
/* We mustn't merge with the previous code */
|
|
/* if we have just crossed the non-XOR/XOR */
|
|
/* boundary. */
|
|
/************************************************/
|
|
if (match[1].type == RUN_FG &&
|
|
srcOffset != rowDelta) {
|
|
match[1].length += bestFGRunLength;
|
|
srcOffset += bestFGRunLength;
|
|
continue;
|
|
}
|
|
else {
|
|
bestRunLength = bestFGRunLength;
|
|
bestRunType = RUN_FG;
|
|
}
|
|
}
|
|
else {
|
|
/************************************************/
|
|
/* If we decided to take a run earlier then */
|
|
/* allow it now. (May be a short BG run, for */
|
|
/* example) If nothing so far then take color */
|
|
/* image) */
|
|
/************************************************/
|
|
if (bestRunLength == 0) {
|
|
bestRunType = IMAGE_COLOR;
|
|
bestRunLength = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// We're in a color run. Keep small runs of other types
|
|
// from breaking up the color run and increasing the
|
|
// encoded size.
|
|
if (bestRunLength < (unsigned)(bestRunType == RUN_BG ?
|
|
MinRunSize : (MinRunSize + 2))) {
|
|
bestRunType = IMAGE_COLOR;
|
|
bestRunLength = 1;
|
|
}
|
|
}
|
|
|
|
// Get out of the loop after all checks are completed.
|
|
break;
|
|
}
|
|
|
|
/****************************************************************/
|
|
/* When we get here we have found the best run. Now check for */
|
|
/* various amalgamation conditions with the previous run type. */
|
|
/* Note that we may already have done amalgamation of short */
|
|
/* runs, but we had to do multiple samples for the longer runs */
|
|
/* so we repeat the checks here */
|
|
/****************************************************************/
|
|
|
|
/****************************************************************/
|
|
// If we are encoding a color run then combine it with an
|
|
// existing run if possible.
|
|
/****************************************************************/
|
|
if (bestRunType != IMAGE_COLOR) {
|
|
/************************************************************/
|
|
/* We are no longer encoding a COLOR_IMAGE of any kind */
|
|
/************************************************************/
|
|
inColorRun = FALSE;
|
|
|
|
// If we can amalgamate the entry then do so without creating
|
|
// a new array entry. Our search for FGBG runs is dependent
|
|
// upon that type of run being amalgamated because we break
|
|
// every 64 characters so that our mode switch detection
|
|
// works OK.
|
|
//
|
|
// Take care not to merge across the non-xor/xor boundary.
|
|
if (srcOffset != rowDelta) {
|
|
// Bump srcOffset and try a merge.
|
|
srcOffset += bestRunLength;
|
|
|
|
switch (bestRunType) {
|
|
case RUN_BG:
|
|
// BG runs merge with BG and BG_PEL runs.
|
|
if (match[1].type == RUN_BG ||
|
|
match[1].type == RUN_BG_PEL) {
|
|
match[1].length += bestRunLength;
|
|
TRC_DBG((TB, "Merged BG with preceding, "
|
|
"giving %u", match[1].length));
|
|
continue;
|
|
}
|
|
|
|
// Deliberate fallthrough to BG_PEL.
|
|
|
|
case RUN_BG_PEL:
|
|
// If it is a BG run following a FGBG run then
|
|
// merge in the pels to make the FGBG length a
|
|
// multiple of 8. If the remaining BG run is <= 8
|
|
// (which would translate to one extra byte in
|
|
// the previous FGBG as well as one byte of BG),
|
|
// merge it in also, otherwise just write the
|
|
// shortened BG run. Note that for RUN_BG_PEL,
|
|
// FG color will be the same as for the
|
|
// FGBG, no need to check.
|
|
if (match[1].type == IMAGE_FGBG &&
|
|
match[1].length & 0x0007) {
|
|
unsigned mergelen = 8 - (match[1].length &
|
|
0x0007);
|
|
|
|
if (mergelen > bestRunLength)
|
|
mergelen = bestRunLength;
|
|
match[1].length += mergelen;
|
|
bestRunLength -= mergelen;
|
|
TRC_DBG((TB,"Add %u pels to FGBG giving %u "
|
|
"leaving %u",
|
|
mergelen, match[1].length,
|
|
bestRunLength));
|
|
|
|
if (bestRunLength <= 8) {
|
|
match[1].length += bestRunLength;
|
|
TRC_DBG((TB,"Merge BG with prev FGBG "
|
|
"gives %u", match[1].length));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case RUN_FG:
|
|
// Keep track of the FG color. Remember to
|
|
// subtract bestRunLength since we incremented
|
|
// it before the switch statement.
|
|
fgChar = xorbuf[srcOffset - bestRunLength];
|
|
|
|
// FG run merges with previous FG if FG color is same.
|
|
if (match[1].type == RUN_FG &&
|
|
match[1].fgChar == fgChar) {
|
|
match[1].length += bestRunLength;
|
|
TRC_DBG((TB, "Merged FG with preceding, giving %u",
|
|
match[1].length));
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
|
|
case IMAGE_FGBG:
|
|
// FGBG leaves the foreground character in
|
|
// fgCharWork.
|
|
fgChar = fgCharWork;
|
|
|
|
// FGBG merges with previous if the FG colors are
|
|
// the same.
|
|
if (match[1].type == IMAGE_FGBG &&
|
|
match[1].fgChar == fgChar) {
|
|
match[1].length += bestRunLength;
|
|
TRC_DBG((TB, "Merged FGBG with preceding "
|
|
"FGBG, giving %u", match[1].length));
|
|
continue;
|
|
}
|
|
|
|
// FGBG merges with with small BG runs.
|
|
if (match[1].type == RUN_BG &&
|
|
match[1].length < 8) {
|
|
match[1].type = IMAGE_FGBG;
|
|
match[1].length += bestRunLength;
|
|
match[1].fgChar = fgChar;
|
|
TRC_DBG((TB, "Merged FGBG with preceding "
|
|
"BG run -> %u", match[1].length));
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
// Keep track of the FG color. The macro that searches for
|
|
// FGBG runs leaves the character in fgCharWork.
|
|
// Note this code is inlined into the merging code
|
|
// before.
|
|
if (bestRunType == RUN_FG)
|
|
fgChar = xorbuf[srcOffset];
|
|
else if (bestRunType == IMAGE_FGBG)
|
|
fgChar = fgCharWork;
|
|
|
|
// We're at the end of the first line. Just bump the
|
|
// source offset.
|
|
srcOffset += bestRunLength;
|
|
}
|
|
}
|
|
else {
|
|
/************************************************************/
|
|
/* Flag that we are within a color run */
|
|
/************************************************************/
|
|
inColorRun = TRUE;
|
|
|
|
srcOffset += bestRunLength;
|
|
|
|
/************************************************************/
|
|
// Merge the color run immediately, if possible. Note color
|
|
// runs are not restricted by the non-XOR/XOR boundary.
|
|
/************************************************************/
|
|
if (match[1].type == IMAGE_COLOR) {
|
|
match[1].length += bestRunLength;
|
|
continue;
|
|
}
|
|
if (match[0].type == IMAGE_COLOR && match[1].length == 1) {
|
|
// If it is a color run spanning any kind of single pel
|
|
// entity then merge all three runs into one.
|
|
// We have to create a special match queue condition
|
|
// here -- the single merged entry needs to be placed
|
|
// in the match[1] position and a null entry into [0]
|
|
// to allow the rest of the code to continue to
|
|
// be hardcoded to merge with [1].
|
|
match[1].length = match[0].length +
|
|
bestRunLength + 1;
|
|
match[1].type = IMAGE_COLOR;
|
|
match[0].type = 0;
|
|
|
|
TRC_DBG((TB, "Merged color with preceding color gives %u",
|
|
match[1].length));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/****************************************************************/
|
|
// The current run could not be merged with a previous match
|
|
// queue entry, We have to encode the [0] slot then add the
|
|
// current run the the queue.
|
|
/****************************************************************/
|
|
TRC_DBG((TB, "Best run of type %u has length %u", bestRunType,
|
|
bestRunLength));
|
|
|
|
DoEncoding:
|
|
|
|
// First check for our approaching the end of the destination
|
|
// buffer and get out if this is the case. We allow for the
|
|
// largest general run order (a mega-mega set run = 4 bytes).
|
|
// Orders which may be larger are checked within the case arm
|
|
if ((unsigned)(destbuf - pDst + 4) <= dstBufferSize)
|
|
goto ContinueEncoding;
|
|
else
|
|
DC_QUIT;
|
|
ContinueEncoding:
|
|
|
|
switch (match[0].type) {
|
|
case 0:
|
|
// Unused entry.
|
|
break;
|
|
|
|
case RUN_BG:
|
|
case RUN_BG_PEL:
|
|
// Note that for BG_PEL we utilize the code sequence
|
|
// BG,BG which would not otherwise appear as a special
|
|
// case meaning insert one current FG char between
|
|
// the two runs.
|
|
ENCODE_ORDER_MEGA(destbuf,
|
|
CODE_BG_RUN,
|
|
match[0].length,
|
|
CODE_MEGA_MEGA_BG_RUN,
|
|
MAX_LENGTH_ORDER,
|
|
MAX_LENGTH_LONG_ORDER);
|
|
TRC_DBG((TB, "BG RUN %u",match[0].length));
|
|
EncodeSrcOffset += match[0].length;
|
|
break;
|
|
|
|
case RUN_FG:
|
|
// If the fg value is different from the current
|
|
// then encode a set+run code.
|
|
if (EncodeFGChar != match[0].fgChar) {
|
|
SETFGCHAR(match[0].fgChar, EncodeFGChar, fgShift);
|
|
ENCODE_ORDER_MEGA(destbuf,
|
|
CODE_SET_FG_FG_RUN,
|
|
match[0].length,
|
|
CODE_MEGA_MEGA_SET_FG_RUN,
|
|
MAX_LENGTH_ORDER_LITE,
|
|
MAX_LENGTH_LONG_ORDER_LITE);
|
|
*destbuf++ = EncodeFGChar;
|
|
TRC_DBG((TB, "SET_FG_FG_RUN %u", match[0].length));
|
|
}
|
|
else {
|
|
ENCODE_ORDER_MEGA(destbuf,
|
|
CODE_FG_RUN,
|
|
match[0].length,
|
|
CODE_MEGA_MEGA_FG_RUN,
|
|
MAX_LENGTH_ORDER,
|
|
MAX_LENGTH_LONG_ORDER);
|
|
TRC_DBG((TB, "FG_RUN %u", match[0].length));
|
|
}
|
|
EncodeSrcOffset += match[0].length;
|
|
break;
|
|
|
|
case IMAGE_FGBG:
|
|
runLength = match[0].length;
|
|
|
|
// Check for our approaching the end of the destination
|
|
// buffer and get out if this is the case.
|
|
if ((destbuf - pDst + (runLength + 7)/8 + 4) <=
|
|
dstBufferSize)
|
|
goto ContinueFGBG;
|
|
else
|
|
DC_QUIT;
|
|
ContinueFGBG:
|
|
|
|
// We need to convert FGBG runs into the pixel form.
|
|
if (EncodeFGChar != match[0].fgChar) {
|
|
SETFGCHAR(match[0].fgChar, EncodeFGChar, fgShift);
|
|
ENCODE_ORDER_MEGA_FGBG(destbuf,
|
|
CODE_SET_FG_FG_BG,
|
|
runLength,
|
|
CODE_MEGA_MEGA_SET_FGBG,
|
|
MAX_LENGTH_FGBG_ORDER_LITE,
|
|
MAX_LENGTH_LONG_FGBG_ORDER);
|
|
*destbuf++ = EncodeFGChar;
|
|
TRC_DBG((TB, "SET_FG_FG_BG %u", match[0].length));
|
|
while (runLength >= 8) {
|
|
ENCODEFGBG(*destbuf);
|
|
destbuf++;
|
|
EncodeSrcOffset += 8;
|
|
runLength -= 8;
|
|
}
|
|
if (runLength) {
|
|
ENCODEFGBG(*destbuf);
|
|
|
|
// Keep the final partial byte clean to help GDC
|
|
// packing.
|
|
*destbuf &= ((0x01 << runLength) - 1);
|
|
destbuf++;
|
|
EncodeSrcOffset += runLength;
|
|
}
|
|
}
|
|
else {
|
|
if (runLength == 8) {
|
|
BYTE fgbgChar;
|
|
|
|
// See if it is one of the high probability bytes.
|
|
ENCODEFGBG(fgbgChar);
|
|
|
|
// Check for single byte encoding of FGBG images.
|
|
switch (fgbgChar) {
|
|
case SPECIAL_FGBG_CODE_1:
|
|
*destbuf++ = CODE_SPECIAL_FGBG_1;
|
|
break;
|
|
case SPECIAL_FGBG_CODE_2:
|
|
*destbuf++ = CODE_SPECIAL_FGBG_2;
|
|
break;
|
|
default:
|
|
ENCODE_ORDER_MEGA_FGBG(destbuf,
|
|
CODE_FG_BG_IMAGE,
|
|
runLength,
|
|
CODE_MEGA_MEGA_FGBG,
|
|
MAX_LENGTH_FGBG_ORDER,
|
|
MAX_LENGTH_LONG_FGBG_ORDER);
|
|
*destbuf++ = fgbgChar;
|
|
break;
|
|
}
|
|
EncodeSrcOffset += 8;
|
|
}
|
|
else {
|
|
// Encode as standard FGBG.
|
|
ENCODE_ORDER_MEGA_FGBG(destbuf,
|
|
CODE_FG_BG_IMAGE,
|
|
runLength,
|
|
CODE_MEGA_MEGA_FGBG,
|
|
MAX_LENGTH_FGBG_ORDER,
|
|
MAX_LENGTH_LONG_FGBG_ORDER);
|
|
TRC_DBG((TB, "FG_BG %u", match[0].length));
|
|
while (runLength >= 8) {
|
|
ENCODEFGBG(*destbuf);
|
|
destbuf++;
|
|
EncodeSrcOffset += 8;
|
|
runLength -= 8;
|
|
}
|
|
if (runLength) {
|
|
ENCODEFGBG(*destbuf);
|
|
*destbuf &= ((0x01 << runLength) - 1);
|
|
destbuf++;
|
|
EncodeSrcOffset += runLength;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case RUN_COLOR:
|
|
ENCODE_ORDER_MEGA(destbuf,
|
|
CODE_COLOR_RUN,
|
|
match[0].length,
|
|
CODE_MEGA_MEGA_COLOR_RUN,
|
|
MAX_LENGTH_ORDER,
|
|
MAX_LENGTH_LONG_ORDER);
|
|
TRC_DBG((TB, "COLOR_RUN %u", match[0].length));
|
|
*destbuf++ = pSrc[EncodeSrcOffset];
|
|
EncodeSrcOffset += match[0].length;
|
|
break;
|
|
|
|
case RUN_DITHER:
|
|
{
|
|
unsigned ditherlen = match[0].length / 2;
|
|
ENCODE_ORDER_MEGA(destbuf,
|
|
CODE_DITHERED_RUN,
|
|
ditherlen,
|
|
CODE_MEGA_MEGA_DITHER,
|
|
MAX_LENGTH_ORDER_LITE,
|
|
MAX_LENGTH_LONG_ORDER_LITE);
|
|
TRC_DBG((TB, "DITHERED_RUN %u", match[0].length));
|
|
|
|
// First check for our approaching the end of the
|
|
// destination buffer and get out if this is the case.
|
|
if ((unsigned)(destbuf - pDst + 2) <= dstBufferSize) {
|
|
*destbuf++ = pSrc[EncodeSrcOffset];
|
|
*destbuf++ = pSrc[EncodeSrcOffset + 1];
|
|
EncodeSrcOffset += match[0].length;
|
|
}
|
|
else {
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IMAGE_COLOR:
|
|
// Length 1 can possibly be encoded as a single BLACK/WHITE.
|
|
if (match[0].length == 1) {
|
|
if (pSrc[EncodeSrcOffset] == 0x00) {
|
|
*destbuf++ = CODE_BLACK;
|
|
EncodeSrcOffset++;
|
|
break;
|
|
}
|
|
if (pSrc[EncodeSrcOffset] == 0xFF) {
|
|
*destbuf++ = CODE_WHITE;
|
|
EncodeSrcOffset++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Store the data in non-compressed form.
|
|
ENCODE_ORDER_MEGA(destbuf,
|
|
CODE_COLOR_IMAGE,
|
|
match[0].length,
|
|
CODE_MEGA_MEGA_CLR_IMG,
|
|
MAX_LENGTH_ORDER,
|
|
MAX_LENGTH_LONG_ORDER);
|
|
TRC_DBG((TB, "COLOR_IMAGE %u", match[0].length));
|
|
|
|
// First check for our approaching the end of the
|
|
// destination buffer and get out if this is the case.
|
|
if ((destbuf - pDst + (UINT_PTR)match[0].length) <=
|
|
dstBufferSize) {
|
|
// Now just copy the data over.
|
|
memcpy(destbuf, pSrc+EncodeSrcOffset, match[0].length);
|
|
destbuf += match[0].length;
|
|
EncodeSrcOffset += match[0].length;
|
|
}
|
|
else {
|
|
DC_QUIT;
|
|
}
|
|
|
|
break;
|
|
|
|
#ifdef DC_DEBUG
|
|
default:
|
|
TRC_ERR((TB, "Invalid run type %u",match[0].type));
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************/
|
|
// Done encoding, what we do next is determined by whether we're
|
|
// flushing the match queue after everything is scanned.
|
|
/****************************************************************/
|
|
match[0] = match[1];
|
|
if (!bEncodeAllMatches) {
|
|
// Push the current run into the top of the queue.
|
|
match[1].type = bestRunType;
|
|
match[1].length = bestRunLength;
|
|
match[1].fgChar = fgChar;
|
|
}
|
|
else {
|
|
// We need to check to see if we're really finished. Since
|
|
// our maximum queue depth is 2, if we're done then the only
|
|
// remaining entry has an encoding type of 0.
|
|
if (match[0].type == 0) {
|
|
goto PostScan;
|
|
}
|
|
else {
|
|
match[1].type = 0;
|
|
goto DoEncoding;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (scanCount == 0) {
|
|
// If we have just done our scan of the first line then now do the
|
|
// rest of the buffer. Reset our saved pel count.
|
|
numPels = saveNumPels;
|
|
}
|
|
else {
|
|
// When we are done with the second pass (we've reached the end of
|
|
// the buffer) we have to force the remaining items in the match
|
|
// queue to be encoded. Yes this is similar to old BASIC
|
|
// code in using gotos, but we cannot place the encoding code into
|
|
// a function because of the number of params required, and
|
|
// we cannot duplicate it because it is too big. This code is
|
|
// some of the most used in the system so the cost is worth it.
|
|
bEncodeAllMatches = TRUE;
|
|
goto DoEncoding;
|
|
}
|
|
}
|
|
|
|
PostScan:
|
|
// Success, calculate the amount of space we used.
|
|
compressedLength = (unsigned)(destbuf - pDst);
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return compressedLength;
|
|
}
|
|
#endif
|
|
|
|
#ifdef DC_HICOLOR
|
|
/****************************************************************************/
|
|
/* Hi res color compression functions */
|
|
/****************************************************************************/
|
|
/****************************************************************************/
|
|
/* 15bpp version of CompressV2Int */
|
|
/****************************************************************************/
|
|
unsigned RDPCALL SHCLASS CompressV2Int15(PBYTE pSrc,
|
|
PBYTE pDst,
|
|
unsigned numBytes,
|
|
unsigned rowDelta,
|
|
unsigned dstBufferSize,
|
|
BYTE * xorbuf,
|
|
MATCH * match)
|
|
{
|
|
/****************************************************************************/
|
|
/* Function name */
|
|
/****************************************************************************/
|
|
#define BC_FN_NAME "CompressV2Int15"
|
|
|
|
/****************************************************************************/
|
|
/* Data type of a pixel */
|
|
/****************************************************************************/
|
|
#define BC_PIXEL TSUINT16
|
|
|
|
/****************************************************************************/
|
|
/* Length in bytes of a pixel */
|
|
/****************************************************************************/
|
|
#define BC_PIXEL_LEN 2
|
|
|
|
/****************************************************************************/
|
|
/* Default fgPel */
|
|
/****************************************************************************/
|
|
#define BC_DEFAULT_FGPEL 0x0000FF7F
|
|
|
|
/****************************************************************************/
|
|
/* Macro to move to the next pixel in the buffer (modifies pPos) */
|
|
/****************************************************************************/
|
|
#define BC_TO_NEXT_PIXEL(pPos) pPos += 2
|
|
|
|
/****************************************************************************/
|
|
/* Macro to returns the value of the pixel at pPos (doesn't modify pPos) */
|
|
/****************************************************************************/
|
|
#define BC_GET_PIXEL(pPos) ((TSUINT16) ((((PTSUINT8)(pPos))[1]) & 0x7f) | \
|
|
(TSUINT16) (((((PTSUINT8)(pPos))[0])) << 8) )
|
|
|
|
/****************************************************************************/
|
|
/* Macro to insert a pixel value pel at position pPos (doesn't modify pPos) */
|
|
/* */
|
|
/* pel may well be an expression (e.g. a BC_GET_PIXEL macro) so evaluate */
|
|
/* it once into a local variable. */
|
|
/****************************************************************************/
|
|
#define BC_SET_PIXEL(pPos, pel) \
|
|
{ \
|
|
BC_PIXEL val = pel; \
|
|
(((PTSUINT8)(pPos))[1]) = (TSUINT8)( (val) & 0x007F); \
|
|
(((PTSUINT8)(pPos))[0]) = (TSUINT8)(((val) >> 8) & 0x00FF); \
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Include the function body */
|
|
/****************************************************************************/
|
|
#include <abccom.c>
|
|
|
|
/****************************************************************************/
|
|
/* Undefine everything */
|
|
/****************************************************************************/
|
|
#undef BC_FN_NAME
|
|
#undef BC_PIXEL
|
|
#undef BC_PIXEL_LEN
|
|
#undef BC_TO_NEXT_PIXEL
|
|
#undef BC_GET_PIXEL
|
|
#undef BC_SET_PIXEL
|
|
#undef BC_DEFAULT_FGPEL
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* 16bpp version of CompressV2Int */
|
|
/****************************************************************************/
|
|
unsigned RDPCALL SHCLASS CompressV2Int16(PBYTE pSrc,
|
|
PBYTE pDst,
|
|
unsigned numBytes,
|
|
unsigned rowDelta,
|
|
unsigned dstBufferSize,
|
|
BYTE * xorbuf,
|
|
MATCH * match)
|
|
{
|
|
/****************************************************************************/
|
|
/* Function name */
|
|
/****************************************************************************/
|
|
#define BC_FN_NAME "CompressV2Int16"
|
|
|
|
/****************************************************************************/
|
|
/* Data type of a pixel */
|
|
/****************************************************************************/
|
|
#define BC_PIXEL TSUINT16
|
|
|
|
/****************************************************************************/
|
|
/* Length in bytes of a pixel */
|
|
/****************************************************************************/
|
|
#define BC_PIXEL_LEN 2
|
|
|
|
/****************************************************************************/
|
|
/* Default fgPel */
|
|
/****************************************************************************/
|
|
#define BC_DEFAULT_FGPEL 0x0000FFFF
|
|
|
|
/****************************************************************************/
|
|
/* Macro to move to the next pixel in the buffer (modifies pPos) */
|
|
/****************************************************************************/
|
|
#define BC_TO_NEXT_PIXEL(pPos) pPos += 2
|
|
|
|
/****************************************************************************/
|
|
/* Macro to returns the value of the pixel at pPos (doesn't modify pPos) */
|
|
/****************************************************************************/
|
|
#define BC_GET_PIXEL(pPos) ((TSUINT16) (((PTSUINT8)(pPos))[1]) | \
|
|
(TSUINT16) ((((PTSUINT8)(pPos))[0]) << 8) )
|
|
|
|
/****************************************************************************/
|
|
/* Macro to insert a pixel value pel at position pPos (doesn't modify pPos) */
|
|
/* */
|
|
/* pel may well be an expression (e.g. a BC_GET_PIXEL macro) so evaluate */
|
|
/* it once into a local variable. */
|
|
/****************************************************************************/
|
|
#define BC_SET_PIXEL(pPos, pel) \
|
|
{ \
|
|
BC_PIXEL val = pel; \
|
|
(((PTSUINT8)(pPos))[1]) = (TSUINT8)( (val) & 0x00FF); \
|
|
(((PTSUINT8)(pPos))[0]) = (TSUINT8)(((val)>>8) & 0x00FF); \
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Include the function body */
|
|
/****************************************************************************/
|
|
#include <abccom.c>
|
|
|
|
/****************************************************************************/
|
|
/* Undefine everything */
|
|
/****************************************************************************/
|
|
#undef BC_FN_NAME
|
|
#undef BC_PIXEL
|
|
#undef BC_PIXEL_LEN
|
|
#undef BC_TO_NEXT_PIXEL
|
|
#undef BC_GET_PIXEL
|
|
#undef BC_SET_PIXEL
|
|
#undef BC_DEFAULT_FGPEL
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* 24bpp version of CompressV2Int */
|
|
/****************************************************************************/
|
|
unsigned RDPCALL SHCLASS CompressV2Int24(PBYTE pSrc,
|
|
PBYTE pDst,
|
|
unsigned numBytes,
|
|
unsigned rowDelta,
|
|
unsigned dstBufferSize,
|
|
BYTE * xorbuf,
|
|
MATCH * match)
|
|
|
|
{
|
|
/****************************************************************************/
|
|
/* Function name */
|
|
/****************************************************************************/
|
|
#define BC_FN_NAME "CompressV2Int24"
|
|
|
|
/****************************************************************************/
|
|
/* Data type of a pixel */
|
|
/****************************************************************************/
|
|
#define BC_PIXEL TSUINT32
|
|
|
|
/****************************************************************************/
|
|
/* Length in bytes of a pixel */
|
|
/****************************************************************************/
|
|
#define BC_PIXEL_LEN 3
|
|
|
|
/****************************************************************************/
|
|
/* Default fgPel */
|
|
/****************************************************************************/
|
|
#define BC_DEFAULT_FGPEL 0x00FFFFFF
|
|
|
|
/****************************************************************************/
|
|
/* Macro to move to the next pixel in the buffer (modifies pPos) */
|
|
/****************************************************************************/
|
|
#define BC_TO_NEXT_PIXEL(pPos) pPos += 3
|
|
|
|
/****************************************************************************/
|
|
/* Macro to returns the value of the pixel at pPos (doesn't modify pPos) */
|
|
/****************************************************************************/
|
|
#define BC_GET_PIXEL(pPos) ((TSUINT32) (((PTSUINT8)(pPos))[2]) | \
|
|
(TSUINT32) ((((PTSUINT8)(pPos))[1]) << 8) | \
|
|
(TSUINT32) ((((PTSUINT8)(pPos))[0]) << 16) )
|
|
|
|
/****************************************************************************/
|
|
/* Macro to insert a pixel value pel at position pPos (doesn't modify pPos) */
|
|
/* */
|
|
/* pel may well be an expression (e.g. a BC_GET_PIXEL macro) so evaluate */
|
|
/* it once into a local variable. */
|
|
/****************************************************************************/
|
|
#define BC_SET_PIXEL(pPos, pel) \
|
|
{ \
|
|
BC_PIXEL val = pel; \
|
|
(((PTSUINT8)(pPos))[2]) = (TSUINT8)((val) & 0x000000FF); \
|
|
(((PTSUINT8)(pPos))[1]) = (TSUINT8)(((val)>>8) & 0x000000FF); \
|
|
(((PTSUINT8)(pPos))[0]) = (TSUINT8)(((val)>>16) & 0x000000FF); \
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Include the function body */
|
|
/****************************************************************************/
|
|
#include <abccom.c>
|
|
|
|
/****************************************************************************/
|
|
/* Undefine everything */
|
|
/****************************************************************************/
|
|
#undef BC_FN_NAME
|
|
#undef BC_PIXEL
|
|
#undef BC_PIXEL_LEN
|
|
#undef BC_TO_NEXT_PIXEL
|
|
#undef BC_GET_PIXEL
|
|
#undef BC_SET_PIXEL
|
|
#undef BC_DEFAULT_FGPEL
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* 32bpp version of CompressV2Int */
|
|
/****************************************************************************/
|
|
unsigned RDPCALL SHCLASS CompressV2Int32(PBYTE pSrc,
|
|
PBYTE pDst,
|
|
unsigned numBytes,
|
|
unsigned rowDelta,
|
|
unsigned dstBufferSize,
|
|
BYTE * xorbuf,
|
|
MATCH * match)
|
|
{
|
|
/****************************************************************************/
|
|
/* Function name */
|
|
/****************************************************************************/
|
|
#define BC_FN_NAME "CompressV2Int32"
|
|
|
|
/****************************************************************************/
|
|
/* Data type of a pixel */
|
|
/****************************************************************************/
|
|
#define BC_PIXEL TSUINT32
|
|
|
|
/****************************************************************************/
|
|
/* Length in bytes of a pixel */
|
|
/****************************************************************************/
|
|
#define BC_PIXEL_LEN 4
|
|
|
|
/****************************************************************************/
|
|
/* Default fgPel */
|
|
/****************************************************************************/
|
|
#define BC_DEFAULT_FGPEL 0xFFFFFFFF
|
|
|
|
/****************************************************************************/
|
|
/* Macro to move to the next pixel in the buffer (modifies pPos) */
|
|
/****************************************************************************/
|
|
#define BC_TO_NEXT_PIXEL(pPos) pPos += 4
|
|
|
|
/****************************************************************************/
|
|
/* Macro to returns the value of the pixel at pPos (doesn't modify pPos) */
|
|
/****************************************************************************/
|
|
#define BC_GET_PIXEL(pPos) ( \
|
|
(TSUINT32) ( (TSUINT16)(((PTSUINT8)(pPos))[3]) ) | \
|
|
(TSUINT32) (((TSUINT16)(((PTSUINT8)(pPos))[2])) << 8) | \
|
|
(TSUINT32) (((TSUINT32)(((PTSUINT8)(pPos))[1])) << 16) | \
|
|
(TSUINT32) (((TSUINT32)(((PTSUINT8)(pPos))[0])) << 24))
|
|
|
|
/****************************************************************************/
|
|
/* Macro to insert a pixel value pel at position pPos (doesn't modify pPos) */
|
|
/* */
|
|
/* pel may well be an expression (e.g. a BC_GET_PIXEL macro) so evaluate */
|
|
/* it once into a local variable. */
|
|
/****************************************************************************/
|
|
#define BC_SET_PIXEL(pPos, pel) \
|
|
{ \
|
|
BC_PIXEL val = pel; \
|
|
(((PTSUINT8)(pPos))[3]) = (TSUINT8)((val) & 0x000000FF); \
|
|
(((PTSUINT8)(pPos))[2]) = (TSUINT8)(((val)>>8) & 0x000000FF); \
|
|
(((PTSUINT8)(pPos))[1]) = (TSUINT8)(((val)>>16) & 0x000000FF); \
|
|
(((PTSUINT8)(pPos))[0]) = (TSUINT8)(((val)>>24) & 0x000000FF); \
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Include the function body */
|
|
/****************************************************************************/
|
|
#include <abccom.c>
|
|
|
|
/****************************************************************************/
|
|
/* Undefine everything */
|
|
/****************************************************************************/
|
|
#undef BC_FN_NAME
|
|
#undef BC_PIXEL
|
|
#undef BC_PIXEL_LEN
|
|
#undef BC_TO_NEXT_PIXEL
|
|
#undef BC_GET_PIXEL
|
|
#undef BC_SET_PIXEL
|
|
#undef BC_DEFAULT_FGPEL
|
|
}
|
|
|
|
#endif /* DC_HICOLOR */
|
|
|
|
#ifdef DC_DEBUG
|
|
// compression testing
|
|
#include <abdapi.c>
|
|
|
|
#endif
|