@@ 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);
}