ssd1306_draw.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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 "ssd1306.h"
  15. #include "ssd1306_draw.h"
  16. __attribute__( ( always_inline ) ) static inline bool IsPixelVisible( struct SSD1306_Device* DeviceHandle, int x, int y ) {
  17. bool Result = (
  18. ( x >= 0 ) &&
  19. ( x < DeviceHandle->Width ) &&
  20. ( y >= 0 ) &&
  21. ( y < DeviceHandle->Height )
  22. ) ? true : false;
  23. #if CONFIG_SSD1306_CLIPDEBUG > 0
  24. if ( Result == false ) {
  25. ClipDebug( x, y );
  26. }
  27. #endif
  28. return Result;
  29. }
  30. __attribute__( ( always_inline ) ) static inline void SwapInt( int* a, int* b ) {
  31. int Temp = *b;
  32. *b = *a;
  33. *a = Temp;
  34. }
  35. inline void IRAM_ATTR SSD1306_DrawPixelFast( struct SSD1306_Device* DeviceHandle, int X, int Y, int Color ) {
  36. uint32_t YBit = ( Y & 0x07 );
  37. uint8_t* FBOffset = NULL;
  38. /*
  39. * We only need to modify the Y coordinate since the pitch
  40. * of the screen is the same as the width.
  41. * Dividing Y by 8 gives us which row the pixel is in but not
  42. * the bit position.
  43. */
  44. Y>>= 3;
  45. FBOffset = DeviceHandle->Framebuffer + ( ( Y * DeviceHandle->Width ) + X );
  46. if ( Color == SSD_COLOR_XOR ) {
  47. *FBOffset ^= BIT( YBit );
  48. } else {
  49. *FBOffset = ( Color == SSD_COLOR_WHITE ) ? *FBOffset | BIT( YBit ) : *FBOffset & ~BIT( YBit );
  50. }
  51. }
  52. void IRAM_ATTR SSD1306_DrawPixel( struct SSD1306_Device* DeviceHandle, int x, int y, int Color ) {
  53. NullCheck( DeviceHandle, return );
  54. if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
  55. SSD1306_DrawPixelFast( DeviceHandle, x, y, Color );
  56. }
  57. }
  58. void IRAM_ATTR SSD1306_DrawHLine( struct SSD1306_Device* DeviceHandle, int x, int y, int Width, int Color ) {
  59. int XEnd = x + Width;
  60. NullCheck( DeviceHandle, return );
  61. NullCheck( DeviceHandle->Framebuffer, return );
  62. for ( ; x <= XEnd; x++ ) {
  63. if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
  64. SSD1306_DrawPixelFast( DeviceHandle, x, y, Color );
  65. } else {
  66. break;
  67. }
  68. }
  69. }
  70. void IRAM_ATTR SSD1306_DrawVLine( struct SSD1306_Device* DeviceHandle, int x, int y, int Height, int Color ) {
  71. int YEnd = y + Height;
  72. NullCheck( DeviceHandle, return );
  73. NullCheck( DeviceHandle->Framebuffer, return );
  74. for ( ; y <= YEnd; y++ ) {
  75. if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
  76. SSD1306_DrawPixel( DeviceHandle, x, y, Color );
  77. } else {
  78. break;
  79. }
  80. }
  81. }
  82. static inline void IRAM_ATTR DrawWideLine( struct SSD1306_Device* DeviceHandle, int x0, int y0, int x1, int y1, int Color ) {
  83. int dx = ( x1 - x0 );
  84. int dy = ( y1 - y0 );
  85. int Error = 0;
  86. int Incr = 1;
  87. int x = x0;
  88. int y = y0;
  89. if ( dy < 0 ) {
  90. Incr = -1;
  91. dy = -dy;
  92. }
  93. Error = ( dy * 2 ) - dx;
  94. for ( ; x <= x1; x++ ) {
  95. if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
  96. SSD1306_DrawPixelFast( DeviceHandle, x, y, Color );
  97. }
  98. if ( Error > 0 ) {
  99. Error-= ( dx * 2 );
  100. y+= Incr;
  101. }
  102. Error+= ( dy * 2 );
  103. }
  104. }
  105. static inline void IRAM_ATTR DrawTallLine( struct SSD1306_Device* DeviceHandle, int x0, int y0, int x1, int y1, int Color ) {
  106. int dx = ( x1 - x0 );
  107. int dy = ( y1 - y0 );
  108. int Error = 0;
  109. int Incr = 1;
  110. int x = x0;
  111. int y = y0;
  112. if ( dx < 0 ) {
  113. Incr = -1;
  114. dx = -dx;
  115. }
  116. Error = ( dx * 2 ) - dy;
  117. for ( ; y < y1; y++ ) {
  118. if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
  119. SSD1306_DrawPixelFast( DeviceHandle, x, y, Color );
  120. }
  121. if ( Error > 0 ) {
  122. Error-= ( dy * 2 );
  123. x+= Incr;
  124. }
  125. Error+= ( dx * 2 );
  126. }
  127. }
  128. void IRAM_ATTR SSD1306_DrawLine( struct SSD1306_Device* DeviceHandle, int x0, int y0, int x1, int y1, int Color ) {
  129. NullCheck( DeviceHandle, return );
  130. NullCheck( DeviceHandle->Framebuffer, return );
  131. if ( x0 == x1 ) {
  132. SSD1306_DrawVLine( DeviceHandle, x0, y0, ( y1 - y0 ), Color );
  133. } else if ( y0 == y1 ) {
  134. SSD1306_DrawHLine( DeviceHandle, x0, y0, ( x1 - x0 ), Color );
  135. } else {
  136. if ( abs( x1 - x0 ) > abs( y1 - y0 ) ) {
  137. /* Wide ( run > rise ) */
  138. if ( x0 > x1 ) {
  139. SwapInt( &x0, &x1 );
  140. SwapInt( &y0, &y1 );
  141. }
  142. DrawWideLine( DeviceHandle, x0, y0, x1, y1, Color );
  143. } else {
  144. /* Tall ( rise > run ) */
  145. if ( y0 > y1 ) {
  146. SwapInt( &y0, &y1 );
  147. SwapInt( &x0, &x1 );
  148. }
  149. DrawTallLine( DeviceHandle, x0, y0, x1, y1, Color );
  150. }
  151. }
  152. }
  153. void IRAM_ATTR SSD1306_DrawBox( struct SSD1306_Device* DeviceHandle, int x1, int y1, int x2, int y2, int Color, bool Fill ) {
  154. int Width = ( x2 - x1 );
  155. int Height = ( y2 - y1 );
  156. NullCheck( DeviceHandle, return );
  157. NullCheck( DeviceHandle->Framebuffer, return );
  158. if ( Fill == false ) {
  159. /* Top side */
  160. SSD1306_DrawHLine( DeviceHandle, x1, y1, Width, Color );
  161. /* Bottom side */
  162. SSD1306_DrawHLine( DeviceHandle, x1, y1 + Height, Width, Color );
  163. /* Left side */
  164. SSD1306_DrawVLine( DeviceHandle, x1, y1, Height, Color );
  165. /* Right side */
  166. SSD1306_DrawVLine( DeviceHandle, x1 + Width, y1, Height, Color );
  167. } else {
  168. /* Fill the box by drawing horizontal lines */
  169. for ( ; y1 <= y2; y1++ ) {
  170. SSD1306_DrawHLine( DeviceHandle, x1, y1, Width, Color );
  171. }
  172. }
  173. }
  174. void SSD1306_Clear( struct SSD1306_Device* DeviceHandle, int Color ) {
  175. NullCheck( DeviceHandle, return );
  176. NullCheck( DeviceHandle->Framebuffer, return );
  177. memset( DeviceHandle->Framebuffer, Color, DeviceHandle->FramebufferSize );
  178. }