#ifndef GFX_PS1_H
#define GFX_PS1_H

#include <util.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
#endif

/*   0-3   Texture page X Base   (N*64) (ie. in 64-halfword steps)    ;GPUSTAT.0-3
  4     Texture page Y Base   (N*256) (ie. 0 or 256)               ;GPUSTAT.4
  5-6   Semi Transparency     (0=B/2+F/2, 1=B+F, 2=B-F, 3=B+F/4)   ;GPUSTAT.5-6
  7-8   Texture page colors   (0=4bit, 1=8bit, 2=15bit, 3=Reserved);GPUSTAT.7-8
  9     Dither 24bit to 15bit (0=Off/strip LSBs, 1=Dither Enabled) ;GPUSTAT.9
  10    Drawing to display area (0=Prohibited, 1=Allowed)          ;GPUSTAT.10
  11    Texture Disable (0=Normal, 1=Disable if GP1(09h).Bit0=1)   ;GPUSTAT.15
          (Above might be chipselect for (absent) second VRAM chip?)
  12    Textured Rectangle X-Flip   (BIOS does set this bit on power-up...?)
  13    Textured Rectangle Y-Flip   (BIOS does set it equal to GPUSTAT.13...?)
  14-23 Not used (should be 0)
  24-31 Command  (E1h)*/
union gfx_common
{
    struct
    {
        uint32_t tpagex :4;
        uint32_t tpagey :1;
        uint32_t stp :2;
        uint32_t bpp :2;
        uint32_t dither :1;
        uint32_t draw_to_disp :1;
        uint32_t disable :1;
        uint32_t xflip :1;
        uint32_t yflip :1;
        uint32_t :10;
        uint8_t cmd;
    } f;

    uint32_t mask;
};

union gfx_sznext
{
    struct
    {
        uint32_t next :24;
        uint32_t sz :8;
    } f;

    uint32_t cmd_next;
};

struct sprite
{
    union gfx_sznext sznext;
    union gfx_common common;
    uint8_t r, g, b;
    uint8_t cmd;
    int16_t x, y;
    uint8_t u, v;
    uint16_t clutid;
    uint16_t w, h;
};

struct quad
{
    union gfx_sznext sznext;
    uint8_t r, g, b;
    uint8_t cmd;
    int16_t x0, y0;
    uint8_t u0, v0;
    uint16_t clutid;
    int16_t x1, y1;
    uint8_t u1, v1;

    union
    {
        struct
        {
            /* 0-8 Same as GP0(E1h).Bit0-8. */
            uint16_t lb :9;
            uint16_t :2;
            /* 11 Same as GP0(E1h).Bit11. */
            uint16_t hb :1;
            uint16_t :4;
        } bit;

        uint16_t mask;
    } tpage;

    int16_t x2, y2;
    uint8_t u2, v2;
    uint16_t :16;
    int16_t x3, y3;
    uint8_t u3, v3;
    uint16_t :16;
};

struct rect
{
    union gfx_sznext sznext;
    union gfx_common common;
    uint8_t r, g, b;
    uint8_t cmd;
    int16_t x, y;
    uint16_t w, h;
};

struct stp_4line
{
    union gfx_sznext sznext;
    union gfx_common common;
    uint8_t r, g, b;
    uint8_t cmd;
    int16_t x, y;

    struct stp_4line_vtx
    {
        uint32_t r :8;
        uint32_t g :8;
        uint32_t b :8;
        uint32_t :8;

        int16_t x, y;
    } vertices[4];

    uint32_t end;
};

#define common_get_or_ret(t, x, ret) \
    struct t *x = t##_get(); \
    if (!x) return ret

struct sprite *sprite_get(void);
struct quad *quad_get(void);
struct rect *rect_get(void);
struct stp_4line *stp_4line_get(void);

int sprite_from_file_ex(const char *path, struct sprite *s);

#define sprite_from_file(path, s) sprite_from_file_ex("cdrom:\\"path";1", s)

#ifdef __cplusplus
}
#endif

#endif /* GFX_PS1_H */
