Author Topic: Fast sprite rendering in an RGB565 framebuffer  (Read 494 times)

0 Members and 1 Guest are viewing this topic.

Offline gameblabla

  • Super User
  • Join Date: May 2015
  • Location:
  • Posts: 779
  • Post Rating Ratio: +15/-7
  • TI-nspire porter
Fast sprite rendering in an RGB565 framebuffer
« on: April 12, 2018, 12:23:57 am »
So right now i'm working on a project for the Atari Falcon (which will also be ported to DOS and other platforms) and that platform has a Motorola 68030 running at 16Mhz.
However, making things worse is the fact that the system bus is 16-bits only... So i need to make sure to optimize my graphical routines as fast as i can.
I want to use the RGB565 mode on this thing, since its the only one that is linear and not chunky/planar. Plus i like more colors :P
(RGB565 also happens to be the color mode the nspire uses so that should be useful too)

I'm also using a custom display mode, 320x180 rather than 320x240 for performance & convenience reasons. (including 1080p up-scaling)

So for a full RGB565 320x180 picture, i can basically just load the file with fopen & fread and just memcpy everything.
Code: [Select]
memcpy(myscreen_address, mybuffer, (320*180)*2);
Or i can simply use the optimised routines that came with Orion's devkit and use that.
(works the same as memcpy)
Code: [Select]
FastCopy32(mybuffer, myscreen_address, (320*180)*2);

That's pretty and fast... but how about sprites ?
I initially came up with this (no transparency for now, i have a solution for that) :
Code: [Select]
typedef struct tagBITMAP
{
  unsigned short width;
  unsigned short height;
  unsigned long tsize;
  unsigned char *data;
} BITMAP;

void Draw_Sprite(u32* framebuffer, BITMAP* bmp, short x, short y)
{
    u32* dst = &framebuffer[((y * (RL_SCREEN_WIDTH)) + x) / 4];
    memcpy(dst, bmp->data, bmp->tsize);
}

However, unless the picture uses the same width as the screen (320 here), the picture is not displayed properly.
If my sprite is 320x32, it will be displayed properly. However, if its width is anything but 320, it won't be displayed properly.
You see what i mean ?

So what can i do ? I've looked online and even n2DLIb but that library just draws every pixel individually.
That is horribly inefficient and i would like to use memory copying if possible.
We'll just assume that we don't want transparency for sprites. (i have a solution for that)
What would be the fastest way to display a moving sprite on-screen ?


  • Calculators owned: TI Nspire CX, TI-89

Offline tr1p1ea

  • Full User
  • Join Date: Feb 2015
  • Location:
  • Posts: 276
  • Post Rating Ratio: +5/-1
Re: Fast sprite rendering in an RGB565 framebuffer
« Reply #1 on: April 12, 2018, 03:20:35 am »
Could you not use the FastCopy32 function to draw every ROW of your sprite to the specified location in a loop for y?

Sort of like (not real code):

for(int i=0; i<bmp->size; i++) {
  FastCopy32(bmp->data+(i*bmp->size), myscreen_address+((y+i)*320*2)+x*2, bmp->size);
}

Not sure if that is 100% correct, but you get the idea.

Or something to that effect? You would need to check every pixel if you want transparency though, which is possibly why the lib you mentioned does?

Offline gameblabla

  • Super User
  • Join Date: May 2015
  • Location:
  • Posts: 779
  • Post Rating Ratio: +15/-7
  • TI-nspire porter
Re: Fast sprite rendering in an RGB565 framebuffer
« Reply #2 on: April 12, 2018, 03:37:32 am »
Could you not use the FastCopy32 function to draw every ROW of your sprite to the specified location in a loop for y?

Sort of like (not real code):

for(int i=0; i<bmp->size; i++) {
  FastCopy32(bmp->data+(i*bmp->size), myscreen_address+((y+i)*320*2)+x*2, bmp->size);
}

Not sure if that is 100% correct, but you get the idea.

Or something to that effect? You would need to check every pixel if you want transparency though, which is possibly why the lib you mentioned does?
Thanks for the help.
I came up with this :
Code: [Select]
void CopySprite(BITMAP* b, u32* dst, short x, short y)
{
    int j;
    for(j = 0; j < b->height; j++)
    {
memcpy(dst+((b->width/2)*j), bmp->data+((b->width*2)*j), (b->width*2)*2);
dst += (320 - b->width);
    }
}
If the bitmap has a size of 320, it works fine. However, anything different to that and it doesn't work...

Basically the issue is that i can't display properly anything that's not the screen's width size. (320 in this instance)

Quote
Or something to that effect? You would need to check every pixel if you want transparency though, which is possibly why the lib you mentioned does?
Yeah, the library has assembly routines for that. One in particular, FastCopy32Skip16, can be used for transparency by skipping a specific bit.
Code: [Select]
FastCopy32Skip16(bmp->data, dst, bmp->width*4, 0xf81f);
So yeah now you understand why i don't want to draw every pixels when i have something better...
« Last Edit: April 12, 2018, 03:44:55 am by gameblabla »
  • Calculators owned: TI Nspire CX, TI-89

Offline jacobly

  • New User
  • CodeWalrus Supporter
  • *
  • Safe-haven access
  • Join Date: Sep 2015
  • Location:
  • Posts: 8
  • Post Rating Ratio: +0/-0
Re: Fast sprite rendering in an RGB565 framebuffer
« Reply #3 on: April 12, 2018, 07:22:09 am »
dst += (320 - b->width)/2; would be correct if the copy were modifying dst, but since it isn't, it should be dst += 320/2; to go to the next line of the framebuffer.

Edit: The fact that x and y are never used indicates there is something missing in the logic.  I would just do:
Code: [Select]
void CopySprite(BITMAP* b, u32* dst, short x, short y)
{
    u16* from = (u16*)b->data;
    u16* to = (u16*)dst + x + y * 320;
    int j;
    for(j = 0; j < b->height; j++)
    {
        memcpy(to, from, b->width*2);
        to += 320;
        from += b->width;
    }
}
« Last Edit: April 12, 2018, 07:33:02 am by jacobly »

Offline gameblabla

  • Super User
  • Join Date: May 2015
  • Location:
  • Posts: 779
  • Post Rating Ratio: +15/-7
  • TI-nspire porter
Re: Fast sprite rendering in an RGB565 framebuffer
« Reply #4 on: April 12, 2018, 12:47:42 pm »
Edit: The fact that x and y are never used indicates there is something missing in the logic.  I would just do:
:-[
That's true but i was trying to make it work without any x/y axises first.

Thanks, i can confirm your routine works perfectly now !
EDIT: Also its much faster too.
« Last Edit: April 12, 2018, 01:18:18 pm by gameblabla »
  • Calculators owned: TI Nspire CX, TI-89

 


You can also use the following HTML or bulletin board code to share it on your page or forum signature!


Also do not forget to check our affiliates below.
Planet Casio TI-Planet Calc.news BroniesQC BosaikNet Velocity Games