add much-needed optimizations and enhance the snake example game
This commit is contained in:
+135
-18
@@ -3,12 +3,144 @@
|
||||
engine_internal_state_t *internal_state = NULL;
|
||||
game_state_t *game_state = NULL;
|
||||
|
||||
void
|
||||
mark_dirty_rect(int x, int y, int w, int h)
|
||||
{
|
||||
if (w <= 0 || h <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// clip rectangle to the framebuffer
|
||||
if (x < 0) {
|
||||
w += x;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if (y < 0) {
|
||||
h += y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
if (x + w > game_state->width) {
|
||||
w = game_state->width - x;
|
||||
}
|
||||
|
||||
if (y + h > game_state->height) {
|
||||
h = game_state->height - y;
|
||||
}
|
||||
|
||||
if (w <= 0 || h <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_Rect rect = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
.w = w,
|
||||
.h = h
|
||||
};
|
||||
|
||||
if (!game_state->framebuffer_dirty) {
|
||||
game_state->dirty_rect = rect;
|
||||
game_state->framebuffer_dirty = true;
|
||||
return;
|
||||
}
|
||||
|
||||
int left = game_state->dirty_rect.x < rect.x
|
||||
? game_state->dirty_rect.x
|
||||
: rect.x;
|
||||
|
||||
int top = game_state->dirty_rect.y < rect.y
|
||||
? game_state->dirty_rect.y
|
||||
: rect.y;
|
||||
|
||||
int old_right =
|
||||
game_state->dirty_rect.x + game_state->dirty_rect.w;
|
||||
|
||||
int new_right = rect.x + rect.w;
|
||||
|
||||
int old_bottom =
|
||||
game_state->dirty_rect.y + game_state->dirty_rect.h;
|
||||
|
||||
int new_bottom = rect.y + rect.h;
|
||||
|
||||
int right = old_right > new_right
|
||||
? old_right
|
||||
: new_right;
|
||||
|
||||
int bottom = old_bottom > new_bottom
|
||||
? old_bottom
|
||||
: new_bottom;
|
||||
|
||||
game_state->dirty_rect = (SDL_Rect) {
|
||||
.x = left,
|
||||
.y = top,
|
||||
.w = right - left,
|
||||
.h = bottom - top
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
upload_dirty_texture(void)
|
||||
{
|
||||
if (!game_state->framebuffer_dirty) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SDL_Texture *texture =
|
||||
internal_state->sdl_state->texture;
|
||||
|
||||
SDL_Rect rect = game_state->dirty_rect;
|
||||
|
||||
void *locked_pixels = NULL;
|
||||
int locked_pitch = 0;
|
||||
|
||||
if (!SDL_LockTexture(
|
||||
texture,
|
||||
&rect,
|
||||
&locked_pixels,
|
||||
&locked_pitch
|
||||
)) {
|
||||
SDL_Log(
|
||||
"SDL_LockTexture failed: %s",
|
||||
SDL_GetError()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t source_pitch =
|
||||
(size_t)game_state->width * sizeof(uint32_t);
|
||||
|
||||
const size_t row_bytes =
|
||||
(size_t)rect.w * sizeof(uint32_t);
|
||||
|
||||
const uint8_t *source =
|
||||
(const uint8_t *)game_state->framebuffer +
|
||||
(size_t)rect.y * source_pitch +
|
||||
(size_t)rect.x * sizeof(uint32_t);
|
||||
|
||||
uint8_t *destination =
|
||||
(uint8_t *)locked_pixels;
|
||||
|
||||
for (int y = 0; y < rect.h; ++y) {
|
||||
memcpy(
|
||||
destination + (size_t)y * locked_pitch,
|
||||
source + (size_t)y * source_pitch,
|
||||
row_bytes
|
||||
);
|
||||
}
|
||||
|
||||
SDL_UnlockTexture(texture);
|
||||
|
||||
game_state->framebuffer_dirty = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
engine_start() {
|
||||
// main game loop
|
||||
while(game_state->is_running) {
|
||||
uint64_t start = SDL_GetPerformanceCounter();
|
||||
|
||||
// poll events
|
||||
while (SDL_PollEvent(&game_state->event)) {
|
||||
internal_state->engine_poll_events();
|
||||
@@ -18,11 +150,7 @@ engine_start() {
|
||||
internal_state->engine_update_framebuffer();
|
||||
|
||||
// update the texture with the modified framebuffer
|
||||
SDL_UpdateTexture(
|
||||
internal_state->sdl_state->texture,
|
||||
NULL, game_state->framebuffer,
|
||||
internal_state->sdl_state->width * sizeof(uint32_t)
|
||||
);
|
||||
upload_dirty_texture();
|
||||
|
||||
SDL_RenderClear(
|
||||
internal_state->sdl_state->renderer
|
||||
@@ -37,17 +165,6 @@ engine_start() {
|
||||
SDL_RenderPresent(
|
||||
internal_state->sdl_state->renderer
|
||||
);
|
||||
|
||||
uint64_t end = SDL_GetPerformanceCounter();
|
||||
|
||||
double elapsed =
|
||||
(double)(end - start) /
|
||||
(double)SDL_GetPerformanceFrequency();
|
||||
|
||||
// cap the framerate at '1.0/TARGET_FRAME' fps
|
||||
if (elapsed < TARGET_FRAME) {
|
||||
SDL_Delay((TARGET_FRAME - elapsed) * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user