#include "types.h"

#include "vdp.h"
#include "vdp_tile.h"

#include "tools.h"
#include "vdp_dma.h"


// ~76 bytes per scanline in software (during blanking)
// ~190 bytes per scanline in hardware (during blanking)
void VDP_loadTileTo(const u32 *data, u16 index, u16 num, u8 use_dma)
{
    u16 addr;

    addr = index * 32;
    if (use_dma) VDP_DoVRamDMA((u32) data, addr, num * 32);
    else
    {
        volatile u32 *plctrl;
        volatile u32 *pldata;
        const u32 *src;
        u16 i;

        VDP_setAutoInc(2);

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

        *plctrl = GFX_WRITE_VRAM_ADDR(addr);

        src = data;

        i = num;
        while(i--)
        {
            *pldata = *src++;
            *pldata = *src++;
            *pldata = *src++;
            *pldata = *src++;
            *pldata = *src++;
            *pldata = *src++;
            *pldata = *src++;
            *pldata = *src++;
        }
    }
}


void VDP_loadTileTo2(const u8 *data, u16 index, u16 num, u8 use_dma)
{
    u16 addr;

    addr = index * 32;

        volatile u32 *plctrl;
        volatile u32 *pldata;
        const u8 *src;
        u16 i;

        VDP_setAutoInc(2);

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

        *plctrl = GFX_WRITE_VRAM_ADDR(addr);

        src = data;

        i = num;
        while(i--)
        {
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);
            *pldata = (*src++)*0x100+(*src++);            
        }

}

void VDP_loadFont(const u32 *font, u8 use_dma)
{
    VDP_loadTileTo(font, TILE_FONTINDEX, 128, use_dma);
}


void VDP_setTile(u16 plan, u16 tile, u16 x, u16 y)
{
    volatile u32 *plctrl;
    volatile u16 *pwdata;
    u32 addr;

    addr = plan + (2 * (x + (VDP_getPlanWidth() * y)));

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

    *plctrl = GFX_WRITE_VRAM_ADDR(addr);
    *pwdata = tile;
}

void VDP_fillTileRect(u16 plan, u16 tile, u16 x, u16 y, u16 w, u16 h)
{
    volatile u32 *plctrl;
    volatile u16 *pwdata;
    u32 addr;
    u32 planwidth;
    u16 i, j;

    VDP_setAutoInc(2);

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

    planwidth = VDP_getPlanWidth();
    addr = plan + (2 * (x + (planwidth * y)));

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

        j = w;
        while (j--) *pwdata = tile;

		addr += planwidth * 2;
	}
}

void VDP_fillTileRectInc(u16 plan, u16 basetile, u16 x, u16 y, u16 w, u16 h)
{
    volatile u32 *plctrl;
    volatile u16 *pwdata;
    u32 addr;
    u32 planwidth;
    u16 tile;
    u16 i, j;

    VDP_setAutoInc(2);

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

    planwidth = VDP_getPlanWidth();
    addr = plan + (2 * (x + (planwidth * y)));
    tile = basetile;

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

        j = w;
        while (j--) *pwdata = tile++;

		addr += planwidth * 2;
	}
}

void VDP_setTileRect(u16 plan, const u16 *data, u16 basetile, u16 x, u16 y, u16 w, u16 h)
{
    volatile u32 *plctrl;
    volatile u16 *pwdata;
    const u16 *src;
    u32 addr;
    u32 planwidth;
    u16 i, j;

    VDP_setAutoInc(2);

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

    planwidth = VDP_getPlanWidth();
    addr = plan + (2 * (x + (planwidth * y)));
    src = data;

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

        j = w;
        while (j--) *pwdata = basetile | *src++;

		addr += planwidth * 2;
	}
}


void VDP_drawText(u16 plan, const char *str, u16 basetile, u16 x, u16 y)
{
    u32 len;
    u16 data[40];
    u16 i;

    // get the horizontal plan size (in cell)
    i = VDP_getPlanWidth();
    len = strlen(str);

    // if string don't fit in plan, we cut it
    if (len > (i - x)) len = i - x;

    for (i = 0; i < len; i++) data[i] = TILE_FONTINDEX + (str[i] - 32);
    VDP_setTileRect(plan, data, basetile, x, y, len, 1);
}
