gds_font.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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 "gds_private.h"
  12. #include "gds.h"
  13. #include "gds_font.h"
  14. #include "gds_draw.h"
  15. #include "gds_err.h"
  16. static int RoundUpFontHeight( const struct GDS_FontDef* Font ) {
  17. int Height = Font->Height;
  18. if ( ( Height % 8 ) != 0 ) {
  19. return ( ( Height + 7 ) / 8 ) * 8;
  20. }
  21. return Height;
  22. }
  23. static const uint8_t* GetCharPtr( const struct GDS_FontDef* Font, char Character ) {
  24. return &Font->FontData[ ( Character - Font->StartChar ) * ( ( Font->Width * ( RoundUpFontHeight( Font ) / 8 ) ) + 1 ) ];
  25. }
  26. void GDS_FontDrawChar( struct GDS_Device* Device, char Character, int x, int y, int Color ) {
  27. const uint8_t* GlyphData = NULL;
  28. int GlyphColumnLen = 0;
  29. int CharStartX = 0;
  30. int CharStartY = 0;
  31. int CharWidth = 0;
  32. int CharHeight = 0;
  33. int CharEndX = 0;
  34. int CharEndY = 0;
  35. int OffsetX = 0;
  36. int OffsetY = 0;
  37. int YByte = 0;
  38. int YBit = 0;
  39. int i = 0;
  40. NullCheck( ( GlyphData = GetCharPtr( Device->Font, Character ) ), return );
  41. if ( Character >= Device->Font->StartChar && Character <= Device->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( Device->Font ) / 8;
  45. CharWidth = GDS_FontGetCharWidth( Device, Character );
  46. CharHeight = GDS_FontGetHeight( Device );
  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 >= Device->TextWidth || CharEndY < 0 || CharStartY >= Device->Height ) {
  62. ClipDebug( x, y );
  63. return;
  64. }
  65. /* Do not attempt to draw past the end of the screen */
  66. CharEndX = ( CharEndX >= Device->TextWidth ) ? Device->TextWidth - 1 : CharEndX;
  67. CharEndY = ( CharEndY >= Device->Height ) ? Device->Height - 1 : CharEndY;
  68. Device->Dirty = true;
  69. for ( x = CharStartX; x < CharEndX; x++ ) {
  70. for ( y = CharStartY, i = 0; y < CharEndY && i < CharHeight; y++, i++ ) {
  71. YByte = ( i + OffsetY ) / 8;
  72. YBit = ( i + OffsetY ) & 0x07;
  73. if ( GlyphData[ YByte ] & BIT( YBit ) ) {
  74. DrawPixel( Device, x, y, Color );
  75. }
  76. }
  77. GlyphData+= GlyphColumnLen;
  78. }
  79. }
  80. }
  81. const struct GDS_FontDef* GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font ) {
  82. const struct GDS_FontDef* OldFont = Display->Font;
  83. Display->FontForceProportional = false;
  84. Display->FontForceMonospace = false;
  85. Display->Font = Font;
  86. return OldFont;
  87. }
  88. void GDS_FontForceProportional( struct GDS_Device* Display, bool Force ) {
  89. Display->FontForceProportional = Force;
  90. }
  91. void GDS_FontForceMonospace( struct GDS_Device* Display, bool Force ) {
  92. Display->FontForceMonospace = Force;
  93. }
  94. int GDS_FontGetWidth( struct GDS_Device* Display ) {
  95. return Display->Font->Width;
  96. }
  97. int GDS_FontGetHeight( struct GDS_Device* Display ) {
  98. return Display->Font->Height;
  99. }
  100. int GDS_FontGetCharWidth( struct GDS_Device* Display, char Character ) {
  101. const uint8_t* CharPtr = NULL;
  102. int Width = 0;
  103. if ( Character >= Display->Font->StartChar && Character <= Display->Font->EndChar ) {
  104. CharPtr = GetCharPtr( Display->Font, Character );
  105. Width = ( Display->Font->Monospace == true ) ? Display->Font->Width : *CharPtr;
  106. if ( Display->FontForceMonospace == true ) {
  107. Width = Display->Font->Width;
  108. }
  109. if ( Display->FontForceProportional == true ) {
  110. Width = *CharPtr;
  111. }
  112. }
  113. return Width;
  114. }
  115. int GDS_FontGetMaxCharsPerRow( struct GDS_Device* Display ) {
  116. return Display->TextWidth / Display->Font->Width;
  117. }
  118. int GDS_FontGetMaxCharsPerColumn( struct GDS_Device* Display ) {
  119. return Display->Height / Display->Font->Height;
  120. }
  121. int GDS_FontGetCharHeight( struct GDS_Device* Display ) {
  122. return Display->Font->Height;
  123. }
  124. int GDS_FontMeasureString( struct GDS_Device* Display, const char* Text ) {
  125. int Width = 0;
  126. int Len = 0;
  127. NullCheck( Text, return 0 );
  128. for ( Len = strlen( Text ); Len >= 0; Len--, Text++ ) {
  129. if ( *Text >= Display->Font->StartChar && *Text <= Display->Font->EndChar ) {
  130. Width+= GDS_FontGetCharWidth( Display, *Text );
  131. }
  132. }
  133. return Width;
  134. }
  135. void GDS_FontDrawString( struct GDS_Device* Display, int x, int y, const char* Text, int Color ) {
  136. int Len = 0;
  137. int i = 0;
  138. NullCheck( Text, return );
  139. for ( Len = strlen( Text ), i = 0; i < Len; i++ ) {
  140. GDS_FontDrawChar( Display, *Text, x, y, Color );
  141. x+= GDS_FontGetCharWidth( Display, *Text );
  142. Text++;
  143. }
  144. }
  145. void GDS_FontDrawAnchoredString( struct GDS_Device* Display, TextAnchor Anchor, const char* Text, int Color ) {
  146. int x = 0;
  147. int y = 0;
  148. NullCheck( Text, return );
  149. GDS_FontGetAnchoredStringCoords( Display, &x, &y, Anchor, Text );
  150. GDS_FontDrawString( Display, x, y, Text, Color );
  151. }
  152. void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int* OutY, TextAnchor Anchor, const char* Text ) {
  153. int StringWidth = 0;
  154. int StringHeight = 0;
  155. NullCheck( OutX, return );
  156. NullCheck( OutY, return );
  157. NullCheck( Text, return );
  158. StringWidth = GDS_FontMeasureString( Display, Text );
  159. StringHeight = GDS_FontGetCharHeight( Display );
  160. switch ( Anchor ) {
  161. case TextAnchor_East: {
  162. *OutY = ( Display->Height / 2 ) - ( StringHeight / 2 );
  163. *OutX = ( Display->TextWidth - StringWidth );
  164. break;
  165. }
  166. case TextAnchor_West: {
  167. *OutY = ( Display->Height / 2 ) - ( StringHeight / 2 );
  168. *OutX = 0;
  169. break;
  170. }
  171. case TextAnchor_North: {
  172. *OutX = ( Display->TextWidth / 2 ) - ( StringWidth / 2 );
  173. *OutY = 0;
  174. break;
  175. }
  176. case TextAnchor_South: {
  177. *OutX = ( Display->TextWidth / 2 ) - ( StringWidth / 2 );
  178. *OutY = ( Display->Height - StringHeight );
  179. break;
  180. }
  181. case TextAnchor_NorthEast: {
  182. *OutX = ( Display->TextWidth - StringWidth );
  183. *OutY = 0;
  184. break;
  185. }
  186. case TextAnchor_NorthWest: {
  187. *OutY = 0;
  188. *OutX = 0;
  189. break;
  190. }
  191. case TextAnchor_SouthEast: {
  192. *OutY = ( Display->Height - StringHeight );
  193. *OutX = ( Display->TextWidth - StringWidth );
  194. break;
  195. }
  196. case TextAnchor_SouthWest: {
  197. *OutY = ( Display->Height - StringHeight );
  198. *OutX = 0;
  199. break;
  200. }
  201. case TextAnchor_Center: {
  202. *OutY = ( Display->Height / 2 ) - ( StringHeight / 2 );
  203. *OutX = ( Display->TextWidth / 2 ) - ( StringWidth / 2 );
  204. break;
  205. }
  206. default: {
  207. *OutX = 128;
  208. *OutY = 64;
  209. break;
  210. }
  211. };
  212. }