From 3f2648011ff12b3e555851bd6d16a372b55261ac Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Thu, 24 Oct 2002 03:38:23 +0000 Subject: [PATCH] Some SDL source files: dithering routine, zoom routine and misc. tools. --- stepmania/src/SDL_dither.cpp | 89 +++++++++++++++ stepmania/src/SDL_dither.h | 6 + stepmania/src/SDL_rotozoom.h | 54 +++++++++ stepmania/src/SDL_utils.cpp | 206 +++++++++++++++++++++++++++++++++++ stepmania/src/SDL_utils.h | 24 ++++ 5 files changed, 379 insertions(+) create mode 100644 stepmania/src/SDL_dither.cpp create mode 100644 stepmania/src/SDL_dither.h create mode 100644 stepmania/src/SDL_rotozoom.h create mode 100644 stepmania/src/SDL_utils.cpp create mode 100644 stepmania/src/SDL_utils.h diff --git a/stepmania/src/SDL_dither.cpp b/stepmania/src/SDL_dither.cpp new file mode 100644 index 0000000000..e91c1e77a3 --- /dev/null +++ b/stepmania/src/SDL_dither.cpp @@ -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; + } + } +} diff --git a/stepmania/src/SDL_dither.h b/stepmania/src/SDL_dither.h new file mode 100644 index 0000000000..82243904cc --- /dev/null +++ b/stepmania/src/SDL_dither.h @@ -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 diff --git a/stepmania/src/SDL_rotozoom.h b/stepmania/src/SDL_rotozoom.h new file mode 100644 index 0000000000..2fd5953981 --- /dev/null +++ b/stepmania/src/SDL_rotozoom.h @@ -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 */ diff --git a/stepmania/src/SDL_utils.cpp b/stepmania/src/SDL_utils.cpp new file mode 100644 index 0000000000..1fc8e149c3 --- /dev/null +++ b/stepmania/src/SDL_utils.cpp @@ -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); +} diff --git a/stepmania/src/SDL_utils.h b/stepmania/src/SDL_utils.h new file mode 100644 index 0000000000..80859120c5 --- /dev/null +++ b/stepmania/src/SDL_utils.h @@ -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 +