module saurus.sdl; import derelict.sdl.sdl; private import derelict.sdl.image; private import derelict.sdl.ttf; private import saurus.drawing; private import std.stdio; private abstract class SDLObject { protected bool finalized; private static SDLObject[SDLObject] objects; this() { finalized = false; objects[this] = this; } static void finalizeAll() { foreach (SDLObject object; objects) { if (!object.finalized) { object.finalize(); assert(object.finalized == true); } delete objects[object]; } } abstract void finalize(); } static this() { DerelictSDL_Load(); if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { throw new Error("SDL_Init failed."); } DerelictSDLImage_Load(); DerelictSDLttf_Load(); if (TTF_Init() < 0) { throw new Error("TTF_Init failed."); } } static ~this() { SDLObject.finalizeAll(); TTF_Quit(); SDL_Quit(); } class Surface : SDLObject { private SDL_Surface* surface; this(SDL_Surface* surface) { this.surface = surface; } this(char[] name) { this(IMG_Load(name ~ "\0")); } this(int w, int h, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) { this(SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, depth, Rmask, Gmask, Bmask, Amask)); } protected void finalize() { assert(!finalized); SDL_FreeSurface(surface); surface = null; finalized = true; } invariant { if (finalized) { assert(surface == null); } else { assert(surface != null); assert(surface.refcount == 1); } } SDL_Surface* get() { return surface; } Point size() { return new Point(surface.w, surface.h); } void fill(Colour colour = null, Rect rect = null) { if (colour is null) { if (rect is null) { SDL_FillRect(surface, null, 0); } else { SDL_Rect r; r.x = cast(Sint16) rect.x; r.y = cast(Sint16)rect.y; r.w = cast(Uint16)rect.w; r.h = cast(Uint16)rect.h; SDL_FillRect(surface, &r, 0); } } else { Uint32 col = SDL_MapRGB(surface.format, colour.r, colour.g, colour.b); if (rect is null) { SDL_FillRect(surface, null, col); } else { SDL_Rect r; r.x = cast(Sint16) rect.x; r.y = cast(Sint16)rect.y; r.w = cast(Uint16)rect.w; r.h = cast(Uint16)rect.h; SDL_FillRect(surface, &r, col); } } } void blit(Surface src, Point topLeft) { SDL_Rect r; r.x = cast(Sint16) topLeft.x; r.y = cast(Sint16) topLeft.y; SDL_BlitSurface(src.get(), null, surface, &r); } ubyte* lock() { if (SDL_LockSurface(surface) < 0) { throw new Error("SDL_LockSurface failed."); } return cast(ubyte*) surface.pixels; } void unlock() { SDL_UnlockSurface(surface); } int pitch() { return surface.pitch; } Surface convert(int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) { Surface surfaceWithTheFormatWeWant = new Surface(1, 1, depth, Rmask, Gmask, Bmask, Amask); SDL_PixelFormat format = *(surfaceWithTheFormatWeWant.surface.format); delete surfaceWithTheFormatWeWant; return new Surface(SDL_ConvertSurface(surface, &format, SDL_SWSURFACE)); } } class Screen : Surface { this(int w, int h, int bpp, Uint32 flags) { super(SDL_SetVideoMode(w, h, bpp, flags)); } void flip() { SDL_Flip(get()); } } class Font : SDLObject { TTF_Font* font; this(TTF_Font* font) { this.font = font; } this(char[] name, int size) { this(TTF_OpenFont(name ~ "\0", size)); } void finalize() { assert(!finalized); TTF_CloseFont(font); font = null; finalized = true; } invariant { if (finalized) { assert(font == null); } else { assert(font != null); } } Surface render(wchar[] text, Colour colour) { SDL_Color col; col.r = colour.r; col.g = colour.g; col.b = colour.b; col.unused = colour.a; SDL_Surface* s = TTF_RenderUNICODE_Blended(font, cast(ushort*) (text ~ "\0"), col); return new Surface(s); } }