Skip to content

Instantly share code, notes, and snippets.

@Jakz
Created January 15, 2015 15:32
Show Gist options
  • Save Jakz/da135795a24d0382881e to your computer and use it in GitHub Desktop.
Save Jakz/da135795a24d0382881e to your computer and use it in GitHub Desktop.
#include <type_traits>
#include <cstring>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
enum GfxBufferFormat
{
FORMAT_XRGB888,
FORMAT_RGB565,
FORMAT_RGBA5551,
FORMAT_RGBA8888,
};
struct GfxBuffer
{
u16 width;
u16 height;
u8* data;
};
struct Offset
{
u16 x;
u16 y;
};
struct SDL_Surface
{
void* pixels;
u16 w;
u16 h;
};
void SDL_LockSurface(SDL_Surface* surface) { }
void SDL_UnlockSurface(SDL_Surface* surface) { }
class Blitter
{
protected:
template<typename T>
inline void rawBlit(SDL_Surface *dest, const GfxBuffer &buffer, const Offset &offset)
{
SDL_LockSurface(dest);
T *p = static_cast<T*>(dest->pixels) + offset.x + offset.y*dest->w;
T *sp = reinterpret_cast<T*>(buffer.data);
for (int i = 0; i < buffer.height; ++i)
memcpy(p+(i*dest->w), sp+i*buffer.width, sizeof(T)*buffer.width);
SDL_UnlockSurface(dest);
}
public:
Blitter() { }
virtual void blit(const GfxBuffer& buffer, const Offset& offset, SDL_Surface* dest) = 0;
virtual ~Blitter() { }
};
template<GfxBufferFormat FROM, GfxBufferFormat TO>
class FormatBlitter : public Blitter
{
private:
typedef typename std::conditional<FROM == FORMAT_XRGB888 || FROM == FORMAT_RGBA8888, u32, u16>::type pixel_from;
typedef typename std::conditional<TO == FORMAT_XRGB888 || TO == FORMAT_RGBA8888, u32, u16>::type pixel_to;
public:
void blit(const GfxBuffer& buffer, const Offset& offset, SDL_Surface* dest)
{
SDL_LockSurface(dest);
pixel_to* d = reinterpret_cast<pixel_to*>(dest->pixels) + offset.x + offset.y*dest->w;
pixel_from* s = reinterpret_cast<pixel_from*>(buffer.data);
for (int y = 0; y < buffer.height; ++y)
{
pixel_to* bd = d + y*dest->w;
pixel_from* bs = s + y*buffer.width;
for (int x = 0; x < buffer.width; ++x, ++bd, ++bs)
*bd = convert(*bs);
}
SDL_UnlockSurface(dest);
}
template< bool cond, typename U > using conversion_type = typename std::enable_if<cond, U >::type;
template<GfxBufferFormat F = FROM>
static inline conversion_type<F == FORMAT_XRGB888 && TO == FORMAT_RGB565, pixel_to> convert(pixel_from c)
{
u8 r = (c >> 16) / 8;
u8 g = ((c >> 8) & 0xFF) / 4;
u8 b = ((c) & 0xFF) / 8;
return (r << 11) | (g << 5) | b;
}
template<GfxBufferFormat F = FROM>
static inline conversion_type<F == FORMAT_XRGB888 && TO == FORMAT_RGBA8888, pixel_to> convert(pixel_from c)
{
return c << 8;
}
};
template<>
inline void FormatBlitter<FORMAT_RGB565, FORMAT_RGB565>::blit(const GfxBuffer &buffer, const Offset &offset, SDL_Surface *dest)
{
rawBlit<u16>(dest, buffer, offset);
}
template<>
inline void FormatBlitter<FORMAT_RGBA5551, FORMAT_RGBA5551>::blit(const GfxBuffer &buffer, const Offset &offset, SDL_Surface *dest)
{
rawBlit<u16>(dest, buffer, offset);
}
template<>
inline void FormatBlitter<FORMAT_RGBA8888, FORMAT_RGBA8888>::blit(const GfxBuffer &buffer, const Offset &offset, SDL_Surface *dest)
{
rawBlit<u32>(dest, buffer, offset);
}
int main(void)
{
SDL_Surface *dest = new SDL_Surface();
dest->pixels = new u16[32*24];
dest->w = 32;
dest->h = 24;
GfxBuffer src = {20,20,new u8[20*20*sizeof(u32)]};
Offset offset = {5,5};
Blitter* blitter = new FormatBlitter<FORMAT_XRGB888, FORMAT_RGB565>();
blitter->blit(src, offset, dest);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment