#include "types.h"

#include "tools.h"
#include "maths.h"
#include "maths3D.h"

#include "vdp.h"
#include "bitmap.h"

#include "vdp_tile.h"
#include "vdp_dma.h"
#include "vdp_pal.h"


u8 BitmapBuffer[BITMAP_PITCH * BITMAP_PIXHEIGHT];

u16 bitmap_width_tile;
u16 bitmap_height_tile;
u16 bitmap_width_pixel;
u16 bitmap_height_pixel;


void setBitmapMode(u16 w, u16 h)
{
    u16 i, j;
    u16 offset;
    u16 cellwidth;
    u16 cellheight;

    VDP_fillTileRect(BPLAN, 0, 0, 0, VDP_getPlanWidth(), VDP_getPlanHeight());

    if (w > BITMAP_WIDTH) w = BITMAP_WIDTH;
    if (h > BITMAP_HEIGHT) h = BITMAP_HEIGHT;

    bitmap_width_tile = w;
    bitmap_height_tile = h;
    bitmap_width_pixel = w * 4;
    bitmap_height_pixel = h * 8;

    cellwidth = VDP_getWidth() >> 3;
    cellheight = VDP_getHeight() >> 3;

    offset = TILE_BITMAPINDEX;
    for(j = 0; j < h; j++)
    {
        for(i = 0; i < w; i++)
        {
            VDP_setTile(BPLAN, offset, i + ((cellwidth - w) / 2), j + ((cellheight - h) / 2));
            offset++;
        }
        offset += BITMAP_WIDTH - w;
    }
}


void loadBitmap(const u32 *data, u16 x, u16 y, u16 w, u16 h, u16 pitch)
{
    volatile u32 *plctrl;
    volatile u32 *pldata;
    const u32 *src;
    u16 addr;
    u16 adjpitch;
    u16 i, j;

    VDP_setAutoInc(2);

    addr = TILE_BITMAP + ((x + (y * BITMAP_WIDTH)) * 32);
    src = data;
    adjpitch = pitch / 4;

    /* point to vdp port */
    plctrl = (u32 *) GFX_CTRL_PORT;
    pldata = (u32 *) GFX_DATA_PORT;

    i = h;
    while(i--)
    {
        *plctrl = GFX_WRITE_VRAM_ADDR(addr);

        j = w;
        while(j--)
        {
            const u32 *_src;

            _src = src;
            *pldata = *_src;
            _src += adjpitch;
            *pldata = *_src;
            _src += adjpitch;
            *pldata = *_src;
            _src += adjpitch;
            *pldata = *_src;
            _src += adjpitch;
            *pldata = *_src;
            _src += adjpitch;
            *pldata = *_src;
            _src += adjpitch;
            *pldata = *_src;
            _src += adjpitch;
            *pldata = *_src;
            src++;
        }

        addr += BITMAP_WIDTH * 32;
        src -= w;
        src += adjpitch * 8;
    }
}


void clearBitmapAll()
{
    clearBitmap(0, 0, bitmap_width_tile, bitmap_height_tile);
}

// ~70 bytes per scanline
void clearBitmap(u16 x, u16 y, u16 w, u16 h)
{
    u32 *src;
    u32 adjpitch;
    u16 i, j;

    src = (u32 *) (&BitmapBuffer[(x * 4) + (y * 8 * BITMAP_PITCH)]);
    adjpitch = (BITMAP_WIDTH - w) + ((BITMAP_PITCH * 7) / 4);

    i = h;
    while(i--)
    {
        j = w;
        while(j--)
        {
            src[(BITMAP_PITCH * 0) / 4] = 0;
            src[(BITMAP_PITCH * 1) / 4] = 0;
            src[(BITMAP_PITCH * 2) / 4] = 0;
            src[(BITMAP_PITCH * 3) / 4] = 0;
            src[(BITMAP_PITCH * 4) / 4] = 0;
            src[(BITMAP_PITCH * 5) / 4] = 0;
            src[(BITMAP_PITCH * 6) / 4] = 0;
            src[(BITMAP_PITCH * 7) / 4] = 0;
            src++;
        }
        src += adjpitch;
    }
}

void blitBitmapAll()
{
    blitBitmap(0, 0, bitmap_width_tile, bitmap_height_tile);
}

// ~70 bytes per scanline (during blanking)
void blitBitmap(u16 x, u16 y, u16 w, u16 h)
{
    volatile u32 *plctrl;
    volatile u32 *pldata;
    u32 *src;
    u16 addr;
    u32 adjpitch;
    u16 i, j;

    VDP_setAutoInc(2);

    addr = TILE_BITMAP + ((x + (y * BITMAP_WIDTH)) * 32);
    src = (u32 *) (&BitmapBuffer[(x * 4) + (y * 8 * BITMAP_PITCH)]);
    adjpitch = (BITMAP_WIDTH - w) + ((BITMAP_PITCH * 7) / 4);

    /* Point to vdp port */
    plctrl = (u32 *) GFX_CTRL_PORT;
    pldata = (u32 *) GFX_DATA_PORT;

    i = h;
    while(i--)
    {
        *plctrl = GFX_WRITE_VRAM_ADDR(addr);

        j = w;
        while(j--)
        {
            *pldata = src[(BITMAP_PITCH * 0) / 4];
            *pldata = src[(BITMAP_PITCH * 1) / 4];
            *pldata = src[(BITMAP_PITCH * 2) / 4];
            *pldata = src[(BITMAP_PITCH * 3) / 4];
            *pldata = src[(BITMAP_PITCH * 4) / 4];
            *pldata = src[(BITMAP_PITCH * 5) / 4];
            *pldata = src[(BITMAP_PITCH * 6) / 4];
            *pldata = src[(BITMAP_PITCH * 7) / 4];
            src++;
        }

        addr += BITMAP_WIDTH * 32;
        src += adjpitch;
    }
}

void blitAndClearBitmapAll()
{
    blitAndClearBitmap(0, 0, bitmap_width_tile, bitmap_height_tile);
}

// ~36 bytes per scanline (during blanking)
void blitAndClearBitmap(u16 x, u16 y, u16 w, u16 h)
{
    volatile u32 *plctrl;
    volatile u32 *pldata;
    u32 *src;
    u16 addr;
    u32 adjpitch;
    u16 i, j;

    VDP_setAutoInc(2);

    addr = TILE_BITMAP + ((x + (y * BITMAP_WIDTH)) * 32);
    src = (u32 *) (&BitmapBuffer[(x * 4) + (y * 8 * BITMAP_PITCH)]);
    adjpitch = (BITMAP_WIDTH - w) + ((BITMAP_PITCH * 7) / 4);

    /* Point to vdp port */
    plctrl = (u32 *) GFX_CTRL_PORT;
    pldata = (u32 *) GFX_DATA_PORT;

    i = h;
    while(i--)
    {
        *plctrl = GFX_WRITE_VRAM_ADDR(addr);

        j = w;
        while(j--)
        {
            *pldata = src[(BITMAP_PITCH * 0) / 4];
            src[(BITMAP_PITCH * 0) / 4] = 0;
            *pldata = src[(BITMAP_PITCH * 1) / 4];
            src[(BITMAP_PITCH * 1) / 4] = 0;
            *pldata = src[(BITMAP_PITCH * 2) / 4];
            src[(BITMAP_PITCH * 2) / 4] = 0;
            *pldata = src[(BITMAP_PITCH * 3) / 4];
            src[(BITMAP_PITCH * 3) / 4] = 0;
            *pldata = src[(BITMAP_PITCH * 4) / 4];
            src[(BITMAP_PITCH * 4) / 4] = 0;
            *pldata = src[(BITMAP_PITCH * 5) / 4];
            src[(BITMAP_PITCH * 5) / 4] = 0;
            *pldata = src[(BITMAP_PITCH * 6) / 4];
            src[(BITMAP_PITCH * 6) / 4] = 0;
            *pldata = src[(BITMAP_PITCH * 7) / 4];
            src[(BITMAP_PITCH * 7) / 4] = 0;
            src++;
        }

        addr += BITMAP_WIDTH * 32;
        src += adjpitch;
    }
}


void loadGenBmp16ToBitmap(const u16 *genbmp16, u16 x, u16 y, u16 loadpalto)
{
    u32 w, h;

    // get the image width
    w = genbmp16[0];
    // get the image height
    h = genbmp16[1];

    // we load the palette
    if (loadpalto < 4) VDP_setPalette(loadpalto, &genbmp16[2]);

    // &data[18] is (u32*)
    loadBitmap((u32*) &genbmp16[18], x, y, w / 8, h / 8, w / 2);
}

void getGenBmp16Palette(const u16 *genbmp16, u16 *pal)
{
    u16 i;
    const u16 *src;
    u16 *dst;

    src = &genbmp16[2];
    dst = pal;
    i = 16;
    while(i--) *dst++ = *src++;
}

