148 lines
5 KiB
C
148 lines
5 KiB
C
// Sprite demo: bounces a 16x16 ball sprite around the screen using
|
|
// surfaceBlitMasked. The ball is embedded as a `const JoeyAssetT`
|
|
// directly in this file, so no .jas file or runtime allocation is
|
|
// involved -- this exercises the static / embedded path. Press ESC
|
|
// to quit.
|
|
//
|
|
// Each frame we redraw only the ball's old and new bounding boxes
|
|
// (and present those two small rects), so the cost stays small even
|
|
// with the slow 68000-class c2p in the ST and Amiga ports.
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <joey/joey.h>
|
|
|
|
#define BALL_W 16
|
|
#define BALL_H 16
|
|
|
|
#define BALL_PALETTE_IDX 0
|
|
|
|
#define COLOR_BG 0
|
|
#define COLOR_TRANSPARENT 0 // first palette slot doubles as mask
|
|
|
|
// 16x16 ball sprite, 4bpp packed (8 bytes per row):
|
|
// 0 = transparent (mask)
|
|
// 2 = ball body (yellow)
|
|
// 3 = highlight (white)
|
|
// High nibble of each byte is the LEFT pixel.
|
|
static const uint8_t gBallPixels[BALL_H * 8] = {
|
|
0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, // row 0
|
|
0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, // row 1
|
|
0x02, 0x22, 0x32, 0x22, 0x22, 0x22, 0x22, 0x20, // row 2
|
|
0x02, 0x23, 0x32, 0x22, 0x22, 0x22, 0x22, 0x20, // row 3
|
|
0x22, 0x33, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, // row 4
|
|
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, // row 5
|
|
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, // row 6
|
|
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, // row 7
|
|
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, // row 8
|
|
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, // row 9
|
|
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, // row 10
|
|
0x02, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x20, // row 11
|
|
0x02, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x20, // row 12
|
|
0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, // row 13
|
|
0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, // row 14
|
|
0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x00 // row 15
|
|
};
|
|
|
|
// Build the embedded ball asset at runtime. We could declare a
|
|
// `static const JoeyAssetT` with this same data, but ORCA/C 2.1
|
|
// does not handle a file-scope static struct whose pointer field is
|
|
// initialized from another static array's address (linker complains
|
|
// of unresolved references). Building the struct in main() with a
|
|
// local sidesteps the quirk and costs only a handful of stores.
|
|
static void buildBallAsset(JoeyAssetT *ball) {
|
|
uint16_t i;
|
|
|
|
ball->width = BALL_W;
|
|
ball->height = BALL_H;
|
|
ball->hasPalette = true;
|
|
ball->pixels = gBallPixels;
|
|
for (i = 0; i < 16; i++) {
|
|
ball->palette[i] = 0x0000;
|
|
}
|
|
ball->palette[2] = 0x0FF0; // yellow body
|
|
ball->palette[3] = 0x0FFF; // white highlight
|
|
}
|
|
|
|
|
|
static void initialPaint(SurfaceT *screen) {
|
|
surfaceClear(screen, COLOR_BG);
|
|
surfacePresent(screen);
|
|
}
|
|
|
|
|
|
int main(void) {
|
|
JoeyConfigT config;
|
|
SurfaceT *screen;
|
|
JoeyAssetT ball;
|
|
int16_t x;
|
|
int16_t y;
|
|
int16_t vx;
|
|
int16_t vy;
|
|
int16_t lastX;
|
|
int16_t lastY;
|
|
|
|
config.hostMode = HOST_MODE_TAKEOVER;
|
|
config.codegenBytes = 32 * 1024;
|
|
config.maxSurfaces = 4;
|
|
config.audioBytes = 64 * 1024;
|
|
config.assetBytes = 128 * 1024;
|
|
|
|
if (!joeyInit(&config)) {
|
|
fprintf(stderr, "joeyInit failed: %s\n", joeyLastError());
|
|
return 1;
|
|
}
|
|
|
|
screen = surfaceGetScreen();
|
|
if (screen == NULL) {
|
|
fprintf(stderr, "surfaceGetScreen returned NULL\n");
|
|
joeyShutdown();
|
|
return 1;
|
|
}
|
|
|
|
buildBallAsset(&ball);
|
|
joeyAssetApplyPalette(screen, BALL_PALETTE_IDX, &ball);
|
|
scbSetRange(screen, 0, SURFACE_HEIGHT - 1, BALL_PALETTE_IDX);
|
|
initialPaint(screen);
|
|
|
|
x = 40;
|
|
y = 30;
|
|
vx = 2;
|
|
vy = 1;
|
|
lastX = x;
|
|
lastY = y;
|
|
|
|
surfaceBlitMasked(screen, &ball, x, y, COLOR_TRANSPARENT);
|
|
surfacePresentRect(screen, x, y, BALL_W, BALL_H);
|
|
|
|
for (;;) {
|
|
joeyWaitVBL();
|
|
joeyInputPoll();
|
|
if (joeyKeyPressed(KEY_ESCAPE)) {
|
|
break;
|
|
}
|
|
|
|
// Erase old ball position by clearing its bounding rect. Any
|
|
// pixel outside the ball that we wrote (we wrote no pixels
|
|
// outside, since blitMasked respects transparency) stays as
|
|
// background already.
|
|
fillRect(screen, lastX, lastY, BALL_W, BALL_H, COLOR_BG);
|
|
surfacePresentRect(screen, lastX, lastY, BALL_W, BALL_H);
|
|
|
|
x = (int16_t)(x + vx);
|
|
y = (int16_t)(y + vy);
|
|
if (x <= 0) { x = 0; vx = (int16_t)-vx; }
|
|
if (x >= SURFACE_WIDTH - BALL_W) { x = SURFACE_WIDTH - BALL_W; vx = (int16_t)-vx; }
|
|
if (y <= 0) { y = 0; vy = (int16_t)-vy; }
|
|
if (y >= SURFACE_HEIGHT - BALL_H) { y = SURFACE_HEIGHT - BALL_H; vy = (int16_t)-vy; }
|
|
|
|
surfaceBlitMasked(screen, &ball, x, y, COLOR_TRANSPARENT);
|
|
surfacePresentRect(screen, x, y, BALL_W, BALL_H);
|
|
|
|
lastX = x;
|
|
lastY = y;
|
|
}
|
|
|
|
joeyShutdown();
|
|
return 0;
|
|
}
|