worked on Error diffusion dithering algorithm, but it doesn't end up looking much better than OrderedDither
This commit is contained in:
@@ -352,6 +352,7 @@ retry:
|
|||||||
PixFmtMasks[pixfmt].masks[2], PixFmtMasks[pixfmt].masks[3]);
|
PixFmtMasks[pixfmt].masks[2], PixFmtMasks[pixfmt].masks[3]);
|
||||||
|
|
||||||
SM_SDL_OrderedDither(img, dst);
|
SM_SDL_OrderedDither(img, dst);
|
||||||
|
//SM_SDL_ErrorDiffusionDither(img, dst);
|
||||||
SDL_FreeSurface(img);
|
SDL_FreeSurface(img);
|
||||||
img = dst;
|
img = dst;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,13 @@
|
|||||||
|
|
||||||
#define DitherMatDim 4
|
#define DitherMatDim 4
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Added error-diffusion algorithm. (SM_SDL_ErrorDiffusionDither)
|
||||||
|
Error distributed per-row, left to right.
|
||||||
|
http://www.gamasutra.com/features/19990521/pixel_conversion_03.htm
|
||||||
|
*/
|
||||||
|
|
||||||
/* Fractions, 0/16 to 15/16: */
|
/* Fractions, 0/16 to 15/16: */
|
||||||
static const int DitherMat[DitherMatDim][DitherMatDim] =
|
static const int DitherMat[DitherMatDim][DitherMatDim] =
|
||||||
{
|
{
|
||||||
@@ -122,3 +129,71 @@ void SM_SDL_OrderedDither(const SDL_Surface *src, SDL_Surface *dst)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define CLAMP(x, l, h) {if (x > h) x = h; else if (x < l) x = l;}
|
||||||
|
|
||||||
|
void SM_SDL_ErrorDiffusionDither(const SDL_Surface *src, SDL_Surface *dst)
|
||||||
|
{
|
||||||
|
/* We can't dither to paletted surfaces. */
|
||||||
|
ASSERT(dst->format->BytesPerPixel > 1);
|
||||||
|
|
||||||
|
/* For each row: */
|
||||||
|
for(int row = 0; row < src->h; ++row)
|
||||||
|
{
|
||||||
|
Sint32 accumError[4] = { 0, 0, 0, 0 }; // accum error values are reset every row
|
||||||
|
|
||||||
|
const Uint8 *srcp = (const Uint8 *)src->pixels + row * src->pitch;
|
||||||
|
Uint8 *dstp = (Uint8 *)dst->pixels + row * dst->pitch;
|
||||||
|
|
||||||
|
/* For each pixel in row: */
|
||||||
|
for(int col = 0; col < src->w; ++col)
|
||||||
|
{
|
||||||
|
Uint8 originalColors[4];
|
||||||
|
mySDL_GetRGBAV(srcp, src, originalColors);
|
||||||
|
|
||||||
|
Uint8 colorsPlusError[4];
|
||||||
|
int c;
|
||||||
|
for(c = 0; c < 4; ++c)
|
||||||
|
{
|
||||||
|
// move some error to the new pixel (without overflowing)
|
||||||
|
Sint32 errorToAdd;
|
||||||
|
if( accumError[c] >= 0 )
|
||||||
|
errorToAdd = min( accumError[c], (Sint32)255 - originalColors[c] );
|
||||||
|
else
|
||||||
|
errorToAdd = max( accumError[c], (Sint32)-originalColors[c] );
|
||||||
|
|
||||||
|
colorsPlusError[c] = (Uint8)(originalColors[c] + errorToAdd);
|
||||||
|
accumError[c] -= errorToAdd;
|
||||||
|
|
||||||
|
// make sure we didn't overflow
|
||||||
|
ASSERT( (Uint8)(originalColors[c] + errorToAdd) == (Sint32)(originalColors[c] + errorToAdd) );
|
||||||
|
|
||||||
|
}
|
||||||
|
mySDL_SetRGBAV(dstp, dst, colorsPlusError);
|
||||||
|
|
||||||
|
|
||||||
|
Uint8 ditheredColors[4];
|
||||||
|
mySDL_GetRGBAV(dstp, dst, ditheredColors);
|
||||||
|
|
||||||
|
for(c = 0; c < 4; ++c)
|
||||||
|
accumError[c] += originalColors[c] - ditheredColors[c];
|
||||||
|
|
||||||
|
/* Blank the alpha accumulated error.
|
||||||
|
* This has the effect of not dithering the alpha channel. */
|
||||||
|
accumError[3] = 0;
|
||||||
|
|
||||||
|
for(c = 0; c < 4; ++c)
|
||||||
|
{
|
||||||
|
// Reduce funky streaks in low-bit channels by clamping error.
|
||||||
|
CLAMP( accumError[c], -128, +128 );
|
||||||
|
|
||||||
|
// Keep only a fraction of the error to make the effect more subtle.
|
||||||
|
accumError[c] /= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
srcp += src->format->BytesPerPixel;
|
||||||
|
dstp += dst->format->BytesPerPixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,5 +2,6 @@
|
|||||||
#define SM_SDL_DITHER_H 1
|
#define SM_SDL_DITHER_H 1
|
||||||
|
|
||||||
void SM_SDL_OrderedDither(const SDL_Surface *src, SDL_Surface *dst);
|
void SM_SDL_OrderedDither(const SDL_Surface *src, SDL_Surface *dst);
|
||||||
|
void SM_SDL_ErrorDiffusionDither(const SDL_Surface *src, SDL_Surface *dst);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -107,6 +107,27 @@ void mySDL_GetRawRGBAV(const Uint8 *p, const SDL_Surface *src, Uint8 *v)
|
|||||||
mySDL_GetRawRGBAV(pixel, src, v);
|
mySDL_GetRawRGBAV(pixel, src, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mySDL_GetRGBAV(Uint32 pixel, const SDL_Surface *src, Uint8 *v)
|
||||||
|
{
|
||||||
|
mySDL_GetRawRGBAV(pixel, src, v);
|
||||||
|
const SDL_PixelFormat *fmt = src->format;
|
||||||
|
v[0] = v[0] << fmt->Rloss;
|
||||||
|
v[1] = v[1] << fmt->Gloss;
|
||||||
|
v[2] = v[2] << fmt->Bloss;
|
||||||
|
// Correct for surfaces that don't have an alpha channel.
|
||||||
|
if( fmt->Aloss == 8)
|
||||||
|
v[3] = 255;
|
||||||
|
else
|
||||||
|
v[3] = v[3] << fmt->Aloss;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mySDL_GetRGBAV(const Uint8 *p, const SDL_Surface *src, Uint8 *v)
|
||||||
|
{
|
||||||
|
Uint32 pixel = decodepixel(p, src->format->BytesPerPixel);
|
||||||
|
mySDL_GetRGBAV(pixel, src, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Inverse of mySDL_GetRawRGBAV. */
|
/* Inverse of mySDL_GetRawRGBAV. */
|
||||||
Uint32 mySDL_SetRawRGBAV(const SDL_PixelFormat *fmt, const Uint8 *v)
|
Uint32 mySDL_SetRawRGBAV(const SDL_PixelFormat *fmt, const Uint8 *v)
|
||||||
{
|
{
|
||||||
@@ -122,6 +143,22 @@ void mySDL_SetRawRGBAV(Uint8 *p, const SDL_Surface *src, const Uint8 *v)
|
|||||||
encodepixel(p, src->format->BytesPerPixel, pixel);
|
encodepixel(p, src->format->BytesPerPixel, pixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Inverse of mySDL_GetRGBAV. */
|
||||||
|
Uint32 mySDL_SetRGBAV(const SDL_PixelFormat *fmt, const Uint8 *v)
|
||||||
|
{
|
||||||
|
return (v[0] >> fmt->Rloss) << fmt->Rshift |
|
||||||
|
(v[1] >> fmt->Gloss) << fmt->Gshift |
|
||||||
|
(v[2] >> fmt->Bloss) << fmt->Bshift |
|
||||||
|
(v[3] >> fmt->Aloss) << fmt->Ashift;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mySDL_SetRGBAV(Uint8 *p, const SDL_Surface *src, const Uint8 *v)
|
||||||
|
{
|
||||||
|
Uint32 pixel = mySDL_SetRGBAV(src->format, v);
|
||||||
|
encodepixel(p, src->format->BytesPerPixel, pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Get the number of bits representing each color channel in fmt. */
|
/* Get the number of bits representing each color channel in fmt. */
|
||||||
void mySDL_GetBitsPerChannel(const SDL_PixelFormat *fmt, Uint32 bits[4])
|
void mySDL_GetBitsPerChannel(const SDL_PixelFormat *fmt, Uint32 bits[4])
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,9 +14,13 @@ void encodepixel(Uint8 *p, int bpp, Uint32 pixel);
|
|||||||
|
|
||||||
void mySDL_GetRawRGBAV(Uint32 pixel, const SDL_Surface *src, Uint8 *v);
|
void mySDL_GetRawRGBAV(Uint32 pixel, const SDL_Surface *src, Uint8 *v);
|
||||||
void mySDL_GetRawRGBAV(const Uint8 *p, const SDL_Surface *src, Uint8 *v);
|
void mySDL_GetRawRGBAV(const Uint8 *p, const SDL_Surface *src, Uint8 *v);
|
||||||
|
void mySDL_GetRGBAV(Uint32 pixel, const SDL_Surface *src, Uint8 *v);
|
||||||
|
void mySDL_GetRGBAV(const Uint8 *p, const SDL_Surface *src, Uint8 *v);
|
||||||
|
|
||||||
Uint32 mySDL_SetRawRGBAV(const SDL_PixelFormat *fmt, const Uint8 *v);
|
Uint32 mySDL_SetRawRGBAV(const SDL_PixelFormat *fmt, const Uint8 *v);
|
||||||
void mySDL_SetRawRGBAV(Uint8 *p, const SDL_Surface *src, const Uint8 *v);
|
void mySDL_SetRawRGBAV(Uint8 *p, const SDL_Surface *src, const Uint8 *v);
|
||||||
|
Uint32 mySDL_SetRGBAV(const SDL_PixelFormat *fmt, const Uint8 *v);
|
||||||
|
void mySDL_SetRGBAV(Uint8 *p, const SDL_Surface *src, const Uint8 *v);
|
||||||
|
|
||||||
void mySDL_GetBitsPerChannel(const SDL_PixelFormat *fmt, Uint32 bits[4]);
|
void mySDL_GetBitsPerChannel(const SDL_PixelFormat *fmt, Uint32 bits[4]);
|
||||||
void ConvertSDLSurface(SDL_Surface *&image,
|
void ConvertSDLSurface(SDL_Surface *&image,
|
||||||
|
|||||||
Reference in New Issue
Block a user