CXfb.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #include <cstdlib>
  2. #include <cstring>
  3. #include "CXfb.h"
  4. #include "utility/misc.h"
  5. #include "utility/minmax.h"
  6. #define GRAPHICS Nspire::CXfb
  7. #define LCD_CONTROLLER 0xC0000000
  8. volatile uint32_t *lcd_base = (uint32_t *) (LCD_CONTROLLER + 0x10);
  9. volatile uint32_t *lcd_ris = (uint32_t *) (LCD_CONTROLLER + 0x20);
  10. volatile uint32_t *lcd_icr = (uint32_t *) (LCD_CONTROLLER + 0x28);
  11. volatile uint32_t *lcd_control = (uint32_t *) (LCD_CONTROLLER + 0x18);
  12. uint32_t lcd_control_bkp;
  13. volatile uint32_t *lcd_imsc = (uint32_t *) (LCD_CONTROLLER + 0x1C);
  14. uint32_t lcd_imsc_bkp;
  15. #define BUFFER_SIZE 320 * 240 * 2
  16. uint16_t *buffer_screen = NULL, *buffer_render = NULL, *buffer_ready = NULL, *buffer_os;
  17. bool buffer_swap_ready;
  18. /*
  19. * Buffer management
  20. */
  21. #define min(a, b) (((a) < (b)) ? (a) : (b))
  22. #define max(a, b) (((a) > (b)) ? (a) : (b))
  23. void GRAPHICS::buffer_allocate()
  24. {
  25. buffer_screen = (uint16_t *) malloc(BUFFER_SIZE);
  26. buffer_render = (uint16_t *) malloc(BUFFER_SIZE);
  27. buffer_ready = (uint16_t *) malloc(BUFFER_SIZE);
  28. if (buffer_screen == NULL || buffer_render == NULL || buffer_ready == NULL)
  29. {
  30. free(buffer_screen);
  31. free(buffer_render);
  32. free(buffer_ready);
  33. exit(0);
  34. }
  35. memset(buffer_screen, 0, BUFFER_SIZE);
  36. buffer_os = (uint16_t *) *lcd_base;
  37. *lcd_base = (uint32_t) buffer_screen;
  38. buffer_swap_ready = false;
  39. // Set up the controller in order to use vsync signals
  40. lcd_control_bkp = *lcd_control;
  41. *lcd_control &= ~(0b11 << 12);
  42. *lcd_control |= 0b11 << 12;
  43. lcd_imsc_bkp = *lcd_imsc;
  44. *lcd_imsc = 1 << 3;
  45. }
  46. void GRAPHICS::buffer_free()
  47. {
  48. free(buffer_screen);
  49. free(buffer_render);
  50. free(buffer_ready);
  51. *lcd_base = (uint32_t) buffer_os;
  52. *lcd_control = lcd_control_bkp;
  53. *lcd_imsc = lcd_imsc_bkp;
  54. }
  55. void GRAPHICS::buffer_swap_screen()
  56. {
  57. if (buffer_swap_ready)
  58. {
  59. uint16_t *buffer_screen_tmp = buffer_screen;
  60. buffer_screen = buffer_ready;
  61. buffer_ready = buffer_screen_tmp;
  62. *lcd_base = (uint32_t) buffer_screen;
  63. buffer_swap_ready = false;
  64. }
  65. }
  66. void GRAPHICS::buffer_swap_render()
  67. {
  68. uint16_t *buffer_ready_tmp = buffer_ready;
  69. buffer_ready = buffer_render;
  70. buffer_render = buffer_ready_tmp;
  71. buffer_swap_ready = true;
  72. }
  73. void GRAPHICS::buffer_fill(uint16_t color)
  74. {
  75. uint32_t *buffer_render_32 = (uint32_t *) buffer_render;
  76. uint32_t color_32 = color << 16 | color; // To avoid stupid overflows
  77. for (uint32_t i = 0; i < (BUFFER_SIZE / 4); i++)
  78. buffer_render_32[i] = color_32;
  79. }
  80. /*
  81. * Misc LCD functions
  82. */
  83. void GRAPHICS::vsync_isr()
  84. {
  85. buffer_swap_screen();
  86. *lcd_icr = 1 << 3;
  87. }
  88. /*
  89. * Drawing
  90. */
  91. void GRAPHICS::draw_pixel(int x, int y, uint16_t color)
  92. {
  93. buffer_render[x + (y * 320)] = color;
  94. }
  95. void GRAPHICS::draw_pixel_tint(int x, int y, uint16_t color, uint16_t tint)
  96. {
  97. int r = ((color >> 11) * (tint >> 11)) >> 5;
  98. int g = (((color >> 5) & 0b111111) * ((tint >> 5) & 0b111111)) >> 6;
  99. int b = ((color & 0b11111) * (tint & 0b11111)) >> 5;
  100. buffer_render[x + (y * 320)] = (r << 11) | (g << 5) | b;
  101. }
  102. void GRAPHICS::draw_sprite_sheet(const uint16_t *sheet, int x, int y,
  103. const WalrusRPG::Utils::Rect &window)
  104. {
  105. uint16_t color;
  106. int w = min(window.width + x, 320);
  107. int h = min(window.height + y, 240);
  108. for (int j = max(y, 0), l = window.y - min(y, 0); j < h; j++, l++)
  109. {
  110. for (int i = max(x, 0), k = window.x - min(x, 0); i < w; i++, k++)
  111. {
  112. color = sprite_pixel_get(sheet, k, l);
  113. if (color != sheet[2])
  114. draw_pixel(i, j, color);
  115. }
  116. }
  117. }
  118. void GRAPHICS::draw_sprite_sheet_tint(const uint16_t *sheet, int x, int y,
  119. const WalrusRPG::Utils::Rect &window, uint16_t tint)
  120. {
  121. uint16_t color;
  122. int w = min(window.width + x, 320);
  123. int h = min(window.height + y, 240);
  124. for (int j = max(y, 0), l = window.y - min(y, 0); j < h; j++, l++)
  125. {
  126. for (int i = max(x, 0), k = window.x - min(x, 0); i < w; i++, k++)
  127. {
  128. color = sprite_pixel_get(sheet, k, l);
  129. if (color != sheet[2])
  130. draw_pixel_tint(i, j, color, tint);
  131. }
  132. }
  133. }
  134. /*
  135. * Sprite manipulation
  136. */
  137. uint16_t GRAPHICS::sprite_pixel_get(const uint16_t *sprite, uint32_t x, uint32_t y)
  138. {
  139. if (x < sprite[0] && y < sprite[1])
  140. return sprite[x + (y * sprite[0]) + 3];
  141. else
  142. return sprite[2];
  143. }