aboutsummaryrefslogtreecommitdiff
path: root/examples/system/dynlink/library
diff options
context:
space:
mode:
authorJohn "Lameguy" Wilbert Villamor <lameguy64@gmail.com>2021-08-31 13:23:20 +0800
committerGitHub <noreply@github.com>2021-08-31 13:23:20 +0800
commitffa679d4d24b891cb59aba10946368f2ec00c391 (patch)
tree0cf6061915ebf48acdedf6d77b0c1b76eec5b8c3 /examples/system/dynlink/library
parent317dc2b91d3afcdbaddb035f38611d12af161970 (diff)
parentf2fc18f82dd7900465d6ab3ae2080726d5589d39 (diff)
downloadpsn00bsdk-ffa679d4d24b891cb59aba10946368f2ec00c391.tar.gz
Merge pull request #36 from spicyjpeg/dynlink
Dynamic linker, gp-relative addressing, ldscripts and more
Diffstat (limited to 'examples/system/dynlink/library')
-rw-r--r--examples/system/dynlink/library/ball16c.h16
-rw-r--r--examples/system/dynlink/library/balls.c116
-rw-r--r--examples/system/dynlink/library/cube.c154
-rw-r--r--examples/system/dynlink/library/dll_common.h30
4 files changed, 316 insertions, 0 deletions
diff --git a/examples/system/dynlink/library/ball16c.h b/examples/system/dynlink/library/ball16c.h
new file mode 100644
index 0000000..c79f273
--- /dev/null
+++ b/examples/system/dynlink/library/ball16c.h
@@ -0,0 +1,16 @@
+unsigned int ball16c_size=192;
+unsigned char ball16c[] = {
+0x10,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0xc0,0x03,0x10,
+0x01,0x10,0x00,0x01,0x00,0x00,0x00,0x31,0xc6,0x73,0xce,0x94,0xd2,0x07,0x9d,
+0xd6,0xda,0x38,0xe3,0xef,0xbd,0x9b,0xef,0x8c,0xb1,0xc6,0x98,0xde,0xfb,0x4a,
+0xa9,0xa4,0x90,0xad,0xb5,0x00,0x00,0x8c,0x00,0x00,0x00,0xc0,0x03,0x00,0x01,
+0x04,0x00,0x10,0x00,0x00,0x00,0x10,0x22,0x12,0x02,0x00,0x00,0x00,0x10,0x32,
+0x33,0x23,0x11,0x04,0x00,0x00,0x23,0x55,0x66,0x35,0x72,0x47,0x00,0x20,0x52,
+0x86,0x68,0x36,0x12,0x97,0x0a,0x20,0x65,0xbb,0x8b,0x36,0x12,0x91,0x04,0x31,
+0x85,0xbb,0x68,0x35,0x12,0x97,0xdc,0x32,0x86,0x8b,0x56,0x35,0x73,0x97,0xa4,
+0x32,0x66,0x68,0x55,0x23,0x71,0x9e,0xac,0x32,0x65,0x56,0x33,0x13,0x71,0xce,
+0xa4,0x21,0x33,0x33,0x23,0x11,0xe7,0xc9,0xd4,0x12,0x22,0x22,0x13,0x71,0xe7,
+0xc9,0xda,0x10,0x17,0x11,0x77,0x77,0x9e,0x4c,0x0d,0x40,0x77,0x71,0xe7,0x9e,
+0xc9,0xd4,0x0d,0x00,0x94,0x99,0x99,0xcc,0x4c,0xda,0x00,0x00,0xa0,0xc4,0xc4,
+0x44,0xda,0x0d,0x00,0x00,0x00,0xd0,0xaa,0xda,0x0d,0x00,0x00
+};
diff --git a/examples/system/dynlink/library/balls.c b/examples/system/dynlink/library/balls.c
new file mode 100644
index 0000000..2a4d9f4
--- /dev/null
+++ b/examples/system/dynlink/library/balls.c
@@ -0,0 +1,116 @@
+/*
+ * PSn00bSDK dynamic linker example (DLL 2)
+ * (C) 2021 spicyjpeg - MPL licensed
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <psxgpu.h>
+#include <psxgte.h>
+#include <psxpad.h>
+#include <inline_c.h>
+
+#include "dll_common.h"
+#include "ball16c.h"
+
+/* Balls data */
+
+typedef struct {
+ int16_t x, y;
+ int16_t xdir, ydir;
+ uint8_t r, g, b, p;
+} BALL_TYPE;
+
+#define MAX_BALLS 512
+
+/* Functions called by the main executable */
+
+// NOTE: DLLs have no main(), _start() or other defined entry point. C++ global
+// objects are automatically constructed when loading the library, and their
+// destructors are called when unloading it via dlclose(). Other than that, the
+// main executable can freely call DLL functions in any order, however it's
+// still recommended (at least for C code) to have an init() function to e.g.
+// initialize variables or hardware.
+
+static uint32_t frame = 0;
+static BALL_TYPE balls[MAX_BALLS];
+static TIM_IMAGE ball_tim;
+
+void init(CONTEXT *ctx) {
+ GetTimInfo((u_long *) ball16c, &ball_tim);
+
+ LoadImage(ball_tim.prect, ball_tim.paddr);
+ if (ball_tim.mode & 8)
+ LoadImage(ball_tim.crect, ball_tim.caddr);
+
+ // Initialize the balls by giving them a random initial position, velocity
+ // and color.
+ for (uint32_t i = 0; i < MAX_BALLS; i++) {
+ BALL_TYPE *b = &(balls[i]);
+
+ b->x = rand() % (ctx->xres - 16);
+ b->y = rand() % (ctx->yres - 16);
+ b->xdir = ((rand() & 1) ? 1 : -1) * ((rand() % 3) + 1);
+ b->ydir = ((rand() & 1) ? 1 : -1) * ((rand() % 3) + 1);
+ b->r = rand() & 0xff;
+ b->g = rand() & 0xff;
+ b->b = rand() & 0xff;
+ }
+}
+
+void render(CONTEXT *ctx, uint16_t buttons) {
+ DB *db = &(ctx->db[ctx->db_active]);
+ SPRT_16 *sprt = (SPRT_16 *) ctx->db_nextpri;
+
+ for (uint32_t i = 0; i < MAX_BALLS; i++) {
+ BALL_TYPE *b = &(balls[i]);
+
+ setSprt16(sprt);
+
+ setXY0(sprt, b->x, b->y);
+ setRGB0(sprt, b->r, b->g, b->b);
+ setUV0(sprt, 0, 0);
+ setClut(sprt, ball_tim.crect->x, ball_tim.crect->y);
+
+ addPrim(&(db->ot[OT_LEN - 1]), sprt);
+ sprt++;
+
+ // Update the ball's velocity and acceleration, moving them slower if
+ // cross is pressed.
+ int16_t step = !(buttons & PAD_CROSS) ? 1 : 0;
+ b->x += b->xdir >> step;
+ b->y += b->ydir >> step;
+
+ if (
+ (b->x < 0) ||
+ ((b->x + 16) > ctx->xres)
+ )
+ b->xdir *= -1;
+ if (
+ (b->y < 0) ||
+ ((b->y + 16) > ctx->yres)
+ )
+ b->ydir *= -1;
+ }
+
+ ctx->db_nextpri = (uint8_t *) sprt;
+
+ // Add a TPAGE "primitive" to ensure the GPU finds the ball texture.
+ DR_TPAGE *tpri = (DR_TPAGE * ) ctx->db_nextpri;
+
+ setDrawTPage(
+ tpri,
+ 0,
+ 0,
+ getTPage(0, 0, ball_tim.prect->x, ball_tim.prect->y)
+ );
+ addPrim(&(db->ot[OT_LEN - 1]), tpri);
+ tpri++;
+
+ ctx->db_nextpri = (uint8_t *) tpri;
+
+ // Due to our custom resolver, this will actually call dll_printf() in the
+ // main executable.
+ printf("DRAWING BALLS, COUNTER=%d\n", frame++);
+}
diff --git a/examples/system/dynlink/library/cube.c b/examples/system/dynlink/library/cube.c
new file mode 100644
index 0000000..57f3e56
--- /dev/null
+++ b/examples/system/dynlink/library/cube.c
@@ -0,0 +1,154 @@
+/*
+ * PSn00bSDK dynamic linker example (DLL 1)
+ * (C) 2021 spicyjpeg - MPL licensed
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <psxgpu.h>
+#include <psxgte.h>
+#include <psxpad.h>
+#include <inline_c.h>
+
+#include "dll_common.h"
+
+/* Cube model */
+
+typedef struct {
+ int16_t v0, v1, v2, v3;
+} INDEX;
+
+static SVECTOR cube_verts[] = {
+ { -100, -100, -100, 0 },
+ { 100, -100, -100, 0 },
+ { -100, 100, -100, 0 },
+ { 100, 100, -100, 0 },
+ { 100, -100, 100, 0 },
+ { -100, -100, 100, 0 },
+ { 100, 100, 100, 0 },
+ { -100, 100, 100, 0 }
+};
+static SVECTOR cube_norms[] = {
+ { 0, 0, -ONE, 0 },
+ { 0, 0, ONE, 0 },
+ { 0, -ONE, 0, 0 },
+ { 0, ONE, 0, 0 },
+ { -ONE, 0, 0, 0 },
+ { ONE, 0, 0, 0 }
+};
+static INDEX cube_indices[] = {
+ { 0, 1, 2, 3 },
+ { 4, 5, 6, 7 },
+ { 5, 4, 0, 1 },
+ { 6, 7, 3, 2 },
+ { 0, 2, 5, 7 },
+ { 3, 1, 6, 4 }
+};
+
+#define CUBE_FACES 6
+
+/* Light matrices */
+
+// Each column represents the color matrix of each light source and is used as
+// material color when using gte_ncs() or multiplied by a source color when
+// using gte_nccs(). 4096 is 1.0 in this matrix. A column of zeroes disables
+// the light source.
+static MATRIX color_mtx = {
+ ONE, 0, 0, // R
+ ONE, 0, 0, // G
+ ONE, 0, 0 // B
+};
+
+// Each row represents a vector direction of each light source. An entire row
+// of zeroes disables the light source.
+static MATRIX light_mtx = {
+ -2048, -2048, -2048,
+ 0, 0, 0,
+ 0, 0, 0
+};
+
+/* Functions called by the main executable */
+
+// NOTE: DLLs have no main(), _start() or other defined entry point. C++ global
+// objects are automatically constructed when loading the library, and their
+// destructors are called when unloading it via dlclose(). Other than that, the
+// main executable can freely call DLL functions in any order, however it's
+// still recommended (at least for C code) to have an init() function to e.g.
+// initialize variables or hardware.
+
+static uint32_t frame = 0;
+static SVECTOR rot = { 0 };
+static VECTOR pos = { 0, 0, 400 };
+static MATRIX mtx, lmtx;
+
+void init(CONTEXT *ctx) {
+ InitGeom();
+
+ gte_SetGeomOffset(ctx->xres / 2, ctx->yres / 2);
+ gte_SetGeomScreen(ctx->xres / 2);
+ gte_SetBackColor(63, 63, 63);
+ gte_SetColorMatrix(&color_mtx);
+}
+
+void render(CONTEXT *ctx, uint16_t buttons) {
+ RotMatrix(&rot, &mtx);
+ TransMatrix(&mtx, &pos);
+ MulMatrix0(&light_mtx, &mtx, &lmtx);
+
+ gte_SetRotMatrix(&mtx);
+ gte_SetTransMatrix(&mtx);
+ gte_SetLightMatrix(&lmtx);
+
+ // Spin the cube faster is cross is pressed.
+ int16_t step = !(buttons & PAD_CROSS) ? 32 : 16;
+ rot.vx += step;
+ rot.vz += step;
+
+ DB *db = &(ctx->db[ctx->db_active]);
+ POLY_F4 *pol4 = (POLY_F4 *) ctx->db_nextpri;
+
+ for (uint32_t i = 0; i < CUBE_FACES; i++) {
+ int32_t p;
+
+ gte_ldv3(
+ &cube_verts[cube_indices[i].v0],
+ &cube_verts[cube_indices[i].v1],
+ &cube_verts[cube_indices[i].v2]
+ );
+
+ gte_rtpt();
+ gte_nclip();
+ gte_stopz(&p);
+ if (p < 0)
+ continue;
+
+ gte_avsz4();
+ gte_stotz(&p);
+ if ((p >> 2) > OT_LEN)
+ continue;
+
+ setPolyF4(pol4);
+
+ gte_stsxy0(&(pol4->x0));
+ gte_stsxy1(&(pol4->x1));
+ gte_stsxy2(&(pol4->x2));
+
+ gte_ldv0(&(cube_verts[cube_indices[i].v3]));
+ gte_rtps();
+ gte_stsxy(&(pol4->x3));
+
+ gte_ldrgb(&(pol4->r0));
+ gte_ldv0(&(cube_norms[i]));
+ gte_ncs();
+ gte_strgb(&(pol4->r0));
+
+ addPrim(&(db->ot[p >> 2]), pol4);
+ pol4++;
+ }
+
+ ctx->db_nextpri = (uint8_t *) pol4;
+
+ // Due to our custom resolver, this will actually call dll_printf() in the
+ // main executable.
+ printf("DRAWING CUBE, COUNTER=%d\n", frame++);
+}
diff --git a/examples/system/dynlink/library/dll_common.h b/examples/system/dynlink/library/dll_common.h
new file mode 100644
index 0000000..4f9314b
--- /dev/null
+++ b/examples/system/dynlink/library/dll_common.h
@@ -0,0 +1,30 @@
+/*
+ * PSn00bSDK dynamic linker example (shared header)
+ * (C) 2021 spicyjpeg - MPL licensed
+ */
+
+#ifndef __DLL_COMMON_H
+#define __DLL_COMMON_H
+
+#include <psxgpu.h>
+
+/* Common structures shared by the main executable and DLLs */
+
+#define OT_LEN 256
+#define PACKET_LEN 16384
+
+typedef struct {
+ DISPENV disp;
+ DRAWENV draw;
+ uint32_t ot[OT_LEN];
+ uint8_t p[PACKET_LEN];
+} DB;
+
+typedef struct {
+ uint16_t xres, yres;
+ DB db[2];
+ uint32_t db_active;
+ uint8_t *db_nextpri;
+} CONTEXT;
+
+#endif