246 lines
4.5 KiB
C
246 lines
4.5 KiB
C
#include <gfx.h>
|
|
#include <ps1/gfx_private.h>
|
|
#include <psxgpu.h>
|
|
#include <errno.h>
|
|
#include <inttypes.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
void sprite_free(struct sprite *const src)
|
|
{
|
|
}
|
|
|
|
int sprite_clone(const struct sprite *const src, struct sprite *const dst)
|
|
{
|
|
*dst = *src;
|
|
return 0;
|
|
}
|
|
|
|
static void sprite_init(struct sprite *const s)
|
|
{
|
|
memset(s, 0, sizeof *s);
|
|
s->sznext.f.sz = (sizeof *s - sizeof s->sznext) / sizeof (uint32_t);
|
|
s->common.f.cmd = DRAW_MODE;
|
|
s->cmd = 0x65;
|
|
}
|
|
|
|
struct tim_pos
|
|
{
|
|
uint16_t x, y, w, h;
|
|
};
|
|
|
|
static void transfer_init(const struct tim_pos *const p)
|
|
{
|
|
while (!(GPU_CONTROL_PORT & (1 << 0x1c)))
|
|
;
|
|
|
|
GPU_CONTROL_PORT = 0x04000000;
|
|
GPU_DATA_PORT = 0x01000000;
|
|
GPU_DATA_PORT = 0xE6000000;
|
|
GPU_DATA_PORT = 0xA0000000;
|
|
GPU_DATA_PORT = (p->y << 16) | p->x;
|
|
GPU_DATA_PORT = (p->h << 16) | p->w;
|
|
}
|
|
|
|
static int transfer(const size_t sz, FILE *const f)
|
|
{
|
|
const size_t rem = sz % sizeof (uint32_t);
|
|
|
|
if (sz >= sizeof (uint32_t))
|
|
{
|
|
for (size_t i = 0; i < sz / sizeof (uint32_t); i++)
|
|
{
|
|
uint32_t pix;
|
|
|
|
if (!fread(&pix, sizeof pix, 1, f))
|
|
{
|
|
fprintf(stderr, "could not read CLUT word %zu/%zu\n",
|
|
i, sz / sizeof pix);
|
|
return -1;
|
|
}
|
|
|
|
GPU_DATA_PORT = pix;
|
|
}
|
|
}
|
|
|
|
if (rem)
|
|
{
|
|
uint32_t pix = 0;
|
|
|
|
if (!fread(&pix, rem, 1, f))
|
|
{
|
|
fprintf(stderr, "failed reading remaining %zu bytes\n", rem);
|
|
return -1;
|
|
}
|
|
|
|
GPU_DATA_PORT = pix;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct header
|
|
{
|
|
uint32_t sz;
|
|
struct tim_pos pos;
|
|
};
|
|
|
|
static int upload_clut(struct sprite *const s, FILE *const f)
|
|
{
|
|
struct header clut;
|
|
|
|
if (!fread(&clut, sizeof clut, 1, f))
|
|
{
|
|
fprintf(stderr, "no CLUT pos data found\n");
|
|
return -1;
|
|
}
|
|
|
|
transfer_init(&clut.pos);
|
|
|
|
const size_t sz = clut.sz - sizeof clut;
|
|
|
|
if (transfer(sz, f))
|
|
return -1;
|
|
|
|
s->clutid = get_clutid(clut.pos.x, clut.pos.y);
|
|
return 0;
|
|
}
|
|
|
|
enum bpp
|
|
{
|
|
BPP_4 = 0,
|
|
BPP_8 = 1,
|
|
BPP_16 = 2,
|
|
BPP_24 = 4
|
|
};
|
|
|
|
static int upload_img(struct sprite *const s, const enum bpp bpp, FILE *const f)
|
|
{
|
|
struct header img;
|
|
|
|
if (!fread(&img, sizeof img, 1, f))
|
|
{
|
|
fprintf(stderr, "could not extract image header\n");
|
|
return -1;
|
|
}
|
|
|
|
transfer_init(&img.pos);
|
|
|
|
const size_t sz = img.sz - sizeof img;
|
|
|
|
if (transfer(sz, f))
|
|
return -1;
|
|
|
|
enum
|
|
{
|
|
VRAM_X = 1024,
|
|
VRAM_Y = 512,
|
|
TPAGE_WIDTH = 64
|
|
};
|
|
|
|
s->common.f.tpagex = img.pos.x / TPAGE_WIDTH;
|
|
s->common.f.tpagey = img.pos.y / (VRAM_Y / 2);
|
|
s->u = img.pos.x % TPAGE_WIDTH;
|
|
s->v = img.pos.y % (VRAM_Y / 2);
|
|
|
|
switch (bpp)
|
|
{
|
|
case BPP_4:
|
|
s->w = img.pos.w * 4;
|
|
s->u <<= 2;
|
|
break;
|
|
|
|
case BPP_8:
|
|
s->w = img.pos.w * 2;
|
|
s->u <<= 1;
|
|
break;
|
|
|
|
case BPP_16:
|
|
s->w = img.pos.w;
|
|
break;
|
|
|
|
case BPP_24:
|
|
s->w = img.pos.w + (img.pos.w / 2);
|
|
break;
|
|
}
|
|
|
|
s->h = img.pos.h;
|
|
return 0;
|
|
}
|
|
|
|
int sprite_from_fp(struct sprite *const s, FILE *const f)
|
|
{
|
|
int ret = -1;
|
|
|
|
sprite_init(s);
|
|
|
|
struct
|
|
{
|
|
uint32_t version;
|
|
enum bpp bpp :3;
|
|
bool has_clut :1;
|
|
uint32_t :28;
|
|
} h;
|
|
|
|
enum {VERSION_ID = 0x10};
|
|
|
|
if (!fread(&h, sizeof h, 1, f))
|
|
{
|
|
fprintf(stderr, "TIM header not found\n");
|
|
goto end;
|
|
}
|
|
else if (h.version != VERSION_ID)
|
|
{
|
|
fprintf(stderr, "%s: invalid TIM header %#" PRIx32 "\n", h.version);
|
|
goto end;
|
|
}
|
|
else if (h.bpp == BPP_24)
|
|
{
|
|
fprintf(stderr, "24-bit mode unsupported\n");
|
|
goto end;
|
|
}
|
|
else if ((h.has_clut && upload_clut(s, f))
|
|
|| upload_img(s, h.bpp, f))
|
|
goto end;
|
|
|
|
s->common.f.bpp = h.bpp ? __builtin_ctz(h.bpp) + 1 : 0;
|
|
ret = 0;
|
|
|
|
end:
|
|
return ret;
|
|
}
|
|
|
|
int sprite_from_file_ex(const char *const path, struct sprite *const s)
|
|
{
|
|
int ret = -1;
|
|
FILE *f = NULL;
|
|
|
|
if (!path)
|
|
{
|
|
errno = EINVAL;
|
|
goto end;
|
|
}
|
|
|
|
f = fopen(path, "rb");
|
|
|
|
if (!f)
|
|
{
|
|
fprintf(stderr, "could not open %s: %s\n", path, strerror(errno));
|
|
goto end;
|
|
}
|
|
else if (sprite_from_fp(s, f))
|
|
{
|
|
fprintf(stderr, "%s: sprite_from_fp failed\n", path);
|
|
goto end;
|
|
}
|
|
|
|
end:
|
|
|
|
if (f)
|
|
fclose(f);
|
|
|
|
return ret;
|
|
}
|