@@ -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. */
2562static 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+
347504sprite_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