CXfb.cpp 4.3 KB

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