I've seen some other people ask questions about gfx_RotateSprite() and it's other forms, and I understand how to use it now but not how to use it efficiently. I've found that using it with SwapDraw() is nice and speedy, so I've used it like this:
Code:
sprite_buffer = gfx_MallocSprite(sprite_width, sprite_height);

while (stuff == true)
{
     gfx_RotateSprite(sprite, sprite_buffer, angle);

     /* I don't feel like writing more pseudo code, but all your calculations should go here */

    gfx_FillScreen(0);

     gfx_SpriteNoClip(Sprite, 20, 20);

     gfx_SwapDraw();

     ++angle;
}


So this works by taking the sprite you want to rotate and saving it's rotated form into a buffer sprite during the time when all the interrupts are taking care or SwapDraw(), or however it works. FillScreen() makes sure there's a clean buffer to draw the freshly rotated sprite, and everything's blitted normally. Simple stuff. However there is one big flaw that has to do with the sprite input. Since all sprites put in have to be square it means that I have to add a bunch of useless transparent pixels as extra buffer space. If I'm using an array of sprites then this really becomes an issue since some sprites might be smaller than others in the array. All those extra pixels take up RAM, and RAM is precious. What I've been trying to do is find some sort of variant of gfx_CopyRectangle(), but I don't know how to input a sprite as a gfx_location type, so I'm stuck with the RAM-eating solution. If I could somehow malloc up a larger square sprite, and copy the contents of another smaller sprite to it (which would theoretically allow for building sprites from smaller spritesheets and copying the buffer/screen to sprites for quicker rendering) then I could use smaller sprite arrays and quickly copy them to a larger sprite and rotate the thing too, and then draw them normally without having to worry about edges of the sprite getting cut off during rotation. Does anybody have any ideas on how to pull this off?
All sprites are simply a data structure composing of the following:


Code:
typedef struct {
    uint8_t width;
    uint8_t height;
    uint8_t data[];
} gfx_sprite_t


You could use gfx_MallocSprite to make a whole bunch of sprites, and then use the memcpy function to copy the data element to other sprites.
I just to blitbuffer lol
Sorry Mateo, I don't code efficiently, and I confess that!
Now Imma go hide in my pit.....you'll never find the grass block! Burn the MYCELIUMMMM!!!
TimmyTurner62 wrote:
I just to blitbuffer 0x5
Sorry Mateo, I don't code efficiently, and I confess that!
Now Imma go hide in my pit.....you'll never find the grass block! Burn the MYCELIUMMMM!!!


Ehm, what does blitting graphics have to do with allocating memory space and memcpy'ing the sprite data pointers?

King Dub Dub wrote:
If I could somehow malloc up a larger square sprite, and copy the contents of another smaller sprite to it (which would theoretically allow for building sprites from smaller spritesheets and copying the buffer/screen to sprites for quicker rendering) then I could use smaller sprite arrays and quickly copy them to a larger sprite and rotate the thing too, and then draw them normally without having to worry about edges of the sprite getting cut off during rotation.


This sounds like a tilemap?

Remember that the element tiles of the tilemap struct is just a reference to an array of sprite pointers.
MateoConLechuga wrote:
All sprites are simply a data structure composing of the following:


Code:
typedef struct {
    uint8_t width;
    uint8_t height;
    uint8_t data[];
} gfx_sprite_t


You could use gfx_MallocSprite to make a whole bunch of sprites, and then use the memcpy function to copy the data element to other sprites.
KaluW_ wrote:
This sounds like a tilemap?

Remember that the element tiles of the tilemap struct is just a reference to an array of sprite pointers.

I didn't explain too well I guess, but I mean I want to copy a sprite and paste it at given coordinates in a larger sprite.

Code:
//takes an input sprite and pastes it into another sprite at given coordinates:
void CopyPasta(gfx_sprite_t *spriteIn, gfx_sprite_t *spriteOut, uint24_t x, uint8_t y)
{
    uint24_t start_write = (spriteOut->width * y) + x;

    for(uint24_t j = 0; j < spriteIn->height; ++j)
    {
        for(uint24_t i = 0; i < spriteIn->width; ++i)
        {
            //adding a check for transparency is slower than one would think, it's best to just redraw the extra zeros:
            spriteOut->data[start_write + i] = spriteIn->data[(j * spriteIn->width) + i];
        }

        start_write += spriteOut->width;
    }
}

