1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
/*
* PSn00bSDK dynamic linker example (DLL 2)
* (C) 2021 spicyjpeg - MPL licensed
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <psxgpu.h>
#include <psxgte.h>
#include <psxpad.h>
#include <inline_c.h>
#include "dll_common.h"
extern const uint32_t ball16c[];
/* Balls data */
typedef struct {
int16_t x, y;
int16_t xdir, ydir;
uint8_t r, g, b, p;
} Ball;
#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 balls[MAX_BALLS];
static TIM_IMAGE ball_tim;
void init(RenderContext *ctx) {
Framebuffer *db = &(ctx->db[ctx->db_active]);
GetTimInfo(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 *b = &(balls[i]);
b->x = rand() % (db->draw.clip.w - 16);
b->y = rand() % (db->draw.clip.h - 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(RenderContext *ctx, uint16_t buttons) {
Framebuffer *db = &(ctx->db[ctx->db_active]);
SPRT_16 *sprt = (SPRT_16 *) ctx->db_nextpri;
for (uint32_t i = 0; i < MAX_BALLS; i++) {
Ball *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) > db->draw.clip.w)
)
b->xdir *= -1;
if (
(b->y < 0) ||
((b->y + 16) > db->draw.clip.h)
)
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++);
}
|