189 lines
6.6 KiB
C
189 lines
6.6 KiB
C
#include "gui.h"
|
|
#include <SDL.h>
|
|
#include <SDL_image.h>
|
|
#include <SDL_ttf.h>
|
|
#include <stdbool.h>
|
|
|
|
const SCREEN_WIDTH = 800;
|
|
const SCREEN_HEIGHT = 920;
|
|
|
|
// these are meant to be immutable like in Rust
|
|
// unfortunately, C does not allow that
|
|
SDL_Window *window = NULL;
|
|
// SDL_Surface* screenSurface = NULL;
|
|
SDL_Renderer *window_renderer = NULL;
|
|
SDL_Texture *tile_textures[13];
|
|
SDL_Rect tile_size;
|
|
SDL_Texture *game_over_texture = NULL;
|
|
SDL_Texture *you_won_texture = NULL;
|
|
TTF_Font *Sans = NULL;
|
|
SDL_Color Black = { 0, 0, 0 };
|
|
|
|
SDL_Texture *texture_from_png(char *n) {
|
|
SDL_Surface *s = IMG_Load(n);
|
|
SDL_Texture *t = SDL_CreateTextureFromSurface(window_renderer, s);
|
|
SDL_FreeSurface(s);
|
|
return t;
|
|
}
|
|
|
|
void gui_init() {
|
|
|
|
// Initialize SDL
|
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
|
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
|
|
}
|
|
|
|
window = SDL_CreateWindow("2048", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
|
|
if (window == NULL) {
|
|
printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
|
|
}
|
|
|
|
TTF_Init();
|
|
// screenSurface = SDL_GetWindowSurface(window);
|
|
// SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 255, 255, 255));
|
|
|
|
// create renderer and render white window
|
|
window_renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
|
SDL_SetRenderDrawColor(window_renderer, 0xFF, 0xFF, 0xFF, 0xFF);
|
|
SDL_RenderClear(window_renderer);
|
|
SDL_RenderPresent(window_renderer);
|
|
// SDL_UpdateWindowSurface(window);
|
|
|
|
// load up textures
|
|
tile_textures[0] = texture_from_png("res/tile.png");
|
|
tile_textures[1] = texture_from_png("res/1.png");
|
|
tile_textures[2] = texture_from_png("res/2.png");
|
|
tile_textures[3] = texture_from_png("res/4.png");
|
|
tile_textures[4] = texture_from_png("res/8.png");
|
|
tile_textures[5] = texture_from_png("res/16.png");
|
|
tile_textures[6] = texture_from_png("res/32.png");
|
|
tile_textures[7] = texture_from_png("res/64.png");
|
|
tile_textures[8] = texture_from_png("res/128.png");
|
|
tile_textures[9] = texture_from_png("res/256.png");
|
|
tile_textures[10] = texture_from_png("res/512.png");
|
|
tile_textures[11] = texture_from_png("res/1024.png");
|
|
tile_textures[12] = texture_from_png("res/2048.png");
|
|
tile_size.x = 0;
|
|
tile_size.y = 0;
|
|
SDL_QueryTexture(tile_textures[0], NULL, NULL, &tile_size.w, &tile_size.h);
|
|
|
|
game_over_texture = texture_from_png("res/game_over.png");
|
|
you_won_texture = texture_from_png("res/you_won.png");
|
|
|
|
Sans = TTF_OpenFont("res/LiberationSerif-Regular.ttf", 92);
|
|
}
|
|
|
|
void gui_destroy() {
|
|
// Destroy window
|
|
SDL_DestroyWindow(window);
|
|
window = NULL;
|
|
SDL_DestroyRenderer(window_renderer);
|
|
window_renderer = NULL;
|
|
for (int i = 0; i < 13; i++) {
|
|
SDL_DestroyTexture(tile_textures[i]);
|
|
tile_textures[i] = NULL;
|
|
}
|
|
SDL_DestroyTexture(game_over_texture);
|
|
game_over_texture = NULL;
|
|
SDL_DestroyTexture(you_won_texture);
|
|
you_won_texture = NULL;
|
|
|
|
TTF_Quit();
|
|
// Quit SDL subsystems
|
|
SDL_Quit();
|
|
}
|
|
|
|
void gui_loop(Game *game) {
|
|
bool quit = false;
|
|
bool needs_redraw = true; // there's no need to redraw window when nothing's changed. will be set to false later. first run has to be always done
|
|
SDL_Event e;
|
|
|
|
while (!quit) {
|
|
while (SDL_PollEvent(&e) != 0) {
|
|
switch (e.type) {
|
|
/* Keyboard event */
|
|
/* Pass the event data onto PrintKeyInfo() */
|
|
case SDL_KEYDOWN:
|
|
switch (e.key.keysym.sym) {
|
|
case SDLK_h:
|
|
case SDLK_LEFT:
|
|
case SDLK_4:
|
|
needs_redraw = true;
|
|
game_move(game, Left);
|
|
break;
|
|
case SDLK_l:
|
|
case SDLK_RIGHT:
|
|
case SDLK_6:
|
|
needs_redraw = true;
|
|
game_move(game, Right);
|
|
break;
|
|
case SDLK_j:
|
|
case SDLK_DOWN:
|
|
case SDLK_2:
|
|
needs_redraw = true;
|
|
game_move(game, Down);
|
|
break;
|
|
case SDLK_k:
|
|
case SDLK_UP:
|
|
case SDLK_8:
|
|
needs_redraw = true;
|
|
game_move(game, Up);
|
|
break;
|
|
}
|
|
break;
|
|
case SDL_QUIT:
|
|
quit = 1;
|
|
break;
|
|
case SDL_WINDOWEVENT_SHOWN:
|
|
case SDL_WINDOWEVENT_EXPOSED:
|
|
needs_redraw = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (needs_redraw) {
|
|
SDL_RenderClear(window_renderer);
|
|
SDL_Rect tile_rect = tile_size;
|
|
for (int i = 0; i < game->field_size_x; i++) {
|
|
tile_rect.x = i * (700 / game->field_size_x) + 50;
|
|
for (int j = 0; j < game->field_size_y; j++) {
|
|
tile_rect.y = j * (700 / game->field_size_y) + 150;
|
|
|
|
// get texture index from value
|
|
for (int k = 0; k < 13; k++) {
|
|
if (!(game->field[j][i] >> k)) {
|
|
SDL_RenderCopy(window_renderer, tile_textures[k], NULL, &tile_rect);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// score - I am too lazy to optimize this further
|
|
char label_text[24] = "Score: 0x";
|
|
char value[16];
|
|
SDL_itoa(game->score, value, 16);
|
|
strncat(label_text, value, strlen(value));
|
|
SDL_Surface *score_label = TTF_RenderText_Blended(Sans, label_text, Black);
|
|
SDL_Texture *score_label_texture = SDL_CreateTextureFromSurface(window_renderer, score_label);
|
|
SDL_Rect score_label_rect;
|
|
SDL_QueryTexture(score_label_texture, NULL, NULL, &score_label_rect.w, &score_label_rect.h);
|
|
score_label_rect.x = (SCREEN_WIDTH - score_label_rect.w) / 2;
|
|
score_label_rect.y = 25;
|
|
SDL_RenderCopy(window_renderer, score_label_texture, NULL, &score_label_rect);
|
|
SDL_FreeSurface(score_label);
|
|
SDL_DestroyTexture(score_label_texture);
|
|
|
|
if (game->game_over) {
|
|
// render game over screen
|
|
SDL_RenderCopy(window_renderer, game_over_texture, NULL, NULL);
|
|
}
|
|
else if (game->won) {
|
|
SDL_RenderCopy(window_renderer, you_won_texture, NULL, NULL);
|
|
}
|
|
|
|
SDL_RenderPresent(window_renderer);
|
|
needs_redraw = false;
|
|
}
|
|
}
|
|
} |