main.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdbool.h>
  4. #include <SDL.h>
  5. #include "./la.h"
  6. #define STB_IMAGE_IMPLEMENTATION
  7. #include "./stb_image.h"
  8. #define FONT_WIDTH 128
  9. #define FONT_HEIGHT 64
  10. #define FONT_COLS 18
  11. #define FONT_ROWS 7
  12. #define FONT_CHAR_WIDTH (FONT_WIDTH / FONT_COLS)
  13. #define FONT_CHAR_HEIGHT (FONT_HEIGHT / FONT_ROWS)
  14. #define FONT_SCALE 5
  15. void scc(int code)
  16. {
  17. if (code < 0) {
  18. fprintf(stderr, "SDL ERROR: %s\n", SDL_GetError());
  19. exit(1);
  20. }
  21. }
  22. void *scp(void *ptr)
  23. {
  24. if (ptr == NULL) {
  25. fprintf(stderr, "SDL ERROR: %s\n", SDL_GetError());
  26. exit(1);
  27. }
  28. return ptr;
  29. }
  30. SDL_Surface *surface_from_file(const char *file_path)
  31. {
  32. int width, height, n;
  33. unsigned char *pixels = stbi_load(file_path, &width, &height, &n, STBI_rgb_alpha);
  34. if (pixels == NULL) {
  35. fprintf(stderr, "ERROR: could not load file %s: %s\n",
  36. file_path, stbi_failure_reason());
  37. exit(1);
  38. }
  39. #if SDL_BYTEORDER == SDL_BIG_ENDIAN
  40. const Uint32 rmask = 0xff000000;
  41. const Uint32 gmask = 0x00ff0000;
  42. const Uint32 bmask = 0x0000ff00;
  43. const Uint32 amask = 0x000000ff;
  44. #else // little endian, like x86
  45. const Uint32 rmask = 0x000000ff;
  46. const Uint32 gmask = 0x0000ff00;
  47. const Uint32 bmask = 0x00ff0000;
  48. const Uint32 amask = 0xff000000;
  49. #endif
  50. const int depth = 32;
  51. const int pitch = 4*width;
  52. return scp(SDL_CreateRGBSurfaceFrom(
  53. (void*)pixels, width, height, depth, pitch,
  54. rmask, gmask, bmask, amask));
  55. }
  56. #define ASCII_DISPLAY_LOW 32
  57. #define ASCII_DISPLAY_HIGH 126
  58. typedef struct {
  59. SDL_Texture *spritesheet;
  60. SDL_Rect glyph_table[ASCII_DISPLAY_HIGH - ASCII_DISPLAY_LOW + 1];
  61. } Font;
  62. Font font_load_from_file(SDL_Renderer *renderer, const char *file_path)
  63. {
  64. Font font = {0};
  65. SDL_Surface *font_surface = surface_from_file(file_path);
  66. font.spritesheet = scp(SDL_CreateTextureFromSurface(renderer, font_surface));
  67. SDL_FreeSurface(font_surface);
  68. for (size_t ascii = ASCII_DISPLAY_LOW; ascii <= ASCII_DISPLAY_HIGH; ++ascii) {
  69. const size_t index = ascii - ASCII_DISPLAY_LOW;
  70. const size_t col = index % FONT_COLS;
  71. const size_t row = index / FONT_COLS;
  72. font.glyph_table[index] = (SDL_Rect) {
  73. .x = col * FONT_CHAR_WIDTH,
  74. .y = row * FONT_CHAR_HEIGHT,
  75. .w = FONT_CHAR_WIDTH,
  76. .h = FONT_CHAR_HEIGHT,
  77. };
  78. }
  79. return font;
  80. }
  81. void render_char(SDL_Renderer *renderer, Font *font, char c, Vec2f pos, float scale)
  82. {
  83. const SDL_Rect dst = {
  84. .x = (int) floorf(pos.x),
  85. .y = (int) floorf(pos.y),
  86. .w = (int) floorf(FONT_CHAR_WIDTH * scale),
  87. .h = (int) floorf(FONT_CHAR_HEIGHT * scale),
  88. };
  89. assert(c >= ASCII_DISPLAY_LOW);
  90. assert(c <= ASCII_DISPLAY_HIGH);
  91. const size_t index = c - ASCII_DISPLAY_LOW;
  92. scc(SDL_RenderCopy(renderer, font->spritesheet, &font->glyph_table[index], &dst));
  93. }
  94. void render_text_sized(SDL_Renderer *renderer, Font *font, const char *text, size_t text_size, Vec2f pos, Uint32 color, float scale)
  95. {
  96. scc(SDL_SetTextureColorMod(
  97. font->spritesheet,
  98. (color >> (8 * 0)) & 0xff,
  99. (color >> (8 * 1)) & 0xff,
  100. (color >> (8 * 2)) & 0xff));
  101. scc(SDL_SetTextureAlphaMod(font->spritesheet, (color >> (8 * 3)) & 0xff));
  102. Vec2f pen = pos;
  103. for (size_t i = 0; i < text_size; ++i) {
  104. render_char(renderer, font, text[i], pen, scale);
  105. pen.x += FONT_CHAR_WIDTH * scale;
  106. }
  107. }
  108. void render_text(SDL_Renderer *renderer, Font *font, const char *text, Vec2f pos, Uint32 color, float scale)
  109. {
  110. render_text_sized(renderer, font, text, strlen(text), pos, color, scale);
  111. }
  112. #define BUFFER_CAPACITY 1024
  113. char buffer[BUFFER_CAPACITY];
  114. size_t buffer_cursor = 0;
  115. size_t buffer_size = 0;
  116. #define UNHEX(color) \
  117. ((color) >> (8 * 0)) & 0xFF, \
  118. ((color) >> (8 * 1)) & 0xFF, \
  119. ((color) >> (8 * 2)) & 0xFF, \
  120. ((color) >> (8 * 3)) & 0xFF
  121. void render_cursor(SDL_Renderer *renderer, Uint32 color)
  122. {
  123. const SDL_Rect rect = {
  124. .x = (int) floorf(buffer_cursor * FONT_CHAR_WIDTH * FONT_SCALE),
  125. .y = 0,
  126. .w = FONT_CHAR_WIDTH * FONT_SCALE,
  127. .h = FONT_CHAR_HEIGHT * FONT_SCALE,
  128. };
  129. scc(SDL_SetRenderDrawColor(renderer, UNHEX(color)));
  130. scc(SDL_RenderFillRect(renderer, &rect));
  131. }
  132. int main(void)
  133. {
  134. scc(SDL_Init(SDL_INIT_VIDEO));
  135. SDL_Window *window =
  136. scp(SDL_CreateWindow("Text Editor", 0, 0, 800, 600,
  137. SDL_WINDOW_RESIZABLE));
  138. SDL_Renderer *renderer =
  139. scp(SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED));
  140. Font font = font_load_from_file(renderer, "./charmap-oldschool_white.png");
  141. bool quit = false;
  142. while (!quit) {
  143. SDL_Event event = {0};
  144. while (SDL_PollEvent(&event)) {
  145. switch (event.type) {
  146. case SDL_QUIT: {
  147. quit = true;
  148. }
  149. break;
  150. case SDL_KEYDOWN: {
  151. switch (event.key.keysym.sym) {
  152. case SDLK_BACKSPACE: {
  153. if (buffer_size > 0) {
  154. buffer_size -= 1;
  155. buffer_cursor = buffer_size;
  156. }
  157. }
  158. break;
  159. }
  160. }
  161. break;
  162. case SDL_TEXTINPUT: {
  163. size_t text_size = strlen(event.text.text);
  164. const size_t free_space = BUFFER_CAPACITY - buffer_size;
  165. if (text_size > free_space) {
  166. text_size = free_space;
  167. }
  168. memcpy(buffer + buffer_size, event.text.text, text_size);
  169. buffer_size += text_size;
  170. buffer_cursor = buffer_size;
  171. }
  172. break;
  173. }
  174. }
  175. scc(SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0));
  176. scc(SDL_RenderClear(renderer));
  177. render_text_sized(renderer, &font, buffer, buffer_size, vec2f(0.0, 0.0), 0xFFFFFFFF, FONT_SCALE);
  178. render_cursor(renderer, 0xFFFFFFFF);
  179. SDL_RenderPresent(renderer);
  180. }
  181. SDL_Quit();
  182. return 0;
  183. }