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.
399 lines
12 KiB
399 lines
12 KiB
/**************************************************************************\
|
|
*
|
|
* Copyright (c) 2000 Microsoft Corporation
|
|
*
|
|
* Module name:
|
|
*
|
|
* The "Dither" scan operation.
|
|
*
|
|
* Abstract:
|
|
*
|
|
* See Gdiplus\Specs\ScanOperation.doc for an overview.
|
|
*
|
|
* Notes:
|
|
*
|
|
* Revision History:
|
|
*
|
|
* 01/19/2000 andrewgo
|
|
* Created it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hpp"
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Operation Description:
|
|
*
|
|
* Dither: Dither from 32bpp ARGB to 16bpp.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* dst - The destination scan
|
|
* src - The source scan (32bpp ARGB)
|
|
* count - The length of the scan, in pixels
|
|
* otherParams - Additional data. (We use X and Y.)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None
|
|
*
|
|
* Notes:
|
|
*
|
|
* Special cases which alpha-blend and dither in one step, should probably
|
|
* go in this file, but be named e.g. Blend_sRGB_565_Dithered.
|
|
*
|
|
* History:
|
|
*
|
|
* 01/19/2000 andrewgo
|
|
* Created it.
|
|
* 01/19/2000 agodfrey
|
|
* Stashed it here for the time being.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
UINT32 Saturate5Bit[] = { 0, 1, 2, 3, 4, 5, 6, 7,
|
|
8, 9, 10, 11, 12, 13, 14, 15,
|
|
16, 17, 18, 19, 20, 21, 22, 23,
|
|
24, 25, 26, 27, 28, 29, 30, 31,
|
|
31 };
|
|
|
|
UINT32 Saturate6Bit[] = { 0, 1, 2, 3, 4, 5, 6, 7,
|
|
8, 9, 10, 11, 12, 13, 14, 15,
|
|
16, 17, 18, 19, 20, 21, 22, 23,
|
|
24, 25, 26, 27, 28, 29, 30, 31,
|
|
32, 33, 34, 35, 36, 37, 38, 39,
|
|
40, 41, 42, 43, 44, 45, 46, 47,
|
|
48, 49, 50, 51, 52, 53, 54, 55,
|
|
56, 57, 58, 59, 60, 61, 62, 63,
|
|
63 };
|
|
|
|
UINT32 Dither5BitR[16] = { 0x00000000, 0x00040000, 0x00010000, 0x00050000,
|
|
0x00060000, 0x00020000, 0x00070000, 0x00030000,
|
|
0x00010000, 0x00050000, 0x00000000, 0x00040000,
|
|
0x00070000, 0x00030000, 0x00060000, 0x00020000 };
|
|
|
|
UINT32 Dither5BitG[16] = { 0x00000000, 0x00000400, 0x00000100, 0x00000500,
|
|
0x00000600, 0x00000200, 0x00000700, 0x00000300,
|
|
0x00000100, 0x00000500, 0x00000000, 0x00000400,
|
|
0x00000700, 0x00000300, 0x00000600, 0x00000200 };
|
|
|
|
UINT32 Dither6BitG[16] = { 0x00000000, 0x00000200, 0x00000000, 0x00000200,
|
|
0x00000300, 0x00000100, 0x00000300, 0x00000100,
|
|
0x00000000, 0x00000200, 0x00000000, 0x00000200,
|
|
0x00000300, 0x00000100, 0x00000300, 0x00000100 };
|
|
|
|
UINT32 Dither5BitB[16] = { 0x00000000, 0x00000004, 0x00000001, 0x00000005,
|
|
0x00000006, 0x00000002, 0x00000007, 0x00000003,
|
|
0x00000001, 0x00000005, 0x00000000, 0x00000004,
|
|
0x00000007, 0x00000003, 0x00000006, 0x00000002 };
|
|
|
|
// The following 'Dither565' and 'Dither555' matrices are 4 by 4
|
|
// arrays for adding straight to an ARGB dword value. Every row
|
|
// is repeated to allow us to do 128-bit reads with wrapping.
|
|
|
|
UINT32 Dither565[32] = { 0x00000000, 0x00040204, 0x00010001, 0x00050205,
|
|
0x00000000, 0x00040204, 0x00010001, 0x00050205,
|
|
0x00060306, 0x00020102, 0x00070307, 0x00030103,
|
|
0x00060306, 0x00020102, 0x00070307, 0x00030103,
|
|
0x00010001, 0x00050205, 0x00000000, 0x00040204,
|
|
0x00010001, 0x00050205, 0x00000000, 0x00040204,
|
|
0x00070307, 0x00030103, 0x00060306, 0x00020102,
|
|
0x00070307, 0x00030103, 0x00060306, 0x00020102 };
|
|
|
|
UINT32 Dither555[32] = { 0x00000000, 0x00040404, 0x00010101, 0x00050505,
|
|
0x00000000, 0x00040404, 0x00010101, 0x00050505,
|
|
0x00060606, 0x00020202, 0x00070707, 0x00030303,
|
|
0x00060606, 0x00020202, 0x00070707, 0x00030303,
|
|
0x00010101, 0x00050505, 0x00000000, 0x00040404,
|
|
0x00010101, 0x00050505, 0x00000000, 0x00040404,
|
|
0x00070707, 0x00030303, 0x00060606, 0x00020202,
|
|
0x00070707, 0x00030303, 0x00060606, 0x00020202 };
|
|
|
|
// The 'DitherNone' matrix allows us to disable dithering in a dithering
|
|
// routine:
|
|
|
|
UINT32 DitherNone[4] = { 0, 0, 0, 0 };
|
|
|
|
// Dither to 16bpp 565
|
|
|
|
VOID FASTCALL
|
|
ScanOperation::Dither_sRGB_565(
|
|
VOID *dst,
|
|
const VOID *src,
|
|
INT count,
|
|
const OtherParams *otherParams
|
|
)
|
|
{
|
|
// Since the MMX versions easily handle both dithering and non-dithering,
|
|
// it makes it simpler if all the 16bpp functions handle both.
|
|
|
|
if (!otherParams->DoingDither)
|
|
{
|
|
Quantize_sRGB_565(dst, src, count, otherParams);
|
|
return;
|
|
}
|
|
|
|
DEFINE_POINTERS(ARGB, WORD);
|
|
|
|
ASSERT(count != 0);
|
|
ASSERT(otherParams);
|
|
|
|
INT x = otherParams->X;
|
|
INT y = otherParams->Y;
|
|
|
|
// !!![andrewgo] Are we getting the window-relative (x, y)? (Don't think so!)
|
|
|
|
INT startDitherIndex = (y & 3) * 4;
|
|
|
|
do {
|
|
UINT32 src = *s;
|
|
x = (x & 3) + startDitherIndex;
|
|
|
|
*d = (WORD)
|
|
(Saturate5Bit[((src & 0xff0000) + Dither5BitR[x]) >> 19] << 11) +
|
|
(Saturate6Bit[((src & 0x00ff00) + Dither6BitG[x]) >> 10] << 5) +
|
|
(Saturate5Bit[((src & 0x0000ff) + Dither5BitB[x]) >> 3]);
|
|
|
|
s++;
|
|
d++;
|
|
x++;
|
|
} while (--count != 0);
|
|
}
|
|
|
|
// Dither to 16bpp 555
|
|
|
|
VOID FASTCALL
|
|
ScanOperation::Dither_sRGB_555(
|
|
VOID *dst,
|
|
const VOID *src,
|
|
INT count,
|
|
const OtherParams *otherParams
|
|
)
|
|
{
|
|
// Since the MMX versions easily handle both dithering and non-dithering,
|
|
// it makes it simpler if all the 16bpp functions handle both.
|
|
|
|
if (!otherParams->DoingDither)
|
|
{
|
|
Quantize_sRGB_555(dst, src, count, otherParams);
|
|
return;
|
|
}
|
|
|
|
DEFINE_POINTERS(ARGB, WORD);
|
|
|
|
ASSERT(count != 0);
|
|
ASSERT(otherParams);
|
|
|
|
INT x = otherParams->X;
|
|
INT y = otherParams->Y;
|
|
|
|
INT startDitherIndex = (y & 3) * 4;
|
|
|
|
do {
|
|
UINT32 src = *s;
|
|
x = (x & 3) + startDitherIndex;
|
|
|
|
*d = (WORD)
|
|
(Saturate5Bit[((src & 0xff0000) + Dither5BitR[x]) >> 19] << 10) +
|
|
(Saturate5Bit[((src & 0x00ff00) + Dither5BitG[x]) >> 11] << 5) +
|
|
(Saturate5Bit[((src & 0x0000ff) + Dither5BitB[x]) >> 3]);
|
|
|
|
s++;
|
|
d++;
|
|
x++;
|
|
} while (--count != 0);
|
|
}
|
|
|
|
// Blend from sRGB to 16bpp 565, with dithering.
|
|
|
|
VOID FASTCALL
|
|
ScanOperation::Dither_Blend_sRGB_565(
|
|
VOID *dst,
|
|
const VOID *src,
|
|
INT count,
|
|
const OtherParams *otherParams
|
|
)
|
|
{
|
|
// Since the MMX versions easily handle both dithering and non-dithering,
|
|
// it makes it simpler if all the 16bpp functions handle both.
|
|
|
|
if (!otherParams->DoingDither)
|
|
{
|
|
Blend_sRGB_565(dst, src, count, otherParams);
|
|
return;
|
|
}
|
|
|
|
DEFINE_POINTERS(UINT16, UINT16)
|
|
DEFINE_BLEND_POINTER(ARGB)
|
|
|
|
ASSERT(count>0);
|
|
|
|
INT x = otherParams->X;
|
|
INT y = otherParams->Y;
|
|
|
|
INT startDitherIndex = (y & 3) * 4;
|
|
|
|
do {
|
|
UINT32 blendPixel = *bl;
|
|
UINT32 alpha = blendPixel >> 24;
|
|
x = (x & 3) + startDitherIndex;
|
|
|
|
if (alpha != 0)
|
|
{
|
|
UINT32 srcPixel;
|
|
UINT r, g, b;
|
|
|
|
r = blendPixel & 0xff0000;
|
|
g = blendPixel & 0x00ff00;
|
|
b = blendPixel & 0x0000ff;
|
|
|
|
if (alpha != 255)
|
|
{
|
|
srcPixel = *s;
|
|
|
|
UINT sr = (srcPixel >> 11) & 0x1f;
|
|
UINT sg = (srcPixel >> 5) & 0x3f;
|
|
UINT sb = (srcPixel ) & 0x1f;
|
|
|
|
sr = (sr << 3) | (sr >> 2);
|
|
sg = (sg << 2) | (sg >> 4);
|
|
sb = (sb << 3) | (sb >> 2);
|
|
|
|
//
|
|
// Dst = B + (1-Alpha) * S
|
|
//
|
|
|
|
ULONG Multa = 255 - alpha;
|
|
ULONG _D1_000000GG = sg;
|
|
ULONG _D1_00RR00BB = sb | (sr << 16);
|
|
|
|
ULONG _D2_0000GGGG = _D1_000000GG * Multa + 0x00000080;
|
|
ULONG _D2_RRRRBBBB = _D1_00RR00BB * Multa + 0x00800080;
|
|
|
|
ULONG _D3_000000GG = (_D2_0000GGGG & 0x0000ff00) >> 8;
|
|
ULONG _D3_00RR00BB = (_D2_RRRRBBBB & 0xff00ff00) >> 8;
|
|
|
|
ULONG _D4_0000GG00 = (_D2_0000GGGG + _D3_000000GG) & 0x0000FF00;
|
|
ULONG _D4_00RR00BB = ((_D2_RRRRBBBB + _D3_00RR00BB) & 0xFF00FF00) >> 8;
|
|
|
|
r += _D4_00RR00BB; // The BB part will be shifted off
|
|
g += _D4_0000GG00;
|
|
b += _D4_00RR00BB & 0x0000ff;
|
|
}
|
|
|
|
*d = (WORD)
|
|
(Saturate5Bit[(r + Dither5BitR[x]) >> 19] << 11) +
|
|
(Saturate6Bit[(g + Dither6BitG[x]) >> 10] << 5) +
|
|
(Saturate5Bit[(b + Dither5BitB[x]) >> 3]);
|
|
}
|
|
|
|
bl++;
|
|
s++;
|
|
d++;
|
|
x++;
|
|
} while (--count != 0);
|
|
}
|
|
|
|
// Blend from sRGB to 16bpp 555, with dithering.
|
|
|
|
VOID FASTCALL
|
|
ScanOperation::Dither_Blend_sRGB_555(
|
|
VOID *dst,
|
|
const VOID *src,
|
|
INT count,
|
|
const OtherParams *otherParams
|
|
)
|
|
{
|
|
// Since the MMX versions easily handle both dithering and non-dithering,
|
|
// it makes it simpler if all the 16bpp functions handle both.
|
|
|
|
if (!otherParams->DoingDither)
|
|
{
|
|
Blend_sRGB_555(dst, src, count, otherParams);
|
|
return;
|
|
}
|
|
|
|
DEFINE_POINTERS(UINT16, UINT16)
|
|
DEFINE_BLEND_POINTER(ARGB)
|
|
|
|
ASSERT(count>0);
|
|
|
|
INT x = otherParams->X;
|
|
INT y = otherParams->Y;
|
|
|
|
INT startDitherIndex = (y & 3) * 4;
|
|
|
|
do {
|
|
UINT32 blendPixel = *bl;
|
|
UINT32 alpha = blendPixel >> 24;
|
|
x = (x & 3) + startDitherIndex;
|
|
|
|
if (alpha != 0)
|
|
{
|
|
UINT32 srcPixel;
|
|
UINT r, g, b;
|
|
|
|
r = blendPixel & 0xff0000;
|
|
g = blendPixel & 0x00ff00;
|
|
b = blendPixel & 0x0000ff;
|
|
|
|
if (alpha != 255)
|
|
{
|
|
srcPixel = *s;
|
|
|
|
UINT sr = (srcPixel >> 10) & 0x1f;
|
|
UINT sg = (srcPixel >> 5) & 0x1f;
|
|
UINT sb = (srcPixel ) & 0x1f;
|
|
|
|
sr = (sr << 3) | (sr >> 2);
|
|
sg = (sg << 3) | (sg >> 2);
|
|
sb = (sb << 3) | (sb >> 2);
|
|
|
|
//
|
|
// Dst = B + (1-Alpha) * S
|
|
//
|
|
|
|
ULONG Multa = 255 - alpha;
|
|
ULONG _D1_000000GG = sg;
|
|
ULONG _D1_00RR00BB = sb | (sr << 16);
|
|
|
|
ULONG _D2_0000GGGG = _D1_000000GG * Multa + 0x00000080;
|
|
ULONG _D2_RRRRBBBB = _D1_00RR00BB * Multa + 0x00800080;
|
|
|
|
ULONG _D3_000000GG = (_D2_0000GGGG & 0x0000ff00) >> 8;
|
|
ULONG _D3_00RR00BB = (_D2_RRRRBBBB & 0xff00ff00) >> 8;
|
|
|
|
ULONG _D4_0000GG00 = (_D2_0000GGGG + _D3_000000GG) & 0x0000FF00;
|
|
ULONG _D4_00RR00BB = ((_D2_RRRRBBBB + _D3_00RR00BB) & 0xFF00FF00) >> 8;
|
|
|
|
r += _D4_00RR00BB; // The BB part will be shifted off
|
|
g += _D4_0000GG00;
|
|
b += _D4_00RR00BB & 0x0000ff;
|
|
}
|
|
|
|
*d = (WORD)
|
|
(Saturate5Bit[(r + Dither5BitR[x]) >> 19] << 10) +
|
|
(Saturate5Bit[(g + Dither5BitG[x]) >> 11] << 5) +
|
|
(Saturate5Bit[(b + Dither5BitB[x]) >> 3]);
|
|
}
|
|
|
|
bl++;
|
|
s++;
|
|
d++;
|
|
x++;
|
|
} while (--count != 0);
|
|
}
|
|
|
|
// Generate 555 versions of the routines defined in 'sodither.inc'
|
|
|
|
#define DITHER_BLEND_555 1
|
|
|
|
#include "SODither.inc"
|
|
|
|
// Generate 565 versions of the routines defined in 'sodither.inc'
|
|
|
|
#undef DITHER_BLEND_555
|
|
#define DITHER_BLEND_555 0
|
|
|
|
#include "SODither.inc"
|