Here is a blit function for a graphics library I made.
I've built a small graphics library that uses an palette-indexed spritesheet to hold all of the game's sprites. The blit function copies parts of the spritesheet into the screen buffer, according to the sprite position on the screen.
Everything works very well, and it seems to be optimized quite well by the compiler, as it uses a lot of vectorized instructions, but I'm wondering if there is a way to make it more efficient.
Here is the code of the function, alongside the code of the data structures.
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct ScreenManager ScreenManager;
struct ScreenManager
{
uint8_t* screen;
size_t screen_width;
size_t screen_height;
uint32_t* buffer;
void* sdl_window;
void* sdl_renderer;
void* sdl_texture;
const uint32_t* palette;
};
typedef struct SpritesheetSlice SpritesheetSlice;
struct SpritesheetSlice
{
size_t x;
size_t y;
size_t width;
size_t height;
};
typedef struct Sprite Sprite;
struct Sprite
{
double x;
double y;
SpritesheetSlice* sss;
bool visible;
bool allocated;
};
typedef struct SpriteManager SpriteManager;
struct SpriteManager
{
const uint8_t* spritesheet;
size_t spritesheet_width;
size_t spritesheet_height;
uint8_t* mask;
Sprite* sprites;
size_t sprites_maximum;
size_t sprites_free;
};
void
blit(ScreenManager* screen_manager, SpriteManager* sprite_manager)
{
for (size_t i = 0; i < sprite_manager->sprites_maximum; ++i)
{
if (sprite_manager->sprites[i].allocated)
{
size_t sprite_position_x = sprite_manager->sprites[i].x;
size_t sprite_position_y = sprite_manager->sprites[i].y;
size_t sss_offset_x = sprite_manager->sprites[i].sss->x;
size_t sss_offset_y = sprite_manager->sprites[i].sss->y;
size_t sss_width = sprite_manager->sprites[i].sss->width;
size_t sss_height = sprite_manager->sprites[i].sss->height;
size_t screen_height = screen_manager->screen_height;
size_t screen_width = screen_manager->screen_width;
size_t screen_size = screen_height * screen_width;
size_t scanline_in_index = sprite_manager->spritesheet_width * sss_offset_y + sss_offset_x;
const uint8_t* scanline_in = sprite_manager->spritesheet;
size_t scanline_out_index = screen_width * sprite_position_y + sprite_position_x;
uint8_t* scanline_out = screen_manager->screen;
if (screen_width - sprite_position_x < sss_width)
{
sss_width = screen_width - sprite_position_x;
}
for (size_t y = 0; y < sss_height; ++y)
{
for (size_t x = 0; x < sss_width; ++x)
{
uint8_t pixel = scanline_in[x + scanline_in_index];
if (pixel && scanline_out_index <= screen_size)
{
scanline_out[x + scanline_out_index] = pixel;
}
}
scanline_in_index += sprite_manager->spritesheet_width;
scanline_out_index += screen_width;
}
}
}
return;
}