Skip to content

Commit d415b6c

Browse files
pre-swizzle sprite buffers, and render using and/or operations for sprite masking with precalc mask
1 parent 48df598 commit d415b6c

2 files changed

Lines changed: 193 additions & 15 deletions

File tree

include/basic/structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ typedef struct sprite {
273273
int64_t gif_size; /* Gif size */
274274
void *gif_state; /* actually stbi__gif* */
275275
void *gif_ctx; /* actually stbi__context* */
276+
uint32_t *mask;
276277
} sprite_t;
277278

278279
/**

src/basic/graphics.c

Lines changed: 192 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,43 @@ void __assert_fail(const char * assertion, const char * file, unsigned int line,
2121
while(true);
2222
}
2323

24+
static uint32_t rgba_to_fb(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
25+
{
26+
/* Framebuffer expects ARGB */
27+
return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b;
28+
}
29+
30+
static int sprite_swizzle_and_mask_rgba(sprite_t* s, const unsigned char* rgba)
31+
{
32+
if (s == NULL || s->pixels == NULL || s->mask == NULL || rgba == NULL) {
33+
return 0;
34+
}
35+
if (s->width <= 0 || s->height <= 0) {
36+
return 0;
37+
}
38+
39+
int64_t w = s->width;
40+
int64_t h = s->height;
41+
42+
for (int64_t y = 0; y < h; ++y) {
43+
uint32_t* dst = s->pixels + (y * w);
44+
uint32_t* m = s->mask + (y * w);
45+
const unsigned char* src = rgba + (y * w * 4);
46+
47+
for (int64_t x = 0; x < w; ++x) {
48+
uint8_t r = src[x * 4 + 0];
49+
uint8_t g = src[x * 4 + 1];
50+
uint8_t b = src[x * 4 + 2];
51+
uint8_t a = src[x * 4 + 3];
52+
53+
dst[x] = rgba_to_fb(r, g, b, a);
54+
m[x] = (a == 255) ? 0xffffffff : 0x00000000;
55+
}
56+
}
57+
58+
return 1;
59+
}
60+
2461
/* Cheap GIF container scan: counts frames without decoding LZW. */
2562
static int gif_count_frames_and_size(const unsigned char *p, size_t len, int *lw, int *lh)
2663
{
@@ -149,6 +186,7 @@ int64_t alloc_sprite(struct basic_ctx* ctx)
149186
s->width = 0;
150187
s->height = 0;
151188
s->pixels = NULL;
189+
s->mask = NULL;
152190
return i;
153191
}
154192
}
@@ -173,6 +211,9 @@ void free_sprite(struct basic_ctx* ctx, int64_t sprite_handle)
173211
if (s->gif_data) {
174212
buddy_free(ctx->allocator, s->gif_data);
175213
}
214+
if (s->mask) {
215+
buddy_free(ctx->allocator, s->mask);
216+
}
176217

177218
buddy_free(ctx->allocator, s);
178219
ctx->sprites[sprite_handle] = NULL;
@@ -252,6 +293,8 @@ static int sprite_gif_step_next(sprite_t *s)
252293
}
253294
}
254295

296+
sprite_swizzle_and_mask_rgba(s, (unsigned char*)s->pixels);
297+
255298
return 1;
256299
}
257300

@@ -325,7 +368,7 @@ void sprite_first_frame(struct basic_ctx* ctx, int64_t sprite_handle)
325368
}
326369
}
327370

328-
void plot_sprite(struct basic_ctx* ctx, int64_t sprite_handle, int64_t draw_x, int64_t draw_y)
371+
/*void plot_sprite(struct basic_ctx* ctx, int64_t sprite_handle, int64_t draw_x, int64_t draw_y)
329372
{
330373
if (sprite_handle >= 0 && sprite_handle < MAX_SPRITES && ctx->sprites[sprite_handle] != NULL && ctx->sprites[sprite_handle]->pixels != NULL) {
331374
sprite_t* s = ctx->sprites[sprite_handle];
@@ -342,8 +385,122 @@ void plot_sprite(struct basic_ctx* ctx, int64_t sprite_handle, int64_t draw_x, i
342385
}
343386
}
344387
}
388+
}*/
389+
390+
void plot_sprite(struct basic_ctx* ctx, int64_t sprite_handle, int64_t draw_x, int64_t draw_y)
391+
{
392+
if (sprite_handle < 0 || sprite_handle >= MAX_SPRITES) {
393+
return;
394+
}
395+
if (ctx->sprites[sprite_handle] == NULL) {
396+
return;
397+
}
398+
399+
sprite_t* s = ctx->sprites[sprite_handle];
400+
401+
if (s->pixels == NULL || s->mask == NULL) {
402+
return;
403+
}
404+
405+
int64_t fb_w = screen_get_width();
406+
int64_t fb_h = screen_get_height();
407+
408+
int64_t dst_x0 = draw_x;
409+
int64_t dst_y0 = draw_y;
410+
int64_t dst_x1 = draw_x + s->width;
411+
int64_t dst_y1 = draw_y + s->height;
412+
413+
if (dst_x1 <= 0 || dst_y1 <= 0 || dst_x0 >= fb_w || dst_y0 >= fb_h) {
414+
return;
415+
}
416+
417+
int64_t clip_x0 = dst_x0;
418+
int64_t clip_y0 = dst_y0;
419+
int64_t clip_x1 = dst_x1;
420+
int64_t clip_y1 = dst_y1;
421+
422+
if (clip_x0 < 0) {
423+
clip_x0 = 0;
424+
}
425+
if (clip_y0 < 0) {
426+
clip_y0 = 0;
427+
}
428+
if (clip_x1 > fb_w) {
429+
clip_x1 = fb_w;
430+
}
431+
if (clip_y1 > fb_h) {
432+
clip_y1 = fb_h;
433+
}
434+
435+
int64_t copy_w = clip_x1 - clip_x0;
436+
int64_t copy_h = clip_y1 - clip_y0;
437+
438+
if (copy_w <= 0 || copy_h <= 0) {
439+
return;
440+
}
441+
442+
int64_t src_x0 = clip_x0 - draw_x;
443+
int64_t src_y0 = clip_y0 - draw_y;
444+
445+
uint8_t* fb_base = (uint8_t*)framebuffer_address();
446+
447+
for (int64_t row = 0; row < copy_h; ++row) {
448+
int64_t src_y = src_y0 + row;
449+
int64_t dst_y = clip_y0 + row;
450+
451+
const uint32_t* src = s->pixels + ((size_t)src_y * (size_t)s->width) + (size_t)src_x0;
452+
const uint32_t* m = s->mask + ((size_t)src_y * (size_t)s->width) + (size_t)src_x0;
453+
454+
uint32_t* dst = (uint32_t*)(fb_base + pixel_address(clip_x0, dst_y));
455+
456+
int64_t x = 0;
457+
458+
/* 64-bit pairs */
459+
int64_t pairs = copy_w / 2;
460+
461+
if ((((uintptr_t)dst | (uintptr_t)src | (uintptr_t)m) & 7) == 0) {
462+
uint64_t* d64 = (uint64_t*)dst;
463+
const uint64_t* s64 = (const uint64_t*)src;
464+
const uint64_t* m64 = (const uint64_t*)m;
465+
466+
for (int64_t i = 0; i < pairs; ++i) {
467+
uint64_t md = m64[i];
468+
uint64_t sd = s64[i];
469+
uint64_t dd = d64[i];
470+
471+
d64[i] = (dd & ~md) | (sd & md);
472+
}
473+
} else {
474+
for (int64_t i = 0; i < pairs; ++i) {
475+
uint64_t md;
476+
uint64_t sd;
477+
uint64_t dd;
478+
479+
memcpy(&md, m + (i * 2), 8);
480+
memcpy(&sd, src + (i * 2), 8);
481+
memcpy(&dd, dst + (i * 2), 8);
482+
483+
dd = (dd & ~md) | (sd & md);
484+
memcpy(dst + (i * 2), &dd, 8);
485+
}
486+
}
487+
488+
x = pairs * 2;
489+
490+
/* Tail pixel */
491+
if (x < copy_w) {
492+
uint32_t md = m[x];
493+
uint32_t sd = src[x];
494+
uint32_t dd = dst[x];
495+
496+
dst[x] = (dd & ~md) | (sd & md);
497+
}
498+
}
499+
500+
set_video_dirty_area(clip_y0, clip_y1 - 1);
345501
}
346502

503+
347504
sprite_t* get_sprite(struct basic_ctx* ctx, int64_t sprite_handle)
348505
{
349506
if (sprite_handle >= 0 && sprite_handle < MAX_SPRITES && ctx->sprites[sprite_handle] != NULL) {
@@ -499,6 +656,15 @@ void loadsprite_statement(struct basic_ctx* ctx)
499656
}
500657
dprintf("Stream reset\n");
501658

659+
s->mask = buddy_malloc(ctx->allocator, bytes);
660+
if (!s->mask) {
661+
tokenizer_error_printf(ctx, "Not enough memory for sprite mask '%s'", file);
662+
buddy_free(ctx->allocator, canvas);
663+
buddy_free(ctx->allocator, buf);
664+
free_sprite(ctx, sprite_handle);
665+
return;
666+
}
667+
502668
/* Decode first frame into canvas */
503669
if (!sprite_gif_step_next(s)) {
504670
tokenizer_error_printf(ctx, "Failed to decode first GIF frame '%s'", file);
@@ -538,11 +704,32 @@ void loadsprite_statement(struct basic_ctx* ctx)
538704
free_sprite(ctx, sprite_handle);
539705
return;
540706
}
541-
memcpy(pixels, tmp, bytes);
707+
708+
sprite_t* s = get_sprite(ctx, sprite_handle);
709+
s->pixels = pixels;
710+
s->width = w;
711+
s->height = h;
712+
713+
s->mask = buddy_malloc(ctx->allocator, bytes);
714+
if (!s->mask) {
715+
tokenizer_error_printf(ctx, "Not enough memory for sprite mask '%s'", file);
716+
stbi_image_free(tmp);
717+
buddy_free(ctx->allocator, buf);
718+
free_sprite(ctx, sprite_handle);
719+
return;
720+
}
721+
722+
if (!sprite_swizzle_and_mask_rgba(s, tmp)) {
723+
tokenizer_error_printf(ctx, "Failed to swizzle sprite '%s'", file);
724+
stbi_image_free(tmp);
725+
buddy_free(ctx->allocator, buf);
726+
free_sprite(ctx, sprite_handle);
727+
return;
728+
}
729+
542730
stbi_image_free(tmp);
543731

544732
/* Store sprite metadata */
545-
sprite_t* s = get_sprite(ctx, sprite_handle);
546733
s->pixels = pixels;
547734
s->width = w;
548735
s->height = h;
@@ -757,12 +944,7 @@ static bool plot_sprite_quad_axis_aligned_int(struct basic_ctx* ctx, int64_t spr
757944

758945
uint32_t src = s->pixels[vi * w + ui];
759946
if ((src & 0xff000000) == 0xff000000) {
760-
uint32_t a = (src >> 24) & 0xff;
761-
uint32_t r = (src >> 16) & 0xff;
762-
uint32_t g = (src >> 8) & 0xff;
763-
uint32_t b = (src) & 0xff;
764-
volatile uint32_t* addr = (volatile uint32_t*)(framebuffer + pixel_address(px, py));
765-
*addr = (a << 24) | (b << 16) | (g << 8) | r;
947+
*(volatile uint32_t*)(framebuffer + pixel_address(px, py)) = src;
766948
}
767949

768950
u_fp += dx_u;
@@ -968,12 +1150,7 @@ inline static void draw_strip_projective(dpoint_t L0, dpoint_t L1, dpoint_t S0,
9681150
if (ui < sw && vi < sh) {
9691151
uint32_t src = spx[vi * sw + ui];
9701152
if ((src & 0xff000000) == 0xff000000) {
971-
uint32_t a = (src >> 24) & 0xff;
972-
uint32_t r = (src >> 16) & 0xff;
973-
uint32_t g = (src >> 8) & 0xff;
974-
uint32_t b = src & 0xff;
975-
volatile uint32_t* addr = (volatile uint32_t*)(framebuffer + pixel_address(x, y));
976-
*addr = (a << 24) | (b << 16) | (g << 8) | r;
1153+
*(volatile uint32_t*)(framebuffer + pixel_address(x, y)) = src;
9771154
}
9781155
}
9791156
}

0 commit comments

Comments
 (0)