Some SDL source files: dithering routine, zoom routine and
misc. tools.
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "SDL.h"
|
||||
#include "SDL_dither.h"
|
||||
#include "SDL_utils.h"
|
||||
|
||||
#define DitherMatDim 4
|
||||
|
||||
/* Scale these to [0..1): */
|
||||
static const float DitherMatCalc[DitherMatDim][DitherMatDim] =
|
||||
{
|
||||
0/16., 8/16., 2/16., 10/16.,
|
||||
12/16., 4/16., 14/16., 6/16.,
|
||||
3/16., 11/16., 1/16., 9/16.,
|
||||
15/16., 7/16., 13/16., 5/16.
|
||||
};
|
||||
|
||||
/* conv is the ratio from the input to the output. */
|
||||
static Uint8 DitherPixel(int x, int y, int intensity, float conv)
|
||||
{
|
||||
/* The intensity matrix wraps. This assumes the matrix dims are a power of 2. */
|
||||
x &= DitherMatDim-1;
|
||||
y &= DitherMatDim-1;
|
||||
|
||||
/* Ordered dithering is scaling the old intensity range to the new, with
|
||||
* the matrix values biasing to rounding down or up. Matrix values are in
|
||||
* the range [0..1). For example, converting the 8-bit value 100 to 4
|
||||
* bits directly gives 6.25. A matrix value of 0 means the pixel is not
|
||||
* biased at all, which would cause it to be truncated to 6. A value
|
||||
* of 5/16 means that the value is biased to 6.5625, which is also truncated
|
||||
* to 6. A value of 15/16 biases to 6.1875, which causes it to be rounded
|
||||
* up to 6. So, a proportion of pixels gets rounded up based on how close
|
||||
* the number is to the next value. */
|
||||
|
||||
/* Convert the number to the destination range. */
|
||||
float out_intensity = intensity * conv;
|
||||
|
||||
/* Add bias. */
|
||||
out_intensity += DitherMatCalc[y][x];
|
||||
|
||||
/* Truncate, and add e to make sure a value of 14.999998 -> 15. */
|
||||
return Uint8(out_intensity + 0.00001f);
|
||||
}
|
||||
|
||||
void SM_SDL_OrderedDither(const SDL_Surface *src, SDL_Surface *dst)
|
||||
{
|
||||
/* We can't dither to paletted surfaces. */
|
||||
ASSERT(dst->format->BytesPerPixel > 1);
|
||||
|
||||
Uint32 src_cbits[4], dst_cbits[4];
|
||||
mySDL_GetBitsPerChannel(src->format, src_cbits);
|
||||
mySDL_GetBitsPerChannel(dst->format, dst_cbits);
|
||||
|
||||
/* Calculate the ratio from the old bit depth to the new for each color channel. */
|
||||
float conv[4];
|
||||
for(int i = 0; i < 4; ++i)
|
||||
{
|
||||
int MaxInputIntensity = (1 << src_cbits[i])-1;
|
||||
int MaxOutputIntensity = (1 << dst_cbits[i])-1;
|
||||
conv[i] = MaxOutputIntensity / float(MaxInputIntensity);
|
||||
}
|
||||
|
||||
/* For each row: */
|
||||
for(int row = 0; row < src->h; ++row) {
|
||||
const Uint8 *srcp = (const Uint8 *)src->pixels + row * src->pitch;
|
||||
Uint8 *dstp = (Uint8 *)dst->pixels + row * dst->pitch;
|
||||
|
||||
/* For each pixel: */
|
||||
for(int col = 0; col < src->w; ++col) {
|
||||
Uint8 colors[4];
|
||||
mySDL_GetRawRGBAV(srcp, src, colors);
|
||||
|
||||
/* Note that we don't dither the alpha channel. */
|
||||
for(int c = 0; c < 3; ++c) {
|
||||
/* If the destination has less bits, dither: */
|
||||
colors[c] = DitherPixel(col, row, colors[c], conv[c]);
|
||||
}
|
||||
|
||||
/* Convert the alpha channel, which we didn't dither. */
|
||||
colors[3] >>= src_cbits[3] - dst_cbits[3];
|
||||
|
||||
/* Raw value -> int -> pixel */
|
||||
mySDL_SetRawRGBAV(dstp, dst, colors);
|
||||
|
||||
srcp += src->format->BytesPerPixel;
|
||||
dstp += dst->format->BytesPerPixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef SM_SDL_DITHER_H
|
||||
#define SM_SDL_DITHER_H 1
|
||||
|
||||
void SM_SDL_OrderedDither(const SDL_Surface *src, SDL_Surface *dst);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef _SDL_rotozoom_h
|
||||
#define _SDL_rotozoom_h
|
||||
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
/* ---- Defines */
|
||||
|
||||
#define SMOOTHING_OFF 0
|
||||
#define SMOOTHING_ON 1
|
||||
|
||||
/* ---- Prototypes */
|
||||
|
||||
/*
|
||||
|
||||
rotozoomSurface()
|
||||
|
||||
Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
|
||||
'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
|
||||
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
|
||||
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
|
||||
|
||||
*/
|
||||
|
||||
SDL_Surface *rotozoomSurface (const SDL_Surface * src, double angle, double zoom,
|
||||
int smooth);
|
||||
|
||||
|
||||
/*
|
||||
|
||||
zoomSurface()
|
||||
|
||||
Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
|
||||
'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
|
||||
then the destination 32bit surface is anti-aliased. If the surface is not 8bit
|
||||
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
|
||||
|
||||
*/
|
||||
|
||||
SDL_Surface *zoomSurface (const SDL_Surface * src, double zoomx, double zoomy,
|
||||
int smooth);
|
||||
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _SDL_rotozoom_h */
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Various small SDL tools.
|
||||
*
|
||||
* Copyright (c) 2002 by the person(s) listed below. All rights reserved.
|
||||
* Glenn Maynard
|
||||
*
|
||||
* Portions from SDL source and documentation.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "SDL.h"
|
||||
#include "SDL_utils.h"
|
||||
#include "SDL_endian.h"
|
||||
|
||||
#if defined(WIN32)
|
||||
|
||||
/* Pull in all of our SDL libraries here. */
|
||||
#ifdef _DEBUG
|
||||
#pragma comment(lib, "SDL-1.2.5/lib/SDLd.lib")
|
||||
#else
|
||||
#pragma comment(lib, "SDL-1.2.5/lib/SDL.lib")
|
||||
#endif
|
||||
|
||||
#pragma comment(lib, "SDL_image-1.2/SDL_image.lib")
|
||||
|
||||
#endif
|
||||
|
||||
Uint32 mySDL_Swap24(Uint32 x)
|
||||
{
|
||||
return SDL_Swap32(x) >> 8; // xx223344 -> 443322xx -> 00443322
|
||||
}
|
||||
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
#define mySDL_SwapLE24(x) mySDL_Swap24(x)
|
||||
#else
|
||||
#define mySDL_SwapLE24(x) (x)
|
||||
#endif
|
||||
|
||||
/* These conditionals in the inner loop are slow. Templates? */
|
||||
Uint32 decodepixel(const Uint8 *p, int bpp)
|
||||
{
|
||||
switch(bpp) {
|
||||
case 1: return *p;
|
||||
case 2: return *(Uint16 *)p;
|
||||
case 3:
|
||||
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
|
||||
return p[0] << 16 | p[1] << 8 | p[2];
|
||||
else
|
||||
return p[0] | p[1] << 8 | p[2] << 16;
|
||||
|
||||
case 4: return *(Uint32 *)p;
|
||||
default: return 0; /* shouldn't happen, but avoids warnings */
|
||||
}
|
||||
}
|
||||
|
||||
void encodepixel(Uint8 *p, int bpp, Uint32 pixel)
|
||||
{
|
||||
switch(bpp) {
|
||||
case 1: *p = Uint8(pixel); break;
|
||||
case 2: *(Uint16 *)p = Uint16(pixel); break;
|
||||
case 3:
|
||||
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
|
||||
p[0] = Uint8((pixel >> 16) & 0xff);
|
||||
p[1] = Uint8((pixel >> 8) & 0xff);
|
||||
p[2] = Uint8(pixel & 0xff);
|
||||
} else {
|
||||
p[0] = Uint8(pixel & 0xff);
|
||||
p[1] = Uint8((pixel >> 8) & 0xff);
|
||||
p[2] = Uint8((pixel >> 16) & 0xff);
|
||||
}
|
||||
break;
|
||||
case 4: *(Uint32 *)p = pixel; break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get and set colors without scaling them to 0..255. Get them into
|
||||
* an array, which is much easier to work with. We need the surface
|
||||
* to get at flags, or we won't know if colorkey is valid. (Why isn't
|
||||
* format self-contained?) Use mySDL_GetBitsPerChannel() to get the
|
||||
* number of bits per channel. */
|
||||
void mySDL_GetRawRGBAV(Uint32 pixel, const SDL_Surface *src, Uint8 *v)
|
||||
{
|
||||
const SDL_PixelFormat *fmt = src->format;
|
||||
if(src->format->BytesPerPixel == 1) {
|
||||
v[0] = fmt->palette->colors[pixel].r;
|
||||
v[1] = fmt->palette->colors[pixel].g;
|
||||
v[2] = fmt->palette->colors[pixel].b;
|
||||
v[3] = 0xFF;
|
||||
} else {
|
||||
v[0] = Uint8((pixel & fmt->Rmask) >> fmt->Rshift);
|
||||
v[1] = Uint8((pixel & fmt->Gmask) >> fmt->Gshift);
|
||||
v[2] = Uint8((pixel & fmt->Bmask) >> fmt->Bshift);
|
||||
v[3] = Uint8((pixel & fmt->Amask) >> fmt->Ashift);
|
||||
}
|
||||
|
||||
if(src->flags & SDL_SRCCOLORKEY) {
|
||||
if((fmt->colorkey & ~fmt->Amask) == (pixel & ~fmt->Amask))
|
||||
v[3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void mySDL_GetRawRGBAV(const Uint8 *p, const SDL_Surface *src, Uint8 *v)
|
||||
{
|
||||
Uint32 pixel = decodepixel(p, src->format->BytesPerPixel);
|
||||
mySDL_GetRawRGBAV(pixel, src, v);
|
||||
}
|
||||
|
||||
/* Inverse of mySDL_GetRawRGBAV. */
|
||||
Uint32 mySDL_SetRawRGBAV(const SDL_PixelFormat *fmt, const Uint8 *v)
|
||||
{
|
||||
return v[0] << fmt->Rshift |
|
||||
v[1] << fmt->Gshift |
|
||||
v[2] << fmt->Bshift |
|
||||
v[3] << fmt->Ashift;
|
||||
}
|
||||
|
||||
void mySDL_SetRawRGBAV(Uint8 *p, const SDL_Surface *src, const Uint8 *v)
|
||||
{
|
||||
Uint32 pixel = mySDL_SetRawRGBAV(src->format, v);
|
||||
encodepixel(p, src->format->BytesPerPixel, pixel);
|
||||
}
|
||||
|
||||
/* Get the number of bits representing each color channel in fmt. */
|
||||
void mySDL_GetBitsPerChannel(const SDL_PixelFormat *fmt, Uint32 bits[4])
|
||||
{
|
||||
if(fmt->BytesPerPixel == 1) {
|
||||
/* If we're paletted, the palette is 8888. For some reason, the
|
||||
* *loss values are all 8 on paletted surfaces; they should be
|
||||
* 0, to represent the palette. Since they're not, we have to
|
||||
* special case this. */
|
||||
bits[0] = bits[1] = bits[2] = bits[3] = 8;
|
||||
return;
|
||||
}
|
||||
|
||||
/* The actual bits stored in each color is 8-loss. */
|
||||
bits[0] = 8 - fmt->Rloss;
|
||||
bits[1] = 8 - fmt->Gloss;
|
||||
bits[2] = 8 - fmt->Bloss;
|
||||
bits[3] = 8 - fmt->Aloss;
|
||||
}
|
||||
|
||||
void ConvertSDLSurface(SDL_Surface *&image,
|
||||
int width, int height, int bpp,
|
||||
Uint32 R, Uint32 G, Uint32 B, Uint32 A)
|
||||
{
|
||||
SDL_Surface *ret_image = SDL_CreateRGBSurfaceSane(
|
||||
SDL_SWSURFACE, width, height, bpp, R, G, B, A);
|
||||
ASSERT(ret_image != NULL);
|
||||
|
||||
/* If the formats are the same, no conversion is needed. */
|
||||
if(width == image->w && height == image->h &&
|
||||
!memcmp(image->format, ret_image->format, sizeof(SDL_PixelFormat)))
|
||||
{
|
||||
SDL_FreeSurface(ret_image);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(image->flags & SDL_SRCCOLORKEY)) // XXX until HOT PINK color keys are gone
|
||||
SDL_SetColorKey( image, SDL_SRCCOLORKEY, SDL_MapRGB(image->format, 0xFF, 0, 0xFF));
|
||||
|
||||
/* We don't want to actually blend the alpha channel over the destination converted
|
||||
* surface; we want to simply blit it, so make sure SDL_SRCALPHA is not on. */
|
||||
SDL_SetAlpha( image, 0, SDL_ALPHA_OPAQUE );
|
||||
|
||||
SDL_Rect area;
|
||||
area.x = area.y = 0;
|
||||
area.w = short(image->w);
|
||||
area.h = short(image->h);
|
||||
|
||||
SDL_BlitSurface(image, &area, ret_image, &area);
|
||||
SDL_FreeSurface(image);
|
||||
image = ret_image;
|
||||
}
|
||||
|
||||
/* With d3d, textures are stored little endian (local endian for x86).
|
||||
*
|
||||
* I'm not sure if we should store textures in big endian, little endian
|
||||
* or local endian with OpenGL. It doesn't really impact anything except
|
||||
* the actual code that loads the texture itself, and OpenGL does have
|
||||
* byte order toggles, so maybe we can get rid of this. */
|
||||
SDL_Surface *SDL_CreateRGBSurfaceSane
|
||||
(Uint32 flags, int width, int height, int depth,
|
||||
Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
|
||||
{
|
||||
/* This is untested on big-endian machines. */
|
||||
if(depth == 16) {
|
||||
Rmask = SDL_SwapLE16((Uint16)Rmask);
|
||||
Gmask = SDL_SwapLE16((Uint16)Gmask);
|
||||
Bmask = SDL_SwapLE16((Uint16)Bmask);
|
||||
Amask = SDL_SwapLE16((Uint16)Amask);
|
||||
} else if(depth == 24) { // completely untested
|
||||
Rmask = mySDL_SwapLE24(Rmask);
|
||||
Gmask = mySDL_SwapLE24(Gmask);
|
||||
Bmask = mySDL_SwapLE24(Bmask);
|
||||
Amask = mySDL_SwapLE24(Amask);
|
||||
} else if(depth == 32) {
|
||||
Rmask = SDL_SwapLE32(Rmask);
|
||||
Gmask = SDL_SwapLE32(Gmask);
|
||||
Bmask = SDL_SwapLE32(Bmask);
|
||||
Amask = SDL_SwapLE32(Amask);
|
||||
}
|
||||
|
||||
return SDL_CreateRGBSurface(flags, width, height, depth,
|
||||
Rmask, Gmask, Bmask, Amask);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef SM_SDL_UTILS
|
||||
#define SM_SDL_UTILS 1
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
Uint32 decodepixel(const Uint8 *p, int bpp);
|
||||
void encodepixel(Uint8 *p, int bpp, Uint32 pixel);
|
||||
|
||||
void mySDL_GetRawRGBAV(Uint32 pixel, const SDL_Surface *src, Uint8 *v);
|
||||
void mySDL_GetRawRGBAV(const Uint8 *p, const SDL_Surface *src, 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_GetBitsPerChannel(const SDL_PixelFormat *fmt, Uint32 bits[4]);
|
||||
void ConvertSDLSurface(SDL_Surface *&image,
|
||||
int width, int height, int bpp,
|
||||
Uint32 R, Uint32 G, Uint32 B, Uint32 A);
|
||||
SDL_Surface *SDL_CreateRGBSurfaceSane
|
||||
(Uint32 flags, int width, int height, int depth,
|
||||
Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user