main.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <SDL.h>
  4. #define STB_IMAGE_IMPLEMENTATION
  5. #include "stb_image.h"
  6. // TODO: ascending timer
  7. const size_t SCREEN_WIDTH = 800;
  8. const size_t SCREEN_HEIGHT = 600;
  9. const size_t FPS = 60;
  10. const float DELTA_TIME = 1.0f / (float) FPS;
  11. const size_t SPRITE_DIGIT_WIDTH = 300 / 2;
  12. const size_t SPRITE_DIGIT_HEIGHT = 380 / 2;
  13. const size_t DIGIT_WIDTH = 300 / 2;
  14. const size_t DIGIT_HEIGHT = 380 / 2;
  15. const size_t DIGITS_COUNT = 11;
  16. const size_t WIGGLE_COUNT = 3;
  17. const float WIGGLE_DURATION = 0.40 / (float) WIGGLE_COUNT;
  18. const size_t COLON_INDEX = 10;
  19. const SDL_Color MAIN_COLOR = {220, 220, 220, 255};
  20. const SDL_Color PAUSE_COLOR = {220, 120, 120, 255};
  21. const SDL_Color BACKGROUND_COLOR = {24, 24, 24, 255};
  22. const float SCALE_FACTOR = 0.15f;
  23. void sec(int code)
  24. {
  25. if (code < 0) {
  26. fprintf(stderr, "SDL pooped itself: %s\n", SDL_GetError());
  27. abort();
  28. }
  29. }
  30. template <typename T>
  31. T *sec(T *ptr)
  32. {
  33. if (ptr == nullptr) {
  34. fprintf(stderr, "SDL pooped itself: %s\n", SDL_GetError());
  35. abort();
  36. }
  37. return ptr;
  38. }
  39. SDL_Surface *load_png_file_as_surface(const char *image_filename)
  40. {
  41. int width, height;
  42. uint32_t *image_pixels = (uint32_t *) stbi_load(image_filename, &width, &height, NULL, 4);
  43. if (image_pixels == NULL) {
  44. fprintf(stderr, "[ERROR] Could not load `%s` as PNG\n", image_filename);
  45. abort();
  46. }
  47. SDL_Surface* image_surface =
  48. sec(SDL_CreateRGBSurfaceFrom(
  49. image_pixels,
  50. (int) width,
  51. (int) height,
  52. 32,
  53. (int) width * 4,
  54. 0x000000FF,
  55. 0x0000FF00,
  56. 0x00FF0000,
  57. 0xFF000000));
  58. return image_surface;
  59. }
  60. SDL_Texture *load_png_file_as_texture(SDL_Renderer *renderer,
  61. const char *image_filename)
  62. {
  63. SDL_Surface *image_surface = load_png_file_as_surface(image_filename);
  64. return sec(SDL_CreateTextureFromSurface(renderer, image_surface));
  65. }
  66. void render_digit_at(SDL_Renderer *renderer, SDL_Texture *digits, size_t digit_index,
  67. size_t wiggle_index, int *pen_x, int *pen_y, float scale)
  68. {
  69. const int effective_digit_width = (int) floorf((float) DIGIT_WIDTH * scale);
  70. const int effective_digit_height = (int) floorf((float) DIGIT_HEIGHT * scale);
  71. const SDL_Rect src_rect = {
  72. (int) (digit_index * SPRITE_DIGIT_WIDTH),
  73. (int) (wiggle_index * SPRITE_DIGIT_HEIGHT),
  74. SPRITE_DIGIT_WIDTH,
  75. SPRITE_DIGIT_HEIGHT
  76. };
  77. const SDL_Rect dst_rect = {
  78. *pen_x,
  79. *pen_y,
  80. effective_digit_width,
  81. effective_digit_height
  82. };
  83. SDL_RenderCopy(renderer, digits, &src_rect, &dst_rect);
  84. *pen_x += effective_digit_width;
  85. }
  86. void initial_pen(SDL_Window *window, int *pen_x, int *pen_y, float scale)
  87. {
  88. int w, h;
  89. SDL_GetWindowSize(window, &w, &h);
  90. const int effective_digit_width = (int) floorf((float) DIGIT_WIDTH * scale);
  91. const int effective_digit_height = (int) floorf((float) DIGIT_HEIGHT * scale);
  92. *pen_x = w / 2 - effective_digit_width * 8 / 2;
  93. *pen_y = h / 2 - effective_digit_height / 2;
  94. }
  95. int main(int argc, char **argv)
  96. {
  97. if (argc < 2) {
  98. fprintf(stderr, "./sowon <seconds>\n");
  99. exit(1);
  100. }
  101. float time = strtof(argv[1], NULL);
  102. sec(SDL_Init(SDL_INIT_VIDEO));
  103. SDL_Window *window =
  104. sec(SDL_CreateWindow(
  105. "sowon",
  106. 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
  107. SDL_WINDOW_RESIZABLE));
  108. SDL_Renderer *renderer =
  109. sec(SDL_CreateRenderer(
  110. window, -1,
  111. SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED));
  112. sec(SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"));
  113. SDL_Texture *digits = load_png_file_as_texture(renderer, "./digits.png");
  114. sec(SDL_SetTextureColorMod(digits, MAIN_COLOR.r, MAIN_COLOR.g, MAIN_COLOR.b));
  115. bool quit = false;
  116. size_t wiggle_index = 0;
  117. size_t digit_index = 0;
  118. float wiggle_cooldown = WIGGLE_DURATION;
  119. float digit_cooldown = 1.0f;
  120. bool paused = false;
  121. float scale = 1.0f;
  122. while (!quit) {
  123. // INPUT BEGIN //////////////////////////////
  124. SDL_Event event = {};
  125. while (SDL_PollEvent(&event)) {
  126. switch (event.type) {
  127. case SDL_QUIT: {
  128. quit = true;
  129. } break;
  130. case SDL_KEYDOWN: {
  131. switch (event.key.keysym.sym) {
  132. case SDLK_SPACE: {
  133. paused = !paused;
  134. if (paused) {
  135. sec(SDL_SetTextureColorMod(digits, PAUSE_COLOR.r, PAUSE_COLOR.g, PAUSE_COLOR.b));
  136. } else {
  137. sec(SDL_SetTextureColorMod(digits, MAIN_COLOR.r, MAIN_COLOR.g, MAIN_COLOR.b));
  138. }
  139. } break;
  140. case SDLK_EQUALS: {
  141. scale += SCALE_FACTOR * scale;
  142. } break;
  143. case SDLK_MINUS: {
  144. scale -= SCALE_FACTOR * scale;
  145. } break;
  146. case SDLK_0: {
  147. scale = 1.0f;
  148. } break;
  149. }
  150. } break;
  151. default: {}
  152. }
  153. }
  154. // INPUT END //////////////////////////////
  155. // RENDER BEGIN //////////////////////////////
  156. SDL_SetRenderDrawColor(renderer, BACKGROUND_COLOR.r, BACKGROUND_COLOR.g, BACKGROUND_COLOR.b, 255);
  157. SDL_RenderClear(renderer);
  158. {
  159. int pen_x, pen_y;
  160. initial_pen(window, &pen_x, &pen_y, scale);
  161. const size_t t = (size_t) floorf(fmaxf(time, 0.0f));
  162. const size_t hours = t / 60 / 60;
  163. render_digit_at(renderer, digits, hours / 10, wiggle_index, &pen_x, &pen_y, scale);
  164. render_digit_at(renderer, digits, hours % 10, wiggle_index, &pen_x, &pen_y, scale);
  165. render_digit_at(renderer, digits, COLON_INDEX, wiggle_index, &pen_x, &pen_y, scale);
  166. const size_t minutes = t / 60 % 60;
  167. render_digit_at(renderer, digits, minutes / 10, wiggle_index, &pen_x, &pen_y, scale);
  168. render_digit_at(renderer, digits, minutes % 10, wiggle_index, &pen_x, &pen_y, scale);
  169. render_digit_at(renderer, digits, COLON_INDEX, wiggle_index, &pen_x, &pen_y, scale);
  170. const size_t seconds = t % 60;
  171. render_digit_at(renderer, digits, seconds / 10, wiggle_index, &pen_x, &pen_y, scale);
  172. render_digit_at(renderer, digits, seconds % 10, wiggle_index, &pen_x, &pen_y, scale);
  173. }
  174. SDL_RenderPresent(renderer);
  175. // RENDER END //////////////////////////////
  176. // UPDATE BEGIN //////////////////////////////
  177. if (wiggle_cooldown <= 0.0f) {
  178. wiggle_index = (wiggle_index + 1) % WIGGLE_COUNT;
  179. wiggle_cooldown = WIGGLE_DURATION;
  180. }
  181. wiggle_cooldown -= DELTA_TIME;
  182. if (time > 1e-6) {
  183. if (!paused) {
  184. time -= DELTA_TIME;
  185. }
  186. } else {
  187. time = 0.0f;
  188. }
  189. // UPDATE END //////////////////////////////
  190. SDL_Delay((int) floorf(DELTA_TIME * 1000.0f));
  191. }
  192. SDL_Quit();
  193. return 0;
  194. }