#include <gfx.h>
#include <gfx_private.h>
#include <ps1/gfx_private.h>
#include <system/port.h>
#include <psxgpu.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

static union gfx_sznext *first, *last;

static void add_to_list(union gfx_sznext *const p)
{
    if (!first)
        first = p;
    else if (last)
        last->f.next = (uint32_t)p;

    last = p;
}

int sprite_sort(struct sprite *const s)
{
    add_to_list(&s->sznext);
    return 0;
}

int quad_sort(struct quad *const q)
{
    add_to_list(&q->sznext);
    return 0;
}

int rect_sort(struct rect *const r)
{
    add_to_list(&r->sznext);
    return 0;
}

int stp_4line_sort(struct stp_4line *const l)
{
    add_to_list(&l->sznext);
    return 0;
}

static void gfx_sync(void)
{
    /* Wait for the GPU to finish drawing primitives. */
    while (!(GPU_CONTROL_PORT & (1 << 0x1a)))
        ;

    /* Wait for the GPU to be free. */
	while (!(GPU_CONTROL_PORT & (1 << 0x1c)))
        ;

    while (!vblank_set)
        ;

    vblank_set = false;
}

int gfx_draw(void)
{
    static union gfx_sznext term = {.cmd_next = 0xffffff};

    add_to_list(&term);

    void gpu_ctrl(unsigned command, unsigned param);

    gfx_sync();
    gfx_swapbuffers();
    gfx_swapheap();
    gpu_ctrl(4, 2);
    D2_MADR = (uint32_t)first;
	D2_BCR = 0;
	D2_CHCR = (1 << 0xa) | 1 | (1 << 0x18);
    first = NULL;
    return 0;
}
