ssd13x6_draw.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /**
  2. * Copyright (c) 2017-2018 Tara Keeling
  3. *
  4. * This software is released under the MIT License.
  5. * https://opensource.org/licenses/MIT
  6. */
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdint.h>
  10. #include <stdbool.h>
  11. #include <stdlib.h>
  12. #include <math.h>
  13. #include <esp_attr.h>
  14. #include "ssd13x6.h"
  15. #include "ssd13x6_draw.h"
  16. #undef NullCheck
  17. #define NullCheck(X,Y)
  18. __attribute__( ( always_inline ) ) static inline bool IsPixelVisible( struct SSD13x6_Device* DeviceHandle, int x, int y ) {
  19. bool Result = (
  20. ( x >= 0 ) &&
  21. ( x < DeviceHandle->Width ) &&
  22. ( y >= 0 ) &&
  23. ( y < DeviceHandle->Height )
  24. ) ? true : false;
  25. #if CONFIG_SSD13x6_CLIPDEBUG > 0
  26. if ( Result == false ) {
  27. ClipDebug( x, y );
  28. }
  29. #endif
  30. return Result;
  31. }
  32. __attribute__( ( always_inline ) ) static inline void SwapInt( int* a, int* b ) {
  33. int Temp = *b;
  34. *b = *a;
  35. *a = Temp;
  36. }
  37. inline void IRAM_ATTR SSD13x6_DrawPixelFast( struct SSD13x6_Device* DeviceHandle, int X, int Y, int Color ) {
  38. uint32_t YBit = ( Y & 0x07 );
  39. uint8_t* FBOffset = NULL;
  40. /*
  41. * We only need to modify the Y coordinate since the pitch
  42. * of the screen is the same as the width.
  43. * Dividing Y by 8 gives us which row the pixel is in but not
  44. * the bit position.
  45. */
  46. Y>>= 3;
  47. FBOffset = DeviceHandle->Framebuffer + ( ( Y * DeviceHandle->Width ) + X );
  48. if ( Color == SSD_COLOR_XOR ) {
  49. *FBOffset ^= BIT( YBit );
  50. } else {
  51. *FBOffset = ( Color == SSD_COLOR_WHITE ) ? *FBOffset | BIT( YBit ) : *FBOffset & ~BIT( YBit );
  52. }
  53. }
  54. void IRAM_ATTR SSD13x6_DrawPixel( struct SSD13x6_Device* DeviceHandle, int x, int y, int Color ) {
  55. NullCheck( DeviceHandle, return );
  56. if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
  57. SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color );
  58. }
  59. }
  60. void IRAM_ATTR SSD13x6_DrawHLine( struct SSD13x6_Device* DeviceHandle, int x, int y, int Width, int Color ) {
  61. int XEnd = x + Width;
  62. NullCheck( DeviceHandle, return );
  63. NullCheck( DeviceHandle->Framebuffer, return );
  64. for ( ; x < XEnd; x++ ) {
  65. if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
  66. SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color );
  67. } else {
  68. break;
  69. }
  70. }
  71. }
  72. void IRAM_ATTR SSD13x6_DrawVLine( struct SSD13x6_Device* DeviceHandle, int x, int y, int Height, int Color ) {
  73. int YEnd = y + Height;
  74. NullCheck( DeviceHandle, return );
  75. NullCheck( DeviceHandle->Framebuffer, return );
  76. for ( ; y < YEnd; y++ ) {
  77. if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
  78. SSD13x6_DrawPixel( DeviceHandle, x, y, Color );
  79. } else {
  80. break;
  81. }
  82. }
  83. }
  84. static inline void IRAM_ATTR DrawWideLine( struct SSD13x6_Device* DeviceHandle, int x0, int y0, int x1, int y1, int Color ) {
  85. int dx = ( x1 - x0 );
  86. int dy = ( y1 - y0 );
  87. int Error = 0;
  88. int Incr = 1;
  89. int x = x0;
  90. int y = y0;
  91. if ( dy < 0 ) {
  92. Incr = -1;
  93. dy = -dy;
  94. }
  95. Error = ( dy * 2 ) - dx;
  96. for ( ; x < x1; x++ ) {
  97. if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
  98. SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color );
  99. }
  100. if ( Error > 0 ) {
  101. Error-= ( dx * 2 );
  102. y+= Incr;
  103. }
  104. Error+= ( dy * 2 );
  105. }
  106. }
  107. static inline void IRAM_ATTR DrawTallLine( struct SSD13x6_Device* DeviceHandle, int x0, int y0, int x1, int y1, int Color ) {
  108. int dx = ( x1 - x0 );
  109. int dy = ( y1 - y0 );
  110. int Error = 0;
  111. int Incr = 1;
  112. int x = x0;
  113. int y = y0;
  114. if ( dx < 0 ) {
  115. Incr = -1;
  116. dx = -dx;
  117. }
  118. Error = ( dx * 2 ) - dy;
  119. for ( ; y < y1; y++ ) {
  120. if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
  121. SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color );
  122. }
  123. if ( Error > 0 ) {
  124. Error-= ( dy * 2 );
  125. x+= Incr;
  126. }
  127. Error+= ( dx * 2 );
  128. }
  129. }
  130. void IRAM_ATTR SSD13x6_DrawLine( struct SSD13x6_Device* DeviceHandle, int x0, int y0, int x1, int y1, int Color ) {
  131. NullCheck( DeviceHandle, return );
  132. NullCheck( DeviceHandle->Framebuffer, return );
  133. if ( x0 == x1 ) {
  134. SSD13x6_DrawVLine( DeviceHandle, x0, y0, ( y1 - y0 ), Color );
  135. } else if ( y0 == y1 ) {
  136. SSD13x6_DrawHLine( DeviceHandle, x0, y0, ( x1 - x0 ), Color );
  137. } else {
  138. if ( abs( x1 - x0 ) > abs( y1 - y0 ) ) {
  139. /* Wide ( run > rise ) */
  140. if ( x0 > x1 ) {
  141. SwapInt( &x0, &x1 );
  142. SwapInt( &y0, &y1 );
  143. }
  144. DrawWideLine( DeviceHandle, x0, y0, x1, y1, Color );
  145. } else {
  146. /* Tall ( rise > run ) */
  147. if ( y0 > y1 ) {
  148. SwapInt( &y0, &y1 );
  149. SwapInt( &x0, &x1 );
  150. }
  151. DrawTallLine( DeviceHandle, x0, y0, x1, y1, Color );
  152. }
  153. }
  154. }
  155. void IRAM_ATTR SSD13x6_DrawBox( struct SSD13x6_Device* DeviceHandle, int x1, int y1, int x2, int y2, int Color, bool Fill ) {
  156. int Width = ( x2 - x1 );
  157. int Height = ( y2 - y1 );
  158. NullCheck( DeviceHandle, return );
  159. NullCheck( DeviceHandle->Framebuffer, return );
  160. if ( Fill == false ) {
  161. /* Top side */
  162. SSD13x6_DrawHLine( DeviceHandle, x1, y1, Width, Color );
  163. /* Bottom side */
  164. SSD13x6_DrawHLine( DeviceHandle, x1, y1 + Height, Width, Color );
  165. /* Left side */
  166. SSD13x6_DrawVLine( DeviceHandle, x1, y1, Height, Color );
  167. /* Right side */
  168. SSD13x6_DrawVLine( DeviceHandle, x1 + Width, y1, Height, Color );
  169. } else {
  170. /* Fill the box by drawing horizontal lines */
  171. for ( ; y1 <= y2; y1++ ) {
  172. SSD13x6_DrawHLine( DeviceHandle, x1, y1, Width, Color );
  173. }
  174. }
  175. }
  176. void SSD13x6_Clear( struct SSD13x6_Device* DeviceHandle, int Color ) {
  177. NullCheck( DeviceHandle, return );
  178. NullCheck( DeviceHandle->Framebuffer, return );
  179. memset( DeviceHandle->Framebuffer, Color, DeviceHandle->FramebufferSize );
  180. }
  181. void SSD13x6_ClearWindow( struct SSD13x6_Device* DeviceHandle, int x1, int y1, int x2, int y2, int Color ) {
  182. NullCheck( DeviceHandle, return );
  183. NullCheck( DeviceHandle->Framebuffer, return );
  184. /*
  185. int xr = ((x1 - 1) / 8) + 1 ) * 8;
  186. int xl = (x2 / 8) * 8;
  187. for (int y = y1; y <= y2; y++) {
  188. for (int x = x1; x < xr; x++) SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color);
  189. if (xl > xr) memset( DeviceHandle->Framebuffer + (y / 8) * DeviceHandle->Width + xr, 0, xl - xr );
  190. for (int x = xl; x <= x2; x++) SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color);
  191. }
  192. return;
  193. */
  194. // cheap optimization on boundaries
  195. if (x1 == 0 && x2 == DeviceHandle->Width - 1 && y1 % 8 == 0 && (y2 + 1) % 8 == 0) {
  196. memset( DeviceHandle->Framebuffer + (y1 / 8) * DeviceHandle->Width, 0, (y2 - y1 + 1) / 8 * DeviceHandle->Width );
  197. } else {
  198. for (int y = y1; y <= y2; y++) {
  199. for (int x = x1; x <= x2; x++) {
  200. SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color);
  201. }
  202. }
  203. }
  204. }