From f2fc18f82dd7900465d6ab3ae2080726d5589d39 Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Tue, 17 Aug 2021 11:37:03 +0000 Subject: Added dynamic linker API and example, updated README and changelog --- examples/system/dynlink/library/ball16c.h | 16 +++ examples/system/dynlink/library/balls.c | 116 ++++++++++++++++++++ examples/system/dynlink/library/cube.c | 154 +++++++++++++++++++++++++++ examples/system/dynlink/library/dll_common.h | 30 ++++++ 4 files changed, 316 insertions(+) create mode 100644 examples/system/dynlink/library/ball16c.h create mode 100644 examples/system/dynlink/library/balls.c create mode 100644 examples/system/dynlink/library/cube.c create mode 100644 examples/system/dynlink/library/dll_common.h (limited to 'examples/system/dynlink/library') 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 +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +#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 + +/* 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 -- cgit v1.2.3