Wrote this in 4 hours and didn't steal any code from Stack Overflow, I'm proud of myself for actually being competent! I even messed around with optimizations and timing with the internal clock and this is pretty speedy. It's slow enough to notice if you know it's there, but to a fresh eye the delay isn't an issue. I pretty much just inserted this in the graphx sprite rotation example and malloc'd a 46x46 sprite and then copypasta'd a 40x40 sprite in. Taking the enlarged sprite and passing it to the rotation functions worked fine. The only issue was that gfx_MallocSprite doesn't create an empty sprite, so I had to have a for() loop fill it with zeros myself, which also caused some speed drop. Thankfully it only needs to be run once, but even then I'd like feedback on optimization, and maybe an explanation on why sizeof(sprite->data) doesn't compile (invalid application of 'sizeof' to an incomplete type 'uint8_t []'). I might work on a tiny library for this just for ease of use, this could allow for some serious compression if implemented cleanly.
King Dub Dub wrote:
and maybe an explanation on why sizeof(sprite->data) doesn't compile (invalid application of 'sizeof' to an incomplete type 'uint8_t []').

A sprite is a width and a height, followed by some number of data bytes. The compiler doesn't know how many data bytes there are, since that depends on the size of the sprite - if you gave it a pointer to a 2x2 sprite, there would only be 4 bytes of data, while a 10x10 sprite would have 100 bytes of data. C doesn't provide a mechanism to say "the number of data bytes is equal to width * height" (and that's probably a good thing since it means that you always know that sizeof() won't do any potentially expensive computations, and also that the size of something won't randomly change). So, because the compiler doesn't know how much data there is, you'll have to just use width * height instead of sizeof.

As for potential optimizations, I'd recommend using memcpy instead of the inner for loop since you're copying a contiguous array of bytes, though the llvm toolchain might optimize that for you. You could also add spriteIn->width to j each loop and then just use j instead of j *spriteIn->width, which would prevent you from having to do a multiplication each loop.
Done.
Code:
//takes an input sprite and pastes it into another sprite at given coordinates:
void CopyPasta(gfx_sprite_t *spriteIn, gfx_sprite_t *spriteOut, uint24_t x, uint8_t y)
{
    uint24_t start_write = (spriteOut->width * y) + x;

    //write out input sprite row by row into the output sprite:
    for(uint24_t j = 0; j < (spriteIn->height * spriteIn->width); j += spriteIn->width)
    {
        //copy the row of the input to the position needed in the output:
        memcpy(&spriteOut->data[start_write], &spriteIn->data[j], spriteIn->width);

        //add the output sprite's width to move to the next row plus the given X that was added at the start:
        start_write += spriteOut->width;
    }
}

I didn't know how to use memcpy() with specific starting points in arrays, so I added the magic symbols that make problems go away and it works now!
A few optimizations:


Code:
void CopyPasta(const gfx_sprite_t *spriteIn, gfx_sprite_t *spriteOut, uint24_t x, uint8_t y)
{
    const uint24_t width = spriteIn->width;
    const uint24_t sprite_size = spriteIn->height * width;
    uint24_t start_write = (spriteOut->width * y) + x;

    //write out input sprite row by row into the output sprite:
    for(uint24_t j = 0; j < sprite_size; j += width)
    {
        //copy the row of the input to the position needed in the output:
        memcpy(&spriteOut->data[start_write], &spriteIn->data[j], width);

        //add the output sprite's width to move to the next row plus the given X that was added at the start:
        start_write += width;
    }
}
I should've posted earlier Mateo, but you have a typo on the last functional line, width should be spriteOut->width, like this:

Code:
void CopyPasta(const gfx_sprite_t *spriteIn, gfx_sprite_t *spriteOut, uint24_t x, uint8_t y)
{
    const uint24_t width = spriteIn->width;
    const uint24_t sprite_size = spriteIn->height * width;
    uint24_t start_write = (spriteOut->width * y) + x;

    //write out input sprite row by row into the output sprite:
    for(uint24_t j = 0; j < sprite_size; j += width)
    {
        //copy the row of the input to the position needed in the output:
        memcpy(&spriteOut->data[start_write], &spriteIn->data[j], width);

        //add the output sprite's width to move to the next row plus the given X that was added at the start:
        start_write += spriteOut->width;
    }
}


And that peeps, is why you never steal code without testing it thoroughly first. The mind positively reels at the possibilities here, and I think I might make a little demo library or collection of sprite tools at some point as a side project, I'm sure I can make a decent way to obfuscate code with weird functions and cripple the readability whilst saving on RAM and flash size.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement