Files
dangerzone/src/engine/engine.c
T

176 lines
3.4 KiB
C

#include "engine.h"
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) {
// poll events
while (SDL_PollEvent(&game_state->event)) {
internal_state->engine_poll_events();
}
// call the user-defined framebuffer manipulation function
internal_state->engine_update_framebuffer();
// update the texture with the modified framebuffer
upload_dirty_texture();
SDL_RenderClear(
internal_state->sdl_state->renderer
);
SDL_RenderTexture(
internal_state->sdl_state->renderer,
internal_state->sdl_state->texture,
NULL, NULL
);
SDL_RenderPresent(
internal_state->sdl_state->renderer
);
}
}
void
engine_stop() {
engine_sdl_destroy(internal_state->sdl_state);
free(internal_state);
free(game_state);
}