NESe (pronounced "Nessie") is a NES emulator based on the e6502 emulator, also written in C with a focus on speed and portability for use on embedded platforms, especially ARM.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
5.1KB

  1. #include "sdl_overlay.h"
  2. #include "charbits.h"
  3. typedef struct {
  4. const uint8_t* bits;
  5. uint8_t shift;
  6. } bit_buffer;
  7. void make_bit_buffer(bit_buffer* buf, const uint8_t* bits) {
  8. buf->bits = bits;
  9. buf->shift = 0;
  10. }
  11. uint8_t get_bits(bit_buffer* buf) {
  12. uint8_t val = ((buf->bits[0] >> buf->shift) & 3);
  13. if (buf->shift == 6) {
  14. buf->shift = 0;
  15. buf->bits++;
  16. } else {
  17. buf->shift += 2;
  18. }
  19. return val;
  20. }
  21. static const SDL_Color pal[2] = {
  22. {0, 0, 0, 255}, {255, 255, 255, 255}
  23. };
  24. static SDL_Surface* create_char_surface(const uint8_t* bits) {
  25. int w = *bits++;
  26. bit_buffer buf = {0};
  27. make_bit_buffer(&buf, bits);
  28. SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormat(
  29. 0, w, char_h, 8, SDL_PIXELFORMAT_INDEX8
  30. );
  31. SDL_SetPaletteColors(surface->format->palette, pal, 1U, 2U);
  32. SDL_SetColorKey(surface, SDL_TRUE, 0);
  33. uint8_t* line = surface->pixels;
  34. for (int y = char_h; y > 0; --y) {
  35. uint8_t* dst = line;
  36. for (int x = w; x > 0; --x) {
  37. *dst++ = get_bits(&buf);
  38. }
  39. for (int x = (char_w - w); x > 0; --x) get_bits(&buf);
  40. line += surface->pitch;
  41. }
  42. return surface;
  43. }
  44. static SDL_Texture* create_char_texture(SDL_Renderer* rend,
  45. const uint8_t* bits) {
  46. SDL_Surface* surface = create_char_surface(bits);
  47. SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
  48. SDL_Texture* texture = SDL_CreateTextureFromSurface(
  49. rend, surface
  50. );
  51. SDL_FreeSurface(surface);
  52. return texture;
  53. }
  54. int sdl_overlay_font_init(SDL_Renderer* rend,
  55. sdl_overlay_font* font) {
  56. font->chars = chars;
  57. font->charbits = charbits;
  58. font->char_count = char_count;
  59. font->textures = calloc(char_count, sizeof(SDL_Texture*));
  60. for (int i = 0; i < font->char_count; ++i) {
  61. font->textures[i] = create_char_texture(
  62. rend, &font->charbits[i * charbit_size]
  63. );
  64. }
  65. return 0;
  66. }
  67. void sdl_overlay_font_done(sdl_overlay_font* font) {
  68. for (int i = 0; i < font->char_count; ++i) {
  69. SDL_DestroyTexture(font->textures[i]);
  70. }
  71. }
  72. #define overlay_start_x (char_w / 2)
  73. #define overlay_start_y (char_h / 2)
  74. #define space_width ((char_w / 2) - 1)
  75. static inline int char_index(char c) {
  76. if (c >= 'a' && c <= 'z') c += ('A' - 'a');
  77. if (c > ' ' && c < 'a') return (c - ' ');
  78. if (c >= '{' && c <= '~') return (65 + c - '{');
  79. return 0;
  80. }
  81. void measure_string(sdl_overlay_font* font, const char* string,
  82. int* w, int* h) {
  83. *h = char_h;
  84. int max_w = 1;
  85. int cur_w = 1;
  86. for (const char* c = string; *c; ++c) {
  87. if (*c == '\n') {
  88. if (cur_w > max_w) max_w = cur_w;
  89. cur_w = 1;
  90. *h += char_h;
  91. } else if (*c == ' ') {
  92. cur_w += space_width;
  93. } else {
  94. int index = char_index(*c);
  95. int cw = font->charbits[index * charbit_size];
  96. cur_w += (cw - 1);
  97. }
  98. }
  99. if (cur_w > max_w) max_w = cur_w;
  100. *w = max_w;
  101. }
  102. void render_string(SDL_Renderer* rend, int ox, int oy,
  103. int vx, int vy, int sx, int sy,
  104. sdl_overlay_font* font, const char* string,
  105. uint32_t color) {
  106. int x = ox;
  107. int y = oy;
  108. for (const char* c = string; *c; ++c) {
  109. if (*c == '\n') {
  110. x = ox;
  111. y += (char_h + 1);
  112. } else if (*c == ' ') {
  113. x += space_width;
  114. } else {
  115. int index = char_index(*c);
  116. int cw = font->charbits[index * charbit_size];
  117. SDL_Texture* texture = font->textures[index];
  118. SDL_Rect rect = {
  119. .x = (x * sx) + vx,
  120. .y = (y * sy) + vy,
  121. .w = cw * sx,
  122. .h = char_h * sy,
  123. };
  124. SDL_SetTextureColorMod(
  125. texture,
  126. ((color >> 16) & 0xFFU),
  127. ((color >> 8) & 0xFFU),
  128. ((color >> 0) & 0xFFU)
  129. );
  130. SDL_SetTextureAlphaMod(texture,
  131. ((color >> 24) & 0xFFU));
  132. SDL_RenderCopy(rend, texture, NULL, &rect);
  133. x += (cw - 1);
  134. }
  135. }
  136. }
  137. int sdl_overlay_frame(Overlay* overlay, sdl_overlay_font* font,
  138. SDL_Renderer* rend, int vx, int vy,
  139. int sx, int sy) {
  140. int y = overlay_start_y;
  141. int x = overlay_start_x;
  142. overlay_message* last = NULL, *next = NULL;
  143. for ( overlay_message* message = overlay->messages;
  144. NULL != message;
  145. message = next) {
  146. next = message->next;
  147. render_string(rend, x, y, vx, vy, sx, sy,
  148. font, message->string, 0xFFFFFFFFU);
  149. y += (char_h + 1);
  150. if (message->expiry > 0 && --(message->expiry) == 0) {
  151. if (NULL == last) {
  152. overlay->messages = message->next;
  153. } else {
  154. last->next = message->next;
  155. }
  156. free(message->string);
  157. free(message);
  158. } else {
  159. last = message;
  160. }
  161. }
  162. return 0;
  163. }