Join us on Discord!
You can help CodeWalrus stay online by donating here.

Fast sprite rendering in an RGB565 framebuffer

Started by gameblabla, April 12, 2018, 12:23:57 AM

Previous topic - Next topic

0 Members and 2 Guests are viewing this topic.

gameblabla

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.

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)

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) :

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: None (used to own an Nspire and TI-89)

tr1p1ea

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?

gameblabla

#2
Quote from: tr1p1ea 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?
Thanks for the help.
I came up with this :

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)

QuoteOr 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.
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...
  • Calculators owned: None (used to own an Nspire and TI-89)

jacobly

#3
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:

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;
    }
}

gameblabla

#4
Quote from: jacobly on April 12, 2018, 07:22:09 AM
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.
  • Calculators owned: None (used to own an Nspire and TI-89)

Powered by EzPortal