+#include "Desaturate.h"
+
+#include <stdexcept>
+
+using std::runtime_error;
+
+
+namespace sdl {
+
+template<typename SrcType, typename DestType>
+void DesaturatePixel(
+ SrcType *src, SDL_PixelFormat *srcFmt,
+ DestType *dest, SDL_PixelFormat *destFmt,
+ Uint8 amount) {
+
+ Uint8 srcRed = (((*src) & srcFmt->Rmask)
+ >> srcFmt->Rshift) << srcFmt->Rloss;
+ Uint8 srcGreen = (((*src) & srcFmt->Gmask)
+ >> srcFmt->Gshift) << srcFmt->Gloss;
+ Uint8 srcBlue = (((*src) & srcFmt->Bmask)
+ >> srcFmt->Bshift) << srcFmt->Bloss;
+
+ Uint8 srcGrey = (srcRed * 76 + srcGreen * 150 + srcBlue * 29) / 255;
+
+ Uint8 destRed = (srcRed * amount + srcGrey * (255 - amount)) / 255;
+ Uint8 destGreen = (srcGreen * amount + srcGrey * (255 - amount)) / 255;
+ Uint8 destBlue = (srcBlue * amount + srcGrey * (255 - amount)) / 255;
+
+ *dest
+ = ((destRed >> destFmt->Rloss) << destFmt->Rshift)
+ | ((destGreen >> destFmt->Gloss) << destFmt->Gshift)
+ | ((destBlue >> destFmt->Bloss) << destFmt->Bshift)
+ | (*dest & destFmt->Amask);
+}
+
+void Desaturate(
+ SDL_Surface *src,
+ SDL_Surface *dest,
+ Uint8 amount) {
+ Uint32 size = src->w * src->h;
+ SDL_LockSurface(src);
+ SDL_LockSurface(dest);
+ SDL_PixelFormat *srcFmt = src->format;
+ SDL_PixelFormat *destFmt = dest->format;
+ Uint8 srcBPP = srcFmt->BytesPerPixel;
+ Uint8 destBPP = destFmt->BytesPerPixel;
+ switch (srcBPP) {
+ default:
+ SDL_UnlockSurface(dest);
+ SDL_UnlockSurface(src);
+ throw runtime_error("unable to read src format");
+ case 2: {
+ Uint16 *srcIter = reinterpret_cast<Uint16 *>(
+ src->pixels);
+ Uint16 *srcEnd = srcIter + size;
+ switch (destBPP) {
+ default:
+ SDL_UnlockSurface(dest);
+ SDL_UnlockSurface(src);
+ throw runtime_error("unable to read src format");
+ case 2: {
+ Uint16 *destIter = reinterpret_cast<Uint16 *>(
+ dest->pixels);
+ Uint16 *destEnd = destIter + size;
+ for (;srcIter < srcEnd && destIter < destEnd;
+ ++srcIter, ++destIter) {
+ DesaturatePixel(
+ srcIter, srcFmt,
+ destIter, destFmt,
+ amount);
+ }
+ break; }
+ case 4: {
+ Uint32 *destIter = reinterpret_cast<Uint32 *>(
+ dest->pixels);
+ Uint32 *destEnd = destIter + size;
+ for (;srcIter < srcEnd && destIter < destEnd;
+ ++srcIter, ++destIter) {
+ DesaturatePixel(
+ srcIter, srcFmt,
+ destIter, destFmt,
+ amount);
+ }
+ break; }
+ }
+ break; }
+ case 4: {
+ Uint32 *srcIter = reinterpret_cast<Uint32 *>(
+ src->pixels);
+ Uint32 *srcEnd = srcIter + size;
+ switch (destBPP) {
+ default:
+ SDL_UnlockSurface(dest);
+ SDL_UnlockSurface(src);
+ throw runtime_error("unable to read src format");
+ case 2: {
+ Uint16 *destIter = reinterpret_cast<Uint16 *>(
+ dest->pixels);
+ Uint16 *destEnd = destIter + size;
+ for (;srcIter < srcEnd && destIter < destEnd;
+ ++srcIter, ++destIter) {
+ DesaturatePixel(
+ srcIter, srcFmt,
+ destIter, destFmt,
+ amount);
+ }
+ break; }
+ case 4: {
+ Uint32 *destIter = reinterpret_cast<Uint32 *>(
+ dest->pixels);
+ Uint32 *destEnd = destIter + size;
+ for (;srcIter < srcEnd && destIter < destEnd;
+ ++srcIter, ++destIter) {
+ DesaturatePixel(
+ srcIter, srcFmt,
+ destIter, destFmt,
+ amount);
+ }
+ break; }
+ }
+ break; }
+ }
+ SDL_UnlockSurface(dest);
+ SDL_UnlockSurface(src);
+}
+
+}