lav-sdl

SDL верзија програма Лавиринт
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување a91fd2986ddd67cf89dc68e314c802e2498760c5
родитељ b5210924e6d71c7c9adc373dac41e9a1cab5260b
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Thu, 17 Aug 2023 19:38:52 +0200

Optimize drawing by buffering statical parts of display

Signed-off-by: Страхиња Радић <contact@strahinja.org>

Diffstat:
Mlav-sdl.c | 257+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
измењених датотека: 1, додавања: 161(+), брисања: 96(-)

diff --git a/lav-sdl.c b/lav-sdl.c @@ -41,7 +41,8 @@ enum { CELL_WALL, CELL_FAIL, CELL_OK, - CELL_HERO + CELL_START, + CELL_END }; enum { @@ -106,6 +107,7 @@ static int screen_height = DEFAULT_HEIGHT; static SDL_Texture* sprites = NULL; static int state = STATE_SEARCHING_PAUSED; static SDL_Texture* ter16_texture = NULL; +static SDL_Texture* background = NULL; static SDL_Window* window = NULL; void assign_pointIF(const SDL_Point* from, SDL_FPoint* to); @@ -116,12 +118,13 @@ void draw(void); void draw_help_dialog(void); void draw_text(const int x, const int y, const int font_width, const int font_height, SDL_Texture* font_tex, const char* text, ...); +void get_hero_sprite_xy(int* x, int* y); void get_sprite_xy(const char cell, int* x, int* y); void handle_event(SDL_Event* event); -void labyrinth_coord_to_screen_coord(const int x, const int y, float* to_x, - float* to_y); -void labyrinth_coord_to_screen_coordF(const float x, const float y, float* to_x, - float* to_y); +void labyrinth_coord_to_screen_coord(const int x, const int y, + const float startx, const float starty, float* to_x, float* to_y); +void labyrinth_coord_to_screen_coordF(const float x, const float y, + const float startx, const float starty, float* to_x, float* to_y); void load_textures(void); void load_labyrinth(const char* pathname); int location_pop(SDL_Point* location); @@ -172,6 +175,8 @@ cleanup(void) free(labyrinth.cells[y]); free(labyrinth.cells); + if (background) + SDL_DestroyTexture(background); if (ter16_texture) SDL_DestroyTexture(ter16_texture); if (sprites) @@ -188,66 +193,120 @@ draw(void) { SDL_Rect bg_rect, cell_rect; SDL_FRect dest_rect; + SDL_DisplayMode mode; int x, y; - int cx = screen_width / 2, cy = screen_height / 2; + int cx, cy; + float startx, starty; - SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); - SDL_RenderClear(renderer); + cx = screen_width / 2; + cy = screen_height / 2; + + startx = cx - labyrinth.width / 2 * CELL_SIZE * scale_factor; + starty = cy - labyrinth.height / 2 * CELL_SIZE * scale_factor; - bg_rect.x = cx - labyrinth.width / 2 * CELL_SIZE * scale_factor; - bg_rect.y = cy - labyrinth.height / 2 * CELL_SIZE * scale_factor; + bg_rect.x = 0; + bg_rect.y = 0; bg_rect.w = CELL_SIZE * scale_factor * labyrinth.width; bg_rect.h = CELL_SIZE * scale_factor * labyrinth.height; - SDL_SetRenderDrawColor(renderer, 0x22, 0x22, 0x22, SDL_ALPHA_OPAQUE); - SDL_RenderFillRect(renderer, &bg_rect); + + SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderClear(renderer); cell_rect.w = CELL_SIZE; cell_rect.h = CELL_SIZE; - dest_rect.w = CELL_SIZE * scale_factor; - dest_rect.h = CELL_SIZE * scale_factor; + /* Render background */ + if (!background) + { + if (SDL_GetCurrentDisplayMode(0, &mode) < 0) + { + print_error("SDL_GetCurrentDisplayMode failed: %s", + SDL_GetError()); + exit(1); + } - for (y = 0; y < labyrinth.height; y++) - for (x = 0; x < labyrinth.width; x++) + background = SDL_CreateTexture(renderer, mode.format, + SDL_TEXTUREACCESS_TARGET, bg_rect.w, bg_rect.h); + if (!background) { - if (x == start.x && y == start.y - && (animation.active || hero.x != x - || hero.y != y)) - { - cell_rect.x = 1 + 8 * (CELL_SIZE + 1); - cell_rect.y = 1; - } - else if (x == end.x && y == end.y - && (animation.active || hero.x != x - || hero.y != y)) + print_error("SDL_CreateTextureFromSurface failed: %s", + SDL_GetError()); + exit(1); + } + if (SDL_SetRenderTarget(renderer, background) < 0) + { + print_error("SDL_SetRenderTarget failed: %s", + SDL_GetError()); + exit(1); + } + + SDL_SetRenderDrawColor(renderer, 0x22, 0x22, 0x22, + SDL_ALPHA_OPAQUE); + SDL_RenderFillRect(renderer, &bg_rect); + + dest_rect.w = CELL_SIZE * scale_factor; + dest_rect.h = CELL_SIZE * scale_factor; + for (y = 0; y < labyrinth.height; y++) + for (x = 0; x < labyrinth.width; x++) { - cell_rect.x = 1 + 7 * (CELL_SIZE + 1); - cell_rect.y = 1; - } - else if (animation.active - && labyrinth.cells[y][x] == CELL_HERO) - get_sprite_xy(CELL_EMPTY, &cell_rect.x, - &cell_rect.y); - else get_sprite_xy(labyrinth.cells[y][x], &cell_rect.x, &cell_rect.y); - labyrinth_coord_to_screen_coord(x, y, &dest_rect.x, - &dest_rect.y); + labyrinth_coord_to_screen_coord(x, y, 0.0f, + 0.0f, &dest_rect.x, &dest_rect.y); + SDL_RenderCopyF(renderer, sprites, &cell_rect, + &dest_rect); + } + + SDL_SetRenderTarget(renderer, NULL); + } + + /* Draw buffered copy of background */ + dest_rect.x = startx; + dest_rect.y = starty; + dest_rect.w = bg_rect.w; + dest_rect.h = bg_rect.h; + SDL_RenderCopyF(renderer, background, &bg_rect, &dest_rect); + + /* Draw nuggets/cobwebs */ + dest_rect.w = CELL_SIZE * scale_factor; + dest_rect.h = CELL_SIZE * scale_factor; + for (y = 0; y < labyrinth.height; y++) + for (x = 0; x < labyrinth.width; x++) + { + if ((labyrinth.cells[y][x] != CELL_OK + && labyrinth.cells[y][x] != CELL_FAIL) + || (x == start.x && y == start.y) + || (x == end.x && y == end.y)) + continue; + + get_sprite_xy(labyrinth.cells[y][x], &cell_rect.x, + &cell_rect.y); + labyrinth_coord_to_screen_coord(x, y, startx, starty, + &dest_rect.x, &dest_rect.y); SDL_RenderCopyF(renderer, sprites, &cell_rect, &dest_rect); } - draw_text(bg_rect.x, bg_rect.y + bg_rect.h, TER16_WIDTH, TER16_HEIGHT, - ter16_texture, - "Column: %2d, Row: %2d F1 = Help Status: %s", hero.x + 1, - hero.y + 1, state_descriptions[state]); + /* Render hero */ + cell_rect.w = CELL_SIZE; + cell_rect.h = CELL_SIZE; + dest_rect.w = CELL_SIZE * scale_factor; + dest_rect.h = CELL_SIZE * scale_factor; + + get_hero_sprite_xy(&cell_rect.x, &cell_rect.y); if (animation.active) - { labyrinth_coord_to_screen_coordF(animation.position.x, - animation.position.y, &dest_rect.x, &dest_rect.y); - get_sprite_xy((const char)CELL_HERO, &cell_rect.x, &cell_rect.y); - SDL_RenderCopyF(renderer, sprites, &cell_rect, &dest_rect); + animation.position.y, startx, starty, + &dest_rect.x, &dest_rect.y); + else + labyrinth_coord_to_screen_coord(hero.x, hero.y, startx, + starty, &dest_rect.x, &dest_rect.y); + + SDL_RenderCopyF(renderer, sprites, &cell_rect, &dest_rect); + + if (animation.active) + { animation.position.x += animation.delta.x; animation.position.y += animation.delta.y; animation.step++; @@ -256,10 +315,15 @@ draw(void) animation.active = 0; hero.x = (int)animation.destination.x; hero.y = (int)animation.destination.y; - labyrinth.cells[hero.y][hero.x] = CELL_HERO; } } + /* Render status */ + draw_text(startx, starty + bg_rect.h, TER16_WIDTH, + TER16_HEIGHT, ter16_texture, + "Column: %2d, Row: %2d F1 = Help Status: %s", hero.x + 1, + hero.y + 1, state_descriptions[state]); + if (help_shown) draw_help_dialog(); @@ -375,10 +439,38 @@ draw_text(const int x, const int y, const int font_width, const int font_height, } void +get_hero_sprite_xy(int* x, int* y) +{ + switch (state) + { + case STATE_SUCCESS: + *x = 1 + 4 * (CELL_SIZE + 1); + *y = 1; + break; + case STATE_FAILURE: + *x = 1 + 6 * (CELL_SIZE + 1); + *y = 1; + break; + default: + *x = 1 + 3 * (CELL_SIZE + 1); + *y = 1; + break; + } +} + +void get_sprite_xy(const char cell, int* x, int* y) { switch (cell) { + case CELL_START: + *x = 1 + 8 * (CELL_SIZE + 1); + *y = 1; + break; + case CELL_END: + *x = 1 + 7 * (CELL_SIZE + 1); + *y = 1; + break; case CELL_WALL: *x = 1; *y = 1; @@ -391,23 +483,6 @@ get_sprite_xy(const char cell, int* x, int* y) *x = 1 + 2 * (CELL_SIZE + 1); *y = 1; break; - case CELL_HERO: - switch (state) - { - case STATE_SUCCESS: - *x = 1 + 4 * (CELL_SIZE + 1); - *y = 1; - break; - case STATE_FAILURE: - *x = 1 + 6 * (CELL_SIZE + 1); - *y = 1; - break; - default: - *x = 1 + 3 * (CELL_SIZE + 1); - *y = 1; - break; - } - break; default: *x = 1 + 5 * (CELL_SIZE + 1); *y = 1; @@ -423,6 +498,9 @@ handle_event(SDL_Event* event) return; switch (event->type) { + case SDL_QUIT: + running = 0; + break; case SDL_WINDOWEVENT: switch (event->window.event) { @@ -478,27 +556,19 @@ handle_event(SDL_Event* event) } void -labyrinth_coord_to_screen_coord(const int x, const int y, float* to_x, - float* to_y) +labyrinth_coord_to_screen_coord(const int x, const int y, const float startx, + const float starty, float* to_x, float* to_y) { - int cx = screen_width / 2, cy = screen_height / 2; - - *to_x = cx - labyrinth.width / 2 * CELL_SIZE * scale_factor - + x * CELL_SIZE * scale_factor; - *to_y = cy - labyrinth.height / 2 * CELL_SIZE * scale_factor - + y * CELL_SIZE * scale_factor; + *to_x = startx + x * CELL_SIZE * scale_factor; + *to_y = starty + y * CELL_SIZE * scale_factor; } void -labyrinth_coord_to_screen_coordF(const float x, const float y, float* to_x, - float* to_y) +labyrinth_coord_to_screen_coordF(const float x, const float y, + const float startx, const float starty, float* to_x, float* to_y) { - int cx = screen_width / 2, cy = screen_height / 2; - - *to_x = cx - labyrinth.width / 2 * CELL_SIZE * scale_factor - + x * CELL_SIZE * scale_factor; - *to_y = cy - labyrinth.height / 2 * CELL_SIZE * scale_factor - + y * CELL_SIZE * scale_factor; + *to_x = startx + x * CELL_SIZE * scale_factor; + *to_y = starty + y * CELL_SIZE * scale_factor; } void @@ -620,9 +690,10 @@ load_labyrinth(const char* pathname) ch, ch); } - hero.x = start.x; - hero.y = start.y; - labyrinth.cells[hero.y][hero.x] = CELL_HERO; + hero.x = start.x; + hero.y = start.y; + labyrinth.cells[start.y][start.x] = CELL_START; + labyrinth.cells[end.y][end.x] = CELL_END; fclose(input); } @@ -669,7 +740,6 @@ next_step(void) animation.step = 1; animation.final_step = ANIM_STEPS; animation.active = 1; - // labyrinth.cells[hero.y][hero.x] = CELL_HERO; } else if (passable(hero.x, hero.y - 1)) { @@ -684,7 +754,6 @@ next_step(void) animation.step = 1; animation.final_step = ANIM_STEPS; animation.active = 1; - // labyrinth.cells[hero.y][hero.x] = CELL_HERO; } else if (passable(hero.x + 1, hero.y)) { @@ -699,7 +768,6 @@ next_step(void) animation.step = 1; animation.final_step = ANIM_STEPS; animation.active = 1; - // labyrinth.cells[hero.y][hero.x] = CELL_HERO; } else if (passable(hero.x, hero.y + 1)) { @@ -714,7 +782,6 @@ next_step(void) animation.step = 1; animation.final_step = ANIM_STEPS; animation.active = 1; - // labyrinth.cells[hero.y][hero.x] = CELL_HERO; } else { @@ -744,7 +811,8 @@ int passable(const int x, const int y) { return (x >= 0 && x < labyrinth.width && y >= 0 && y < labyrinth.height - && labyrinth.cells[y][x] == CELL_EMPTY); + && (labyrinth.cells[y][x] == CELL_EMPTY + || labyrinth.cells[y][x] == CELL_END)); } void @@ -777,15 +845,13 @@ reset(void) for (int y = 0; y < labyrinth.height; y++) for (int x = 0; x < labyrinth.width; x++) if (labyrinth.cells[y][x] == CELL_FAIL - || labyrinth.cells[y][x] == CELL_OK - || labyrinth.cells[y][x] == CELL_HERO) + || labyrinth.cells[y][x] == CELL_OK) labyrinth.cells[y][x] = CELL_EMPTY; - hero.x = start.x; - hero.y = start.y; - labyrinth.cells[hero.y][hero.x] = CELL_HERO; - state = STATE_SEARCHING_PAUSED; - location_pointer = 0; - redraw = 1; + hero.x = start.x; + hero.y = start.y; + state = STATE_SEARCHING_PAUSED; + location_pointer = 0; + redraw = 1; } void @@ -856,7 +922,6 @@ main(int argc, char** argv) if (state == STATE_SEARCHING) { next_step(); - SDL_Delay(SEARCHING_DELAY); } if (redraw) @@ -864,8 +929,8 @@ main(int argc, char** argv) draw(); redraw = 0; } - } + /* TODO: More sophisticated framerate/vsync/delay handling */ SDL_Delay(10); }