If you have comments or questions concerning this source file, discuss them in the forum.
/*
Copyright (c) 2002 Nicolai Haehnle

See the license.txt for details. If that file was not included in the
source distributions, please email <prefect@rtts.org>
*/
// hal.h -- abstract hardware interface layer classes

#include "keycodes.h"

/*
==============================================================================

HAL

==============================================================================
*/

#define __pic_alpha         1
#define __pic_maskonly      2
#define __pic_onlyalpha     4

#define __pic_colorkey      0x0100 // if RGB = colorkey A := 0
#define __pic_bitmask       0x0200 // create bitmask
#define __pic_redalpha      0x0400 // A := R; R,G,B := 1.0
#define __pic_palkey        0x0800 // palette entry 255 is transparent
#define __pic_nosubpixel    0x1000 // omit subpixel fixes; useful e.g. for HUD

#define __pic_formatmask    (__pic_alpha|__pic_maskonly|__pic_onlyalpha)

#define pic_normal          (0)
#define pic_colorkey        (__pic_colorkey)
#define pic_redalpha        (__pic_alpha|__pic_onlyalpha|__pic_redalpha)
#define pic_nosubpixel      (__pic_nosubpixel)

#define pic_bitmask         (__pic_bitmask)

typedef struct {
    void (*Key)(int code, char c, bool down);
    void (*MouseButton)(int btn, int x, int y, bool down);
    void (*MouseMove)(int x, int y);
    void (*QuitRequest)();
} hal_inputcb_t;

class HPicture;
class HFont;

class HAL {
    friend class HPicture;
    friend class HFont;

public:
    int     scrsize[2];
    int     framestart, frametime;

public:
    HAL();
    virtual ~HAL();

    virtual void Init() = 0;
    virtual void Shutdown() = 0;

    virtual void StartFrame() = 0;
    virtual void EndFrame() = 0;
    virtual void Input(const hal_inputcb_t *cb) = 0;
    virtual byte *GetKeyState() = 0;
    virtual unsigned GetMouseState(int *px, int *py) = 0;

    virtual void Ortho(int x, int y, int w, int h) = 0;
    virtual void SetDrawRect(int x, int y, int w, int h, int ofsx, int ofsy) = 0;

    virtual void SetAlphaOnly(bool on) = 0;

    virtual void FillRect(int x, int y, int w, int h, int r, int g, int b, int a = 255) = 0;
    virtual void DrawLine(float x1, float y1, float x2, float y2,
                int r, int g, int b, int a = 255) = 0;

    virtual byte *Screenshot(int *size) = 0;

private:
    virtual void LoadPicture(HPicture *pic) = 0;
    virtual void UnloadPicture(HPicture *pic) = 0;

public:
    static int  cachecycle;

    void CacheCycle();
};

extern HAL *hal; // there can only be one HAL

const char *HAL_NameForKey(int code);

void HAL_Start(LConfig *cfg);
void HAL_Shutdown();

void HAL_Screenshot(const char *basename);

byte *HAL_CanonicalBitmapLoad(const char *fname, int *size, int *ptype,
                                 unsigned int colorkey);

/*
==============================================================================

PICTURES / TEXTURES

==============================================================================
*/

class HPictureImpl {
public:
    HPicture    *m_pic;
public:
    HPictureImpl(HPicture *pic) { m_pic = pic; }
    virtual ~HPictureImpl() { }
    virtual void Draw(float dstx, float dsty, float srcx, float srcy, float w, float h,
                      int r, int g, int b, int a) = 0;
};

// HPicture is 'just' a shell around the implementation, which allows
// the implementation to be exchanged on-the-fly (think resolution changes)
class HPicture {
    friend class HAL;

public:
    HPictureImpl    *m_pImpl;   // filled in on load
    int             size[2];
    byte            *bitmask;

    int         m_iType;        // data needed to reload the picture
    u32         m_colorkey;
    char        m_szName[64];

private:
    static HPicture *m_pList;
    HPicture        **m_ppPrev;
    HPicture        *m_pNext;

    int             m_iUsed;
    int             m_iCacheCycle;

public:
    static HPicture *Get(const char *name, int type, u32 colorkey);

public:
    inline void AddRef() { m_iUsed++; }
    inline void Release() { m_iUsed--; }

    inline void Draw(float dstx, float dsty, int r = 255, int g = 255, int b = 255, int a = 255) {
        m_pImpl->Draw(dstx, dsty, 0, 0, size[0], size[1], r, g, b, a);
    }
    inline void DrawEx(float dstx, float dsty, float srcx, float srcy, float w, float h,
                int r = 255, int g = 255, int b = 255, int a = 255) {
        m_pImpl->Draw(dstx, dsty, srcx, srcy, w, h, r, g, b, a);
    }

    static void CacheCycle();
    static void UnloadAll();
    static void LoadAll();
    static void Cleanup();

private:
    HPicture(const char *name, int type, u32 colorkey);
    ~HPicture();

};


/*
==============================================================================

FONT

==============================================================================
*/

// it's arguable whether this belongs into the HAL.. I just left it there

#define halign_mask         0x3
#define halign_left         0x0
#define halign_center       0x1
#define halign_right        0x2

#define valign_mask         0xC
#define valign_top          0x0
#define valign_center       0x4
#define valign_bottom       0x8

#define align_wrap          0x10

class HFont {
    friend class HAL;

public:
    char    m_szName[64];

public:
    static HFont *Get(const char *name);

    inline void AddRef() { m_iUsed++; }
    inline void Release() { m_iUsed--; }

    virtual void CharRect(const char *string, int num,
                    int align, int width, int yspacing, LRect *rc) = 0;
    virtual void StringSize(const char *string, int width, int yspacing,
                    int *pw, int *ph) = 0;

    virtual void DrawChar(int dstx, int dsty, char c,
                    int r = 255, int g = 255, int b = 255, int a = 255) = 0;
    virtual void DrawString(int dstx, int dsty, const char *string,
                    int align, int width, int yspacing,
                    int r = 255, int g = 255, int b = 255, int a = 255) = 0;

public:
    HFont(const char *pszName);
    virtual ~HFont() = 0;

    static void CacheCycle();
    static void Cleanup();

    static HFont    *m_pList;
    HFont           **m_ppPrev;
    HFont           *m_pNext;

    int             m_iUsed;
    int             m_iCacheCycle;
};


/*
==============================================================================

SPRITES

==============================================================================
*/

#define MAX_ATTACHS         32
#define MAX_ANIMATIONS      8

typedef struct {
    int         id;
    float       offset[2];
} spr_attach_t;

typedef struct {
    HPicture        *pic;
    byte            r, g, b, a;
    float           offsets[2];
} spr_frame_t;

typedef struct {
    int         id;
    float       speed;
    int         numframes;
    spr_frame_t *frames;
} spr_animation_t;

typedef struct sprite_s {
    struct sprite_s **pprev, *next;
    int             used;
    int             cachecycle;

    char            name[64];

    float           mins[2];
    float           maxs[2];

    int             numattachs;
    spr_attach_t    attachs[MAX_ATTACHS];

    spr_animation_t base;

    int             numanims;
    spr_animation_t anims[MAX_ANIMATIONS];
} sprite_t;


sprite_t *SPR_Get(const char *name);
void SPR_Free(sprite_t *spr);

void SPR_Draw(sprite_t *spr, float scrx, float scry, int animnum, float curtime, int alpha = 255);
spr_attach_t *SPR_GetAttach(sprite_t *spr, int id);

// called internally:
void SPR_CacheCycle();
void SPR_Cleanup();