#include "gui.h" #include #include #include #include const int SCREEN_WIDTH = 800; const int 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; if (game->field_size_x > 5 || game->field_size_y > 5) { int size = 700 / max(game->field_size_y, game->field_size_x); tile_rect.w = size; tile_rect.h = 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[i][j] >> 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: "; char value[16]; SDL_itoa(game->score, value, 10); 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; } } }