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.

149 lines
4.0KB

  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. static inline int char_index(char c) {
  75. if (c >= 'a' && c <= 'z') c += ('A' - 'a');
  76. if (c > ' ' && c < 'a') return (c - ' ');
  77. if (c >= '{' && c <= '~') return (65 + c - '{');
  78. return 0;
  79. }
  80. static void render_string(SDL_Renderer* rend, int ox, int oy,
  81. int sx, int sy,
  82. sdl_overlay_font* font,
  83. const char* string) {
  84. for (const char* c = string; *c; ++c) {
  85. if (*c == ' ') {
  86. ox += ((char_w / 2) - 1);
  87. } else {
  88. int index = char_index(*c);
  89. int cw = font->charbits[index * charbit_size];
  90. SDL_Texture* texture = font->textures[index];
  91. SDL_Rect rect = {
  92. .x = ox * sx,
  93. .y = oy * sy,
  94. .w = cw * sx,
  95. .h = char_h * sy,
  96. };
  97. SDL_RenderCopy(rend, texture, NULL, &rect);
  98. ox += (cw - 1);
  99. }
  100. }
  101. }
  102. int sdl_overlay_frame(Overlay* overlay, sdl_overlay_font* font,
  103. SDL_Renderer* rend,
  104. int sx, int sy) {
  105. int y = overlay_start_y;
  106. overlay_message* last = NULL, *next = NULL;
  107. for ( overlay_message* message = overlay->messages;
  108. NULL != message;
  109. last = message, message = next) {
  110. next = message->next;
  111. render_string(rend, overlay_start_x, y, sx, sy,
  112. font, message->string);
  113. y += (char_h + 1);
  114. if (message->expiry > 0 && --(message->expiry) == 0) {
  115. if (NULL == last) {
  116. overlay->messages = message->next;
  117. } else {
  118. last->next = message->next;
  119. }
  120. free(message->string);
  121. free(message);
  122. }
  123. }
  124. return 0;
  125. }