main.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <SDL.h>
  4. #define STB_IMAGE_IMPLEMENTATION
  5. #include "stb_image.h"
  6. const size_t SCREEN_WIDTH = 800;
  7. const size_t SCREEN_HEIGHT = 600;
  8. const size_t FPS = 60;
  9. const float DELTA_TIME = 1.0f / (float) FPS;
  10. const size_t SPRITE_DIGIT_WIDTH = 300 / 2;
  11. const size_t SPRITE_DIGIT_HEIGHT = 380 / 2;
  12. const size_t DIGIT_WIDTH = 300 / 2;
  13. const size_t DIGIT_HEIGHT = 380 / 2;
  14. const size_t DIGITS_COUNT = 11;
  15. const size_t WIGGLE_COUNT = 3;
  16. const float WIGGLE_DURATION = 0.40 / (float) WIGGLE_COUNT;
  17. const size_t COLON_INDEX = 10;
  18. const SDL_Color MAIN_COLOR = {220, 220, 220, 255};
  19. const SDL_Color PAUSE_COLOR = {220, 120, 120, 255};
  20. const SDL_Color BACKGROUND_COLOR = {24, 24, 24, 255};
  21. const float SCALE_FACTOR = 0.15f;
  22. void sec(int code)
  23. {
  24. if (code < 0) {
  25. fprintf(stderr, "SDL pooped itself: %s\n", SDL_GetError());
  26. abort();
  27. }
  28. }
  29. template <typename T>
  30. T *sec(T *ptr)
  31. {
  32. if (ptr == nullptr) {
  33. fprintf(stderr, "SDL pooped itself: %s\n", SDL_GetError());
  34. abort();
  35. }
  36. return ptr;
  37. }
  38. SDL_Surface *load_png_file_as_surface(const char *image_filename)
  39. {
  40. int width, height;
  41. uint32_t *image_pixels = (uint32_t *) stbi_load(image_filename, &width, &height, NULL, 4);
  42. if (image_pixels == NULL) {
  43. fprintf(stderr, "[ERROR] Could not load `%s` as PNG\n", image_filename);
  44. abort();
  45. }
  46. SDL_Surface* image_surface =
  47. sec(SDL_CreateRGBSurfaceFrom(
  48. image_pixels,
  49. (int) width,
  50. (int) height,
  51. 32,
  52. (int) width * 4,
  53. 0x000000FF,
  54. 0x0000FF00,
  55. 0x00FF0000,
  56. 0xFF000000));
  57. return image_surface;
  58. }
  59. SDL_Texture *load_png_file_as_texture(SDL_Renderer *renderer,
  60. const char *image_filename)
  61. {
  62. SDL_Surface *image_surface = load_png_file_as_surface(image_filename);
  63. return sec(SDL_CreateTextureFromSurface(renderer, image_surface));
  64. }
  65. void render_digit_at(SDL_Renderer *renderer, SDL_Texture *digits, size_t digit_index,
  66. size_t wiggle_index, int *pen_x, int *pen_y, float scale)
  67. {
  68. const int effective_digit_width = (int) floorf((float) DIGIT_WIDTH * scale);
  69. const int effective_digit_height = (int) floorf((float) DIGIT_HEIGHT * scale);
  70. const SDL_Rect src_rect = {
  71. (int) (digit_index * SPRITE_DIGIT_WIDTH),
  72. (int) (wiggle_index * SPRITE_DIGIT_HEIGHT),
  73. SPRITE_DIGIT_WIDTH,
  74. SPRITE_DIGIT_HEIGHT
  75. };
  76. const SDL_Rect dst_rect = {
  77. *pen_x,
  78. *pen_y,
  79. effective_digit_width,
  80. effective_digit_height
  81. };
  82. SDL_RenderCopy(renderer, digits, &src_rect, &dst_rect);
  83. *pen_x += effective_digit_width;
  84. }
  85. void initial_pen(SDL_Window *window, int *pen_x, int *pen_y, float scale)
  86. {
  87. int w, h;
  88. SDL_GetWindowSize(window, &w, &h);
  89. const int effective_digit_width = (int) floorf((float) DIGIT_WIDTH * scale);
  90. const int effective_digit_height = (int) floorf((float) DIGIT_HEIGHT * scale);
  91. *pen_x = w / 2 - effective_digit_width * 8 / 2;
  92. *pen_y = h / 2 - effective_digit_height / 2;
  93. }
  94. int main(int argc, char **argv)
  95. {
  96. bool ascending = true;
  97. float time = 0.0f;
  98. if (argc > 1) {
  99. ascending = false;
  100. time = strtof(argv[1], NULL);
  101. }
  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 (!paused) {
  183. if (ascending) {
  184. time += DELTA_TIME;
  185. } else {
  186. if (time > 1e-6) {
  187. time -= DELTA_TIME;
  188. } else {
  189. time = 0.0f;
  190. }
  191. }
  192. }
  193. // UPDATE END //////////////////////////////
  194. SDL_Delay((int) floorf(DELTA_TIME * 1000.0f));
  195. }
  196. SDL_Quit();
  197. return 0;
  198. }