diff options
| author | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2021-07-03 00:49:03 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2022-03-30 08:20:20 +0200 |
| commit | 6b9f686913efc3725b2690033cd4f398e07076ba (patch) | |
| tree | e9aa91a6b9f617d78123ebe7ad272fc42a60d306 /src/gfx/ps1 | |
| parent | c9e6ae44a9aeb89b3f48f3443d6baa80103f7445 (diff) | |
| download | jancity-6b9f686913efc3725b2690033cd4f398e07076ba.tar.gz | |
Add project source code
Diffstat (limited to 'src/gfx/ps1')
| -rw-r--r-- | src/gfx/ps1/inc/gfx/port.h | 142 | ||||
| -rw-r--r-- | src/gfx/ps1/privinc/ps1/gfx_private.h | 25 | ||||
| -rw-r--r-- | src/gfx/ps1/src/4line.c | 14 | ||||
| -rw-r--r-- | src/gfx/ps1/src/env.c | 42 | ||||
| -rw-r--r-- | src/gfx/ps1/src/heap.c | 19 | ||||
| -rw-r--r-- | src/gfx/ps1/src/init.c | 16 | ||||
| -rw-r--r-- | src/gfx/ps1/src/quad.c | 23 | ||||
| -rw-r--r-- | src/gfx/ps1/src/rect.c | 23 | ||||
| -rw-r--r-- | src/gfx/ps1/src/sort.c | 75 | ||||
| -rw-r--r-- | src/gfx/ps1/src/sprite.c | 244 |
10 files changed, 623 insertions, 0 deletions
diff --git a/src/gfx/ps1/inc/gfx/port.h b/src/gfx/ps1/inc/gfx/port.h new file mode 100644 index 0000000..dec00c3 --- /dev/null +++ b/src/gfx/ps1/inc/gfx/port.h @@ -0,0 +1,142 @@ +#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; +}; + +enum {DRAW_MODE = 0xE1}; + +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 */ diff --git a/src/gfx/ps1/privinc/ps1/gfx_private.h b/src/gfx/ps1/privinc/ps1/gfx_private.h new file mode 100644 index 0000000..fd5a790 --- /dev/null +++ b/src/gfx/ps1/privinc/ps1/gfx_private.h @@ -0,0 +1,25 @@ +#ifndef GFX_PS1_PRIVATE_H +#define GFX_PS1_PRIVATE_H + +#include <gfx.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +enum +{ + SCREEN_W = 368, + SCREEN_H = 240 +}; + +void gfx_swapheap(void); +void gfx_initenvs(void); +void gfx_swapbuffers(void); + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_PS1_PRIVATE_H */ diff --git a/src/gfx/ps1/src/4line.c b/src/gfx/ps1/src/4line.c new file mode 100644 index 0000000..955277e --- /dev/null +++ b/src/gfx/ps1/src/4line.c @@ -0,0 +1,14 @@ +#include <gfx.h> +#include <psxgpu.h> +#include <stdint.h> +#include <string.h> + +void stp_4line_init(struct stp_4line *const l) +{ + memset(l, 0, sizeof *l); + l->sznext.f.sz = (sizeof *l - sizeof l->sznext) / sizeof (uint32_t); + l->common.f.cmd = DRAW_MODE; + l->cmd = 0x5A; + enum {TERMINATION_CODE = 0x55555555}; + l->end = TERMINATION_CODE; +} diff --git a/src/gfx/ps1/src/env.c b/src/gfx/ps1/src/env.c new file mode 100644 index 0000000..c12002b --- /dev/null +++ b/src/gfx/ps1/src/env.c @@ -0,0 +1,42 @@ +#include <gfx.h> +#include <gfx_private.h> +#include <ps1/gfx_private.h> +#include <psxgpu.h> +#include <stdbool.h> + +static GsDispEnv dispenv; +enum {ENV_Y = SCREEN_H + 16}; + +static GsDrawEnv drawenv = +{ + .y = ENV_Y, + .w = SCREEN_W, + .h = SCREEN_H +}; + +int screen_w = SCREEN_W, screen_h = SCREEN_H; + +void gfx_swapbuffers(void) +{ + const short y = drawenv.y; + + drawenv.y = dispenv.y; + dispenv.y = y; + GsSetDrawEnv(&drawenv); + GsSetDispEnv(&dispenv); +} + +void gfx_initenvs(void) +{ + GsSetDrawEnv(&drawenv); + GsSetDispEnv(&dispenv); +} + +bool gfx_inside_drawenv(const short x, const short y, const short w, + const short h) +{ + return (x + w >= 0) + && x < drawenv.w + && (y + h >= 0) + && y < drawenv.h; +} diff --git a/src/gfx/ps1/src/heap.c b/src/gfx/ps1/src/heap.c new file mode 100644 index 0000000..b67ee3e --- /dev/null +++ b/src/gfx/ps1/src/heap.c @@ -0,0 +1,19 @@ +#include <gfx.h> +#include <gfx_private.h> +#include <stddef.h> + +static unsigned int sel; + +void gfx_swapheap(void) +{ + sel ^= 1; +} + +void *gfx_port_heap(size_t *const n) +{ + enum {HEAP_SZ = 5120, N_HEAPS = 2}; + static char heaps[N_HEAPS][HEAP_SZ]; + + *n = sizeof *heaps / sizeof **heaps; + return heaps[sel]; +} diff --git a/src/gfx/ps1/src/init.c b/src/gfx/ps1/src/init.c new file mode 100644 index 0000000..15ecd3e --- /dev/null +++ b/src/gfx/ps1/src/init.c @@ -0,0 +1,16 @@ +#include <gfx_private.h> +#include <ps1/gfx_private.h> +#include <psxgpu.h> + +void gfx_deinit(void) +{ +} + +int gfx_init(void) +{ + GsInit(); + GsClearMem(); + GsSetVideoMode(SCREEN_W, SCREEN_H, VIDEO_MODE); + gfx_initenvs(); + return 0; +} diff --git a/src/gfx/ps1/src/quad.c b/src/gfx/ps1/src/quad.c new file mode 100644 index 0000000..649426f --- /dev/null +++ b/src/gfx/ps1/src/quad.c @@ -0,0 +1,23 @@ +#include <gfx.h> +#include <gfx/port.h> +#include <stdint.h> +#include <string.h> + +static void quad_init(struct quad *const q) +{ + memset(q, 0, sizeof *q); + q->sznext.f.sz = (sizeof *q - sizeof q->sznext) / sizeof (uint32_t); + q->cmd = 0x2d; +} + +int quad_from_sprite(const struct sprite *const s, struct quad *const q) +{ + quad_init(q); + q->tpage.mask = s->common.mask; + q->clutid = s->clutid; + q->u0 = q->u2 = s->u; + q->v0 = q->v1 = s->v; + q->u1 = q->u3 = s->u + s->w - 1; + q->v2 = q->v3 = s->v + s->h - 1; + return 0; +} diff --git a/src/gfx/ps1/src/rect.c b/src/gfx/ps1/src/rect.c new file mode 100644 index 0000000..7e593b7 --- /dev/null +++ b/src/gfx/ps1/src/rect.c @@ -0,0 +1,23 @@ +#include <gfx.h> +#include <psxgpu.h> +#include <stdint.h> +#include <string.h> + +static void common_init(struct rect *const r) +{ + memset(r, 0, sizeof *r); + r->sznext.f.sz = (sizeof *r - sizeof r->sznext) / sizeof (uint32_t); + r->common.f.cmd = DRAW_MODE; +} + +void rect_init(struct rect *const r) +{ + common_init(r); + r->cmd = 0x60; +} + +void semitrans_rect_init(struct rect *const r) +{ + common_init(r); + r->cmd = 0x62; +} diff --git a/src/gfx/ps1/src/sort.c b/src/gfx/ps1/src/sort.c new file mode 100644 index 0000000..5cc14aa --- /dev/null +++ b/src/gfx/ps1/src/sort.c @@ -0,0 +1,75 @@ +#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; +} + +void sprite_sort(struct sprite *const s) +{ + add_to_list(&s->sznext); +} + +void quad_sort(struct quad *const q) +{ + add_to_list(&q->sznext); +} + +void rect_sort(struct rect *const r) +{ + add_to_list(&r->sznext); +} + +void stp_4line_sort(struct stp_4line *const l) +{ + add_to_list(&l->sznext); +} + +void gfx_draw(void) +{ + static union gfx_sznext term = {.cmd_next = 0xffffff}; + + add_to_list(&term); + + void gpu_ctrl(unsigned int command, unsigned int 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; + gfx_reset_heap(); +} + +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; +} diff --git a/src/gfx/ps1/src/sprite.c b/src/gfx/ps1/src/sprite.c new file mode 100644 index 0000000..3e35a70 --- /dev/null +++ b/src/gfx/ps1/src/sprite.c @@ -0,0 +1,244 @@ +#include <gfx.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; +} |
