ssd1306_font.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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 <math.h>
  11. #include "ssd1306.h"
  12. #include "ssd1306_draw.h"
  13. #include "ssd1306_font.h"
  14. static int RoundUpFontHeight( const struct SSD1306_FontDef* Font ) {
  15. int Height = Font->Height;
  16. if ( ( Height % 8 ) != 0 ) {
  17. return ( ( Height + 7 ) / 8 ) * 8;
  18. }
  19. return Height;
  20. }
  21. static const uint8_t* GetCharPtr( const struct SSD1306_FontDef* Font, char Character ) {
  22. return &Font->FontData[ ( Character - Font->StartChar ) * ( ( Font->Width * ( RoundUpFontHeight( Font ) / 8 ) ) + 1 ) ];
  23. }
  24. void SSD1306_FontDrawChar( struct SSD1306_Device* DisplayHandle, char Character, int x, int y, int Color ) {
  25. const uint8_t* GlyphData = NULL;
  26. int GlyphColumnLen = 0;
  27. int CharStartX = 0;
  28. int CharStartY = 0;
  29. int CharWidth = 0;
  30. int CharHeight = 0;
  31. int CharEndX = 0;
  32. int CharEndY = 0;
  33. int OffsetX = 0;
  34. int OffsetY = 0;
  35. int YByte = 0;
  36. int YBit = 0;
  37. int i = 0;
  38. NullCheck( DisplayHandle, return );
  39. NullCheck( DisplayHandle->Font, return );
  40. NullCheck( ( GlyphData = GetCharPtr( DisplayHandle->Font, Character ) ), return );
  41. if ( Character >= DisplayHandle->Font->StartChar || Character <= DisplayHandle->Font->EndChar ) {
  42. /* The first byte in the glyph data is the width of the character in pixels, skip over */
  43. GlyphData++;
  44. GlyphColumnLen = RoundUpFontHeight( DisplayHandle->Font ) / 8;
  45. CharWidth = SSD1306_FontGetCharWidth( DisplayHandle, Character );
  46. CharHeight = SSD1306_FontGetHeight( DisplayHandle );
  47. CharStartX = x;
  48. CharStartY = y;
  49. CharEndX = CharStartX + CharWidth;
  50. CharEndY = CharStartY + CharHeight;
  51. /* If the character is partially offscreen offset the end by
  52. * distance between (coord) and 0.
  53. */
  54. OffsetX = ( CharStartX < 0 ) ? abs( CharStartX ) : 0;
  55. OffsetY = ( CharStartY < 0 ) ? abs( CharStartY ) : 0;
  56. /* This skips into the proper column within the glyph data */
  57. GlyphData+= ( OffsetX * GlyphColumnLen );
  58. CharStartX+= OffsetX;
  59. CharStartY+= OffsetY;
  60. /* Do not attempt to draw if this character is entirely offscreen */
  61. if ( CharEndX < 0 || CharStartX >= DisplayHandle->Width || CharEndY < 0 || CharStartY >= DisplayHandle->Height ) {
  62. ClipDebug( x, y );
  63. return;
  64. }
  65. /* Do not attempt to draw past the end of the screen */
  66. CharEndX = ( CharEndX >= DisplayHandle->Width ) ? DisplayHandle->Width - 1 : CharEndX;
  67. CharEndY = ( CharEndY >= DisplayHandle->Height ) ? DisplayHandle->Height - 1 : CharEndY;
  68. for ( x = CharStartX; x < CharEndX; x++ ) {
  69. for ( y = CharStartY, i = 0; y < CharEndY && i < CharHeight; y++, i++ ) {
  70. YByte = ( i + OffsetY ) / 8;
  71. YBit = ( i + OffsetY ) & 0x07;
  72. if ( GlyphData[ YByte ] & BIT( YBit ) ) {
  73. SSD1306_DrawPixel( DisplayHandle, x, y, Color );
  74. }
  75. }
  76. GlyphData+= GlyphColumnLen;
  77. }
  78. }
  79. }
  80. bool SSD1306_SetFont( struct SSD1306_Device* Display, const struct SSD1306_FontDef* Font ) {
  81. NullCheck( Display, return false );
  82. NullCheck( Font, return false );
  83. Display->FontForceProportional = false;
  84. Display->FontForceMonospace = false;
  85. Display->Font = Font;
  86. return true;
  87. }
  88. void SSD1306_FontForceProportional( struct SSD1306_Device* Display, bool Force ) {
  89. NullCheck( Display, return );
  90. NullCheck( Display->Font, return );
  91. Display->FontForceProportional = Force;
  92. }
  93. void SSD1306_FontForceMonospace( struct SSD1306_Device* Display, bool Force ) {
  94. NullCheck( Display, return );
  95. NullCheck( Display->Font, return );
  96. Display->FontForceMonospace = Force;
  97. }
  98. int SSD1306_FontGetWidth( struct SSD1306_Device* Display ) {
  99. NullCheck( Display, return 0 );
  100. NullCheck( Display->Font, return 0 );
  101. return Display->Font->Width;
  102. }
  103. int SSD1306_FontGetHeight( struct SSD1306_Device* Display ) {
  104. NullCheck( Display, return 0 );
  105. NullCheck( Display->Font, return 0 );
  106. return Display->Font->Height;
  107. }
  108. int SSD1306_FontGetCharWidth( struct SSD1306_Device* Display, char Character ) {
  109. const uint8_t* CharPtr = NULL;
  110. int Width = 0;
  111. NullCheck( Display, return 0 );
  112. NullCheck( Display->Font, return 0 );
  113. if ( Character >= Display->Font->StartChar && Character <= Display->Font->EndChar ) {
  114. CharPtr = GetCharPtr( Display->Font, Character );
  115. Width = ( Display->Font->Monospace == true ) ? Display->Font->Width : *CharPtr;
  116. if ( Display->FontForceMonospace == true ) {
  117. Width = Display->Font->Width;
  118. }
  119. if ( Display->FontForceProportional == true ) {
  120. Width = *CharPtr;
  121. }
  122. }
  123. return Width;
  124. }
  125. int SSD1306_FontGetMaxCharsPerRow( struct SSD1306_Device* Display ) {
  126. NullCheck( Display, return 0 );
  127. NullCheck( Display->Font, return 0 );
  128. return Display->Width / Display->Font->Width;
  129. }
  130. int SSD1306_FontGetMaxCharsPerColumn( struct SSD1306_Device* Display ) {
  131. NullCheck( Display, return 0 );
  132. NullCheck( Display->Font, return 0 );
  133. return Display->Height / Display->Font->Height;
  134. }
  135. int SSD1306_FontGetCharHeight( struct SSD1306_Device* Display ) {
  136. NullCheck( Display, return 0 );
  137. NullCheck( Display->Font, return 0 );
  138. return Display->Font->Height;
  139. }
  140. int SSD1306_FontMeasureString( struct SSD1306_Device* Display, const char* Text ) {
  141. int Width = 0;
  142. int Len = 0;
  143. NullCheck( Display, return 0 );
  144. NullCheck( Display->Font, return 0 );
  145. NullCheck( Text, return 0 );
  146. for ( Len = strlen( Text ); Len >= 0; Len--, Text++ ) {
  147. if ( *Text >= Display->Font->StartChar && *Text <= Display->Font->EndChar ) {
  148. Width+= SSD1306_FontGetCharWidth( Display, *Text );
  149. }
  150. }
  151. return Width;
  152. }
  153. void SSD1306_FontDrawString( struct SSD1306_Device* Display, int x, int y, const char* Text, int Color ) {
  154. int Len = 0;
  155. int i = 0;
  156. NullCheck( Display, return );
  157. NullCheck( Display->Font, return );
  158. NullCheck( Text, return );
  159. for ( Len = strlen( Text ), i = 0; i < Len; i++ ) {
  160. SSD1306_FontDrawChar( Display, *Text, x, y, Color );
  161. x+= SSD1306_FontGetCharWidth( Display, *Text );
  162. Text++;
  163. }
  164. }
  165. void SSD1306_FontDrawAnchoredString( struct SSD1306_Device* Display, TextAnchor Anchor, const char* Text, int Color ) {
  166. int x = 0;
  167. int y = 0;
  168. NullCheck( Display, return );
  169. NullCheck( Text, return );
  170. SSD1306_FontGetAnchoredStringCoords( Display, &x, &y, Anchor, Text );
  171. SSD1306_FontDrawString( Display, x, y, Text, Color );
  172. }
  173. void SSD1306_FontGetAnchoredStringCoords( struct SSD1306_Device* Display, int* OutX, int* OutY, TextAnchor Anchor, const char* Text ) {
  174. int StringWidth = 0;
  175. int StringHeight = 0;
  176. NullCheck( Display, return );
  177. NullCheck( OutX, return );
  178. NullCheck( OutY, return );
  179. NullCheck( Text, return );
  180. StringWidth = SSD1306_FontMeasureString( Display, Text );
  181. StringHeight = SSD1306_FontGetCharHeight( Display );
  182. switch ( Anchor ) {
  183. case TextAnchor_East: {
  184. *OutY = ( Display->Height / 2 ) - ( StringHeight / 2 );
  185. *OutX = ( Display->Width - StringWidth );
  186. break;
  187. }
  188. case TextAnchor_West: {
  189. *OutY = ( Display->Height / 2 ) - ( StringHeight / 2 );
  190. *OutX = 0;
  191. break;
  192. }
  193. case TextAnchor_North: {
  194. *OutX = ( Display->Width / 2 ) - ( StringWidth / 2 );
  195. *OutY = 0;
  196. break;
  197. }
  198. case TextAnchor_South: {
  199. *OutX = ( Display->Width / 2 ) - ( StringWidth / 2 );
  200. *OutY = ( Display->Height - StringHeight );
  201. break;
  202. }
  203. case TextAnchor_NorthEast: {
  204. *OutX = ( Display->Width - StringWidth );
  205. *OutY = 0;
  206. break;
  207. }
  208. case TextAnchor_NorthWest: {
  209. *OutY = 0;
  210. *OutX = 0;
  211. break;
  212. }
  213. case TextAnchor_SouthEast: {
  214. *OutY = ( Display->Height - StringHeight );
  215. *OutX = ( Display->Width - StringWidth );
  216. break;
  217. }
  218. case TextAnchor_SouthWest: {
  219. *OutY = ( Display->Height - StringHeight );
  220. *OutX = 0;
  221. break;
  222. }
  223. case TextAnchor_Center: {
  224. *OutY = ( Display->Height / 2 ) - ( StringHeight / 2 );
  225. *OutX = ( Display->Width / 2 ) - ( StringWidth / 2 );
  226. break;
  227. }
  228. default: {
  229. *OutX = 128;
  230. *OutY = 64;
  231. break;
  232. }
  233. };
  234. }