Graphics.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #include <cstdlib>
  2. #include <cstring>
  3. #include "Graphics.h"
  4. #include "utility/misc.h"
  5. #define GRAPHICS WalrusRPG::Graphics
  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::lcd_vsync()
  81. {
  82. *lcd_icr = 1 << 3;
  83. while (!(*lcd_ris & (1 << 3)))
  84. ;
  85. }
  86. void GRAPHICS::vsync_isr()
  87. {
  88. buffer_swap_screen();
  89. *lcd_icr = 1 << 3;
  90. }
  91. /*
  92. * Drawing
  93. */
  94. void GRAPHICS::draw_pixel(int x, int y, uint16_t color)
  95. {
  96. buffer_render[x + (y * 320)] = color;
  97. }
  98. void GRAPHICS::draw_sprite_sheet(const uint16_t *sheet, int x, int y,
  99. const WalrusRPG::Utils::Rect &window)
  100. {
  101. uint16_t color;
  102. int w = min(window.width + x, 320);
  103. int h = min(window.height + y, 240);
  104. for (int j = max(y, 0), l = window.y - min(y, 0); j < h; j++, l++)
  105. {
  106. for (int i = max(x, 0), k = window.x - min(x, 0); i < w; i++, k++)
  107. {
  108. color = sprite_pixel_get(sheet, k, l);
  109. if (color != sheet[2])
  110. draw_pixel(i, j, color);
  111. }
  112. }
  113. }
  114. /*
  115. * Sprite manipulation
  116. */
  117. uint16_t GRAPHICS::sprite_pixel_get(const uint16_t *sprite, uint32_t x, uint32_t y)
  118. {
  119. if (x < sprite[0] && y < sprite[1])
  120. return sprite[x + (y * sprite[0]) + 3];
  121. else
  122. return sprite[2];
  123. }