SDL_ttf: Re-added solid text rendering

From a0ed8b647fcbd88832213e928e624c24ed117a68 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 24 Oct 2024 09:09:05 -0700
Subject: [PATCH] Re-added solid text rendering

It turns out this is useful for pixel fonts

Fixes https://github.com/libsdl-org/SDL_ttf/issues/423
---
 docs/README-migration.md   |   8 +-
 examples/showfont.c        |  13 ++-
 examples/testapp.c         |  40 +++++----
 include/SDL3_ttf/SDL_ttf.h | 138 +++++++++++++++++++++++++++++++
 src/SDL_ttf.c              | 163 ++++++++++++++++++++++++++++++-------
 src/SDL_ttf.sym            |   3 +
 6 files changed, 314 insertions(+), 51 deletions(-)

diff --git a/docs/README-migration.md b/docs/README-migration.md
index f56e3ece..bb609986 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -36,8 +36,6 @@ Several functions have been renamed. We have provided a handy semantic patch to
 
 In general we have switched to using UTF8 in the API. Functions which had 3 variants, for Latin-1, UTF-8, and UCS2, now accept UTF-8 text. In addition, those functions now have an optional length parameter which allows you to render substrings.
 
-The solid color rendering functions have been removed in favor of the higher quality shaded and blended functions.
-
 The alpha in background colors is now transparent if it's equal to 0.
 
 The following functions have been renamed:
@@ -58,12 +56,15 @@ The following functions have been renamed:
 * TTF_RenderGlyph32_Blended() => TTF_RenderGlyph_Blended()
 * TTF_RenderGlyph32_LCD() => TTF_RenderGlyph_LCD()
 * TTF_RenderGlyph32_Shaded() => TTF_RenderGlyph_Shaded()
+* TTF_RenderGlyph32_Solid() => TTF_RenderGlyph_Solid()
 * TTF_RenderUTF8_Blended() => TTF_RenderText_Blended()
 * TTF_RenderUTF8_Blended_Wrapped() => TTF_RenderText_Blended_Wrapped()
 * TTF_RenderUTF8_LCD() => TTF_RenderText_LCD()
 * TTF_RenderUTF8_LCD_Wrapped() => TTF_RenderText_LCD_Wrapped()
 * TTF_RenderUTF8_Shaded() => TTF_RenderText_Shaded()
 * TTF_RenderUTF8_Shaded_Wrapped() => TTF_RenderText_Shaded_Wrapped()
+* TTF_RenderUTF8_Solid() => TTF_RenderText_Solid()
+* TTF_RenderUTF8_Solid_Wrapped() => TTF_RenderText_Solid_Wrapped()
 * TTF_SetFontScriptName() => TTF_SetFontScript()
 * TTF_SetFontWrappedAlign() => TTF_SetFontWrapAlignment()
 * TTF_SizeText() => TTF_GetTextSize()
@@ -81,7 +82,6 @@ The following functions have been removed:
 * TTF_OpenFontIndexDPI() - replaced with TTF_OpenFontWithProperties()
 * TTF_OpenFontIndexDPIIO() - replaced with TTF_OpenFontWithProperties()
 * TTF_OpenFontIndexIO() - replaced with TTF_OpenFontWithProperties()
-* TTF_RenderGlyph32_Solid()
 * TTF_RenderGlyph_Solid()
 * TTF_RenderText_Solid()
 * TTF_RenderText_Solid_Wrapped()
@@ -93,8 +93,6 @@ The following functions have been removed:
 * TTF_RenderUNICODE_Shaded_Wrapped()
 * TTF_RenderUNICODE_Solid()
 * TTF_RenderUNICODE_Solid_Wrapped()
-* TTF_RenderUTF8_Solid()
-* TTF_RenderUTF8_Solid_Wrapped()
 * TTF_SizeUNICODE()
 
 The following symbols have been renamed:
diff --git a/examples/showfont.c b/examples/showfont.c
index 244abad1..a9284579 100644
--- a/examples/showfont.c
+++ b/examples/showfont.c
@@ -40,7 +40,7 @@
 
 
 #define TTF_SHOWFONT_USAGE \
-"Usage: %s [-textengine surface|renderer] [-shaded] [-blended] [-wrapped] [-b] [-i] [-u] [-s] [-outline size] [-hintlight|-hintmono|-hintnone] [-nokerning] [-wrap] [-align left|center|right] [-fgcol r,g,b,a] [-bgcol r,g,b,a] [-editbox] <font>.ttf [ptsize] [text]\n"
+"Usage: %s [-textengine surface|renderer] [-solid] [-shaded] [-blended] [-wrapped] [-b] [-i] [-u] [-s] [-outline size] [-hintlight|-hintmono|-hintnone] [-nokerning] [-wrap] [-align left|center|right] [-fgcol r,g,b,a] [-bgcol r,g,b,a] [-editbox] <font>.ttf [ptsize] [text]\n"
 
 typedef enum
 {
@@ -51,6 +51,7 @@ typedef enum
 
 typedef enum
 {
+    TextRenderSolid,
     TextRenderShaded,
     TextRenderBlended
 } TextRenderMethod;
@@ -311,6 +312,9 @@ int main(int argc, char *argv[])
                 return(1);
             }
         } else
+        if (SDL_strcmp(argv[i], "-solid") == 0) {
+            rendermethod = TextRenderSolid;
+        } else
         if (SDL_strcmp(argv[i], "-shaded") == 0) {
             rendermethod = TextRenderShaded;
         } else
@@ -511,6 +515,13 @@ int main(int argc, char *argv[])
         message = DEFAULT_TEXT;
     }
     switch (rendermethod) {
+    case TextRenderSolid:
+        if (wrap) {
+            text = TTF_RenderText_Solid_Wrapped(font, message, 0, *forecol, 0);
+        } else {
+            text = TTF_RenderText_Solid(font, message, 0, *forecol);
+        }
+        break;
     case TextRenderShaded:
         if (wrap) {
             text = TTF_RenderText_Shaded_Wrapped(font, message, 0, *forecol, *backcol, 0);
diff --git a/examples/testapp.c b/examples/testapp.c
index 57cd4590..8c364a2c 100644
--- a/examples/testapp.c
+++ b/examples/testapp.c
@@ -112,7 +112,7 @@ static void help(void)
     SDL_Log("t   : ticks elapsed for 50 rendering");
     SDL_Log("d   : display normal texture, no screen update, stream texture ");
     SDL_Log("r   : start/stop random test");
-    SDL_Log("m   : render mode Blended/Shaded");
+    SDL_Log("m   : render mode Solid/Blended/Shaded");
     SDL_Log("x   : text engine None/Surface/Renderer");
     SDL_Log("n   : change direction");
     SDL_Log("9/0 : -/+ alpha color fg");
@@ -191,10 +191,10 @@ static int print_elapsed_ticks = 0;
 static int update_screen_mode = 0;
 static int save_to_bmp = 0;
 
-/* RENDER_BLENDED = 0, RENDER_SHADED = 1, RENDER_LCD = 2 */
+/* RENDER_SOLID = 0, RENDER_BLENDED = 1, RENDER_SHADED = 2, RENDER_LCD = 3 } */
 static int render_mode = -1;
 static int render_mode_overwrite;
-static const char *render_mode_desc[] = { "Blended", "Shaded", "LCD" };
+static const char *render_mode_desc[] = { "Solid", "Blended", "Shaded", "LCD" };
 static const int render_mode_count = SDL_arraysize(render_mode_desc);
 
 static int textengine_mode = 0;
@@ -698,6 +698,10 @@ int main(void)
     seed=1641805930; replay=1; font_style=9; kerning=1; sdf=1; wrap=0; wrap_size=661; w_align=2; outline=0; curr_size=20; render_mode=3; curr_str=14; curr_font=1777; hinting=1; fg_alpha=65; // light LCD
 #endif
 
+    //seed=1673390190; replay=1; font_style=12; kerning=0; sdf=1; wrap=0; wrap_size=91; w_align=0; outline=0; curr_size=16; render_mode=0; curr_str=14; curr_font=1288; hinting=0; fg_alpha=77; // none Solid
+
+    //seed=1673390190; replay=1; font_style=12; kerning=0; sdf=0; wrap=0; wrap_size=91; w_align=0; outline=0; curr_size=30; render_mode=1; curr_str=14; curr_font=1288; hinting=0; fg_alpha=77; // none Solid
+
     //seed=1673390190; replay=1; font_style=9; kerning=1; sdf=0; wrap=1; wrap_size=94; w_align=2; outline=7; curr_size=42; render_mode=1; curr_str=75; curr_font=1997; hinting=1; fg_alpha=90; // light Blended
 
     if (replay) {
@@ -957,15 +961,17 @@ int main(void)
 
                 if (textengine_mode == 0) {
 
-                    switch (render_mode)
-                    {
+                    switch (render_mode) {
                        case 0:
-                          text_surface = TTF_RenderText_Blended(font, text, 0, textcol);
+                          text_surface = TTF_RenderText_Solid(font, text, 0, textcol);
                           break;
                        case 1:
-                          text_surface = TTF_RenderText_Shaded(font, text, 0, textcol, boardcol);
+                          text_surface = TTF_RenderText_Blended(font, text, 0, textcol);
                           break;
                        case 2:
+                          text_surface = TTF_RenderText_Shaded(font, text, 0, textcol, boardcol);
+                          break;
+                       case 3:
 #if defined(HAVE_LCD)
                           text_surface = TTF_RenderText_LCD(font, text, 0, textcol, boardcol);
 #else
@@ -996,15 +1002,17 @@ int main(void)
                 }
 
                 if (textengine_mode == 0) {
-                    switch (render_mode)
-                    {
+                    switch (render_mode) {
                        case 0:
-                          text_surface = TTF_RenderText_Blended(font, text, 0, textcol);
+                          text_surface = TTF_RenderText_Solid(font, text, 0, textcol);
                           break;
                        case 1:
-                          text_surface = TTF_RenderText_Shaded(font, text, 0, textcol, boardcol);
+                          text_surface = TTF_RenderText_Blended(font, text, 0, textcol);
                           break;
                        case 2:
+                          text_surface = TTF_RenderText_Shaded(font, text, 0, textcol, boardcol);
+                          break;
+                       case 3:
 #if defined(HAVE_LCD)
                           text_surface = TTF_RenderText_LCD(font, text, 0, textcol, boardcol);
 #else
@@ -1047,15 +1055,17 @@ int main(void)
                 }
 
                 if (textengine_mode == 0) {
-                    switch (render_mode)
-                    {
+                    switch (render_mode) {
                         case 0:
-                            text_surface = TTF_RenderText_Blended_Wrapped(font, text, 0, textcol, wrap_size);
+                            text_surface = TTF_RenderText_Solid_Wrapped(font, text, 0, textcol, wrap_size);
                             break;
                         case 1:
-                            text_surface = TTF_RenderText_Shaded_Wrapped(font, text, 0, textcol, boardcol, wrap_size);
+                            text_surface = TTF_RenderText_Blended_Wrapped(font, text, 0, textcol, wrap_size);
                             break;
                         case 2:
+                            text_surface = TTF_RenderText_Shaded_Wrapped(font, text, 0, textcol, boardcol, wrap_size);
+                            break;
+                        case 3:
 #if defined(HAVE_LCD)
                             text_surface = TTF_RenderText_LCD_Wrapped(font, text, 0, textcol, boardcol, wrap_size);
 #else
diff --git a/include/SDL3_ttf/SDL_ttf.h b/include/SDL3_ttf/SDL_ttf.h
index ab7c492b..9e00cf75 100644
--- a/include/SDL3_ttf/SDL_ttf.h
+++ b/include/SDL3_ttf/SDL_ttf.h
@@ -757,6 +757,108 @@ typedef enum TTF_Direction
   TTF_DIRECTION_BTT         /* Bottom to Top */
 } TTF_Direction;
 
+/**
+ * Render UTF-8 text at fast quality to a new 8-bit surface.
+ *
+ * This function will allocate a new 8-bit, palettized surface. The surface's
+ * 0 pixel will be the colorkey, giving a transparent background. The 1 pixel
+ * will be set to the text color.
+ *
+ * This will not word-wrap the string; you'll get a surface with a single line
+ * of text, as long as the string requires. You can use
+ * TTF_RenderText_Solid_Wrapped() instead if you need to wrap the output to
+ * multiple lines.
+ *
+ * This will not wrap on newline characters.
+ *
+ * You can render at other quality levels with TTF_RenderText_Shaded,
+ * TTF_RenderText_Blended, and TTF_RenderText_LCD.
+ *
+ * \param font the font to render with.
+ * \param text text to render, in UTF-8 encoding.
+ * \param length the length of the text, in bytes, or 0 for null terminated
+ *               text.
+ * \param fg the foreground color for the text.
+ * \returns a new 8-bit, palettized surface, or NULL if there was an error.
+ *
+ * \threadsafety This function should be called on the thread that created the
+ *               font.
+ *
+ * \since This function is available since SDL_ttf 3.0.0.
+ *
+ * \sa TTF_RenderText_Blended
+ * \sa TTF_RenderText_LCD
+ * \sa TTF_RenderText_Shaded
+ * \sa TTF_RenderText_Solid
+ * \sa TTF_RenderText_Solid_Wrapped
+ */
+extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Solid(TTF_Font *font, const char *text, size_t length, SDL_Color fg);
+
+/**
+ * Render word-wrapped UTF-8 text at fast quality to a new 8-bit surface.
+ *
+ * This function will allocate a new 8-bit, palettized surface. The surface's
+ * 0 pixel will be the colorkey, giving a transparent background. The 1 pixel
+ * will be set to the text color.
+ *
+ * Text is wrapped to multiple lines on line endings and on word boundaries if
+ * it extends beyond `wrapLength` in pixels.
+ *
+ * If wrapLength is 0, this function will only wrap on newline characters.
+ *
+ * You can render at other quality levels with TTF_RenderText_Shaded_Wrapped,
+ * TTF_RenderText_Blended_Wrapped, and TTF_RenderText_LCD_Wrapped.
+ *
+ * \param font the font to render with.
+ * \param text text to render, in UTF-8 encoding.
+ * \param length the length of the text, in bytes, or 0 for null terminated
+ *               text.
+ * \param fg the foreground color for the text.
+ * \param wrapLength the maximum width of the text surface or 0 to wrap on
+ *                   newline characters.
+ * \returns a new 8-bit, palettized surface, or NULL if there was an error.
+ *
+ * \threadsafety This function should be called on the thread that created the
+ *               font.
+ *
+ * \since This function is available since SDL_ttf 3.0.0.
+ *
+ * \sa TTF_RenderText_Blended_Wrapped
+ * \sa TTF_RenderText_LCD_Wrapped
+ * \sa TTF_RenderText_Shaded_Wrapped
+ * \sa TTF_RenderText_Solid
+ */
+extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Solid_Wrapped(TTF_Font *font, const char *text, size_t length, SDL_Color fg, int wrapLength);
+
+/**
+ * Render a single 32-bit glyph at fast quality to a new 8-bit surface.
+ *
+ * This function will allocate a new 8-bit, palettized surface. The surface's
+ * 0 pixel will be the colorkey, giving a transparent background. The 1 pixel
+ * will be set to the text color.
+ *
+ * The glyph is rendered without any padding or centering in the X direction,
+ * and aligned normally in the Y direction.
+ *
+ * You can render at other quality levels with TTF_RenderGlyph_Shaded,
+ * TTF_RenderGlyph_Blended, and TTF_RenderGlyph_LCD.
+ *
+ * \param font the font to render with.
+ * \param ch the character to render.
+ * \param fg the foreground color for the text.
+ * \returns a new 8-bit, palettized surface, or NULL if there was an error.
+ *
+ * \threadsafety This function should be called on the thread that created the
+ *               font.
+ *
+ * \since This function is available since SDL_ttf 3.0.0.
+ *
+ * \sa TTF_RenderGlyph_Blended
+ * \sa TTF_RenderGlyph_LCD
+ * \sa TTF_RenderGlyph_Shaded
+ */
+extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Solid(TTF_Font *font, Uint32 ch, SDL_Color fg);
+
 /**
  * Set direction to be used for text shaping by a font.
  *
@@ -1057,6 +1159,9 @@ extern SDL_DECLSPEC bool SDLCALL TTF_MeasureString(TTF_Font *font, const char *t
  *
  * This will not wrap on newline characters.
  *
+ * You can render at other quality levels with TTF_RenderText_Solid,
+ * TTF_RenderText_Blended, and TTF_RenderText_LCD.
+ *
  * \param font the font to render with.
  * \param text text to render, in UTF-8 encoding.
  * \param length the length of the text, in bytes, or 0 for null terminated
@@ -1073,6 +1178,7 @@ extern SDL_DECLSPEC bool SDLCALL TTF_MeasureString(TTF_Font *font, const char *t
  * \sa TTF_RenderText_Blended
  * \sa TTF_RenderText_LCD
  * \sa TTF_RenderText_Shaded_Wrapped
+ * \sa TTF_RenderText_Solid
  */
 extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Shaded(TTF_Font *font, const char *text, size_t length, SDL_Color fg, SDL_Color bg);
 
@@ -1089,6 +1195,9 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Shaded(TTF_Font *font,
  *
  * If wrap_width is 0, this function will only wrap on newline characters.
  *
+ * You can render at other quality levels with TTF_RenderText_Solid_Wrapped,
+ * TTF_RenderText_Blended_Wrapped, and TTF_RenderText_LCD_Wrapped.
+ *
  * \param font the font to render with.
  * \param text text to render, in UTF-8 encoding.
  * \param length the length of the text, in bytes, or 0 for null terminated
@@ -1107,6 +1216,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Shaded(TTF_Font *font,
  * \sa TTF_RenderText_Blended_Wrapped
  * \sa TTF_RenderText_LCD_Wrapped
  * \sa TTF_RenderText_Shaded
+ * \sa TTF_RenderText_Solid_Wrapped
  */
 extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Shaded_Wrapped(TTF_Font *font, const char *text, size_t length, SDL_Color fg, SDL_Color bg, int wrap_width);
 
@@ -1121,6 +1231,9 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Shaded_Wrapped(TTF_Font
  * The glyph is rendered without any padding or centering in the X direction,
  * and aligned normally in the Y direction.
  *
+ * You can render at other quality levels with TTF_RenderGlyph_Solid,
+ * TTF_RenderGlyph_Blended, and TTF_RenderGlyph_LCD.
+ *
  * \param font the font to render with.
  * \param ch the codepoint to render.
  * \param fg the foreground color for the text.
@@ -1134,6 +1247,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Shaded_Wrapped(TTF_Font
  *
  * \sa TTF_RenderGlyph_Blended
  * \sa TTF_RenderGlyph_LCD
+ * \sa TTF_RenderGlyph_Solid
  */
 extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Shaded(TTF_Font *font, Uint32 ch, SDL_Color fg, SDL_Color bg);
 
@@ -1151,6 +1265,9 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Shaded(TTF_Font *font,
  *
  * This will not wrap on newline characters.
  *
+ * You can render at other quality levels with TTF_RenderText_Solid,
+ * TTF_RenderText_Shaded, and TTF_RenderText_LCD.
+ *
  * \param font the font to render with.
  * \param text text to render, in UTF-8 encoding.
  * \param length the length of the text, in bytes, or 0 for null terminated
@@ -1166,6 +1283,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Shaded(TTF_Font *font,
  * \sa TTF_RenderText_Blended_Wrapped
  * \sa TTF_RenderText_LCD
  * \sa TTF_RenderText_Shaded
+ * \sa TTF_RenderText_Solid
  */
 extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended(TTF_Font *font, const char *text, size_t length, SDL_Color fg);
 
@@ -1181,6 +1299,9 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended(TTF_Font *font,
  *
  * If wrap_width is 0, this function will only wrap on newline characters.
  *
+ * You can render at other quality levels with TTF_RenderText_Solid_Wrapped,
+ * TTF_RenderText_Shaded_Wrapped, and TTF_RenderText_LCD_Wrapped.
+ *
  * \param font the font to render with.
  * \param text text to render, in UTF-8 encoding.
  * \param length the length of the text, in bytes, or 0 for null terminated
@@ -1198,6 +1319,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended(TTF_Font *font,
  * \sa TTF_RenderText_Blended
  * \sa TTF_RenderText_LCD_Wrapped
  * \sa TTF_RenderText_Shaded_Wrapped
+ * \sa TTF_RenderText_Solid_Wrapped
  */
 extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended_Wrapped(TTF_Font *font, const char *text, size_t length, SDL_Color fg, int wrap_width);
 
@@ -1211,6 +1333,9 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended_Wrapped(TTF_Fon
  * The glyph is rendered without any padding or centering in the X direction,
  * and aligned normally in the Y direction.
  *
+ * You can render at other quality levels with TTF_RenderGlyph_Solid,
+ * TTF_RenderGlyph_Shaded, and TTF_RenderGlyph_LCD.
+ *
  * \param font the font to render with.
  * \param ch the codepoint to render.
  * \param fg the foreground color for the text.
@@ -1223,6 +1348,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended_Wrapped(TTF_Fon
  *
  * \sa TTF_RenderGlyph_LCD
  * \sa TTF_RenderGlyph_Shaded
+ * \sa TTF_RenderGlyph_Solid
  */
 extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Blended(TTF_Font *font, Uint32 ch, SDL_Color fg);
 
@@ -1240,6 +1366,9 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Blended(TTF_Font *font
  *
  * This will not wrap on newline characters.
  *
+ * You can render at other quality levels with TTF_RenderText_Solid,
+ * TTF_RenderText_Shaded, and TTF_RenderText_Blended.
+ *
  * \param font the font to render with.
  * \param text text to render, in UTF-8 encoding.
  * \param length the length of the text, in bytes, or 0 for null terminated
@@ -1256,6 +1385,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Blended(TTF_Font *font
  * \sa TTF_RenderText_Blended
  * \sa TTF_RenderText_LCD_Wrapped
  * \sa TTF_RenderText_Shaded
+ * \sa TTF_RenderText_Solid
  */
 extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_LCD(TTF_Font *font, const char *text, size_t length, SDL_Color fg, SDL_Color bg);
 
@@ -1272,6 +1402,9 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_LCD(TTF_Font *font, con
  *
  * If wrap_width is 0, this function will only wrap on newline characters.
  *
+ * You can render at other quality levels with TTF_RenderText_Solid_Wrapped,
+ * TTF_RenderText_Shaded_Wrapped, and TTF_RenderText_Blended_Wrapped.
+ *
  * \param font the font to render with.
  * \param text text to render, in UTF-8 encoding.
  * \param length the length of the text, in bytes, or 0 for null terminated
@@ -1290,6 +1423,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_LCD(TTF_Font *font, con
  * \sa TTF_RenderText_Blended_Wrapped
  * \sa TTF_RenderText_LCD
  * \sa TTF_RenderText_Shaded_Wrapped
+ * \sa TTF_RenderText_Solid_Wrapped
  */
 extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_LCD_Wrapped(TTF_Font *font, const char *text, size_t length, SDL_Color fg, SDL_Color bg, int wrap_width);
 
@@ -1304,6 +1438,9 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_LCD_Wrapped(TTF_Font *f
  * The glyph is rendered without any padding or centering in the X direction,
  * and aligned normally in the Y direction.
  *
+ * You can render at other quality levels with TTF_RenderGlyph_Solid,
+ * TTF_RenderGlyph_Shaded, and TTF_RenderGlyph_Blended.
+ *
  * \param font the font to render with.
  * \param ch the codepoint to render.
  * \param fg the foreground color for the text.
@@ -1317,6 +1454,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_LCD_Wrapped(TTF_Font *f
  *
  * \sa TTF_RenderGlyph_Blended
  * \sa TTF_RenderGlyph_Shaded
+ * \sa TTF_RenderGlyph_Solid
  */
 extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_LCD(TTF_Font *font, Uint32 ch, SDL_Color fg, SDL_Color bg);
 
diff --git a/src/SDL_ttf.c b/src/SDL_ttf.c
index 6908a729..4951c04e 100644
--- a/src/SDL_ttf.c
+++ b/src/SDL_ttf.c
@@ -170,12 +170,13 @@ static SDL_INLINE int hasNEON(void)
 #define DIVIDE_BY_255(x)    DIVIDE_BY_255_SIGNED(x, 1)
 
 
-#define CACHED_METRICS  0x10
+#define CACHED_METRICS  0x20
 
-#define CACHED_PIXMAP   0x01
-#define CACHED_COLOR    0x02
-#define CACHED_LCD      0x04
-#define CACHED_SUBPIX   0x08
+#define CACHED_BITMAP   0x01
+#define CACHED_PIXMAP   0x02
+#define CACHED_COLOR    0x04
+#define CACHED_LCD      0x08
+#define CACHED_SUBPIX   0x10
 
 
 typedef struct {
@@ -192,6 +193,7 @@ typedef struct {
 typedef struct cached_glyph {
     int stored;
     FT_UInt index;
+    TTF_Image bitmap;
     TTF_Image pixmap;
     int sz_left;
     int sz_top;
@@ -338,6 +340,7 @@ static struct
     TTF_CHECK_POINTER("font", font, errval)
 
 typedef enum {
+    RENDER_SOLID = 0,
     RENDER_SHADED,
     RENDER_BLENDED,
     RENDER_LCD
@@ -347,7 +350,7 @@ typedef enum {
         false, 0, NULL, NULL
 
 
-static bool Find_GlyphByIndex(TTF_Font *font, FT_UInt idx, int want_pixmap, int want_color, int want_lcd, int want_subpixel, int translation, c_glyph **out_glyph, TTF_Image **out_image);
+static bool Find_GlyphByIndex(TTF_Font *font, FT_UInt idx, int want_bitmap, int want_pixmap, int want_color, int want_lcd, int want_subpixel, int translation, c_glyph **out_glyph, TTF_Image **out_image);
 
 #if defined(USE_DUFFS_LOOP)
 
@@ -1160,7 +1163,7 @@ static int Get_Alignment(void)
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-value"
 #endif
-#define BUILD_RENDER_LINE(NAME, IS_BLENDED, IS_BLENDED_OPAQUE, IS_LCD, WP_WC, WS, BLIT_GLYPH_BLENDED_OPAQUE_OPTIM, BLIT_GLYPH_BLENDED_OPTIM, BLIT_GLYPH_OPTIM) \
+#define BUILD_RENDER_LINE(NAME, IS_BLENDED, IS_BLENDED_OPAQUE, IS_LCD, WB_WP_WC, WS, BLIT_GLYPH_BLENDED_OPAQUE_OPTIM, BLIT_GLYPH_BLENDED_OPTIM, BLIT_GLYPH_OPTIM) \
                                                                                                                         \
 static bool Render_Line_##NAME(TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, SDL_Color *fg)             \
 {                                                                                                                       \
@@ -1174,7 +1177,7 @@ static bool Render_Line_##NAME(TTF_Font *font, SDL_Surface *textbuf, int xstart,
         int y       = font->pos_buf[i].y;                                                                               \
         TTF_Image *image;                                                                                               \
                                                                                                                         \
-        if (Find_GlyphByIndex(font, idx, WP_WC, WS, x & 63, NULL, &image)) {                                            \
+        if (Find_GlyphByIndex(font, idx, WB_WP_WC, WS, x & 63, NULL, &image)) {                                         \
             int above_w, above_h;                                                                                       \
             Uint32 dstskip;                                                                                             \
             Sint32 srcskip; /* Can be negative */                                                                       \
@@ -1270,18 +1273,20 @@ static bool Render_Line_##NAME(TTF_Font *font, SDL_Surface *textbuf, int xstart,
 }                                                                                                                       \
                                                                                                                         \
 
-#define PIXMAP  CACHED_PIXMAP, 0, 0
-#define COLOR   0, CACHED_COLOR, 0
-#define LCD     0, 0, CACHED_LCD
+#define BITMAP  CACHED_BITMAP, 0, 0, 0
+#define PIXMAP  0, CACHED_PIXMAP, 0, 0
+#define COLOR   0, 0, CACHED_COLOR, 0
+#define LCD     0, 0, 0, CACHED_LCD
 
 #define SUBPIX  CACHED_SUBPIX
 
-// BUILD_RENDER_LINE(NAME, IS_BLENDED, IS_BLENDED_OPAQUE, WANT_PIXMAP_COLOR_LCD, WANT_SUBPIXEL, BLIT_GLYPH_BLENDED_OPAQUE_OPTIM, BLIT_GLYPH_BLENDED_OPTIM, BLIT_GLYPH_OPTIM)
+// BUILD_RENDER_LINE(NAME, IS_BLENDED, IS_BLENDED_OPAQUE, WANT_BITMAP_PIXMAP_COLOR_LCD, WANT_SUBPIXEL, BLIT_GLYPH_BLENDED_OPAQUE_OPTIM, BLIT_GLYPH_BLENDED_OPTIM, BLIT_GLYPH_OPTIM)
 
 #if defined(HAVE_SSE2_INTRINSICS)
 BUILD_RENDER_LINE(SSE_Shaded            , 0, 0, 0, PIXMAP, 0     ,                       ,                , BG_SSE     )
 BUILD_RENDER_LINE(SSE_Blended           , 1, 0, 0,  COLOR, 0     ,                       , BG_Blended_SSE ,            )
 BUILD_RENDER_LINE(SSE_Blended_Opaque    , 1, 1, 0,  COLOR, 0     , BG_Blended_Opaque_SSE ,                ,            )
+BUILD_RENDER_LINE(SSE_Solid             , 0, 0, 0, BITMAP, 0     ,                       ,                , BG_SSE     )
 BUILD_RENDER_LINE(SSE_Shaded_SP         , 0, 0, 0, PIXMAP, SUBPIX,                       ,                , BG_SSE     )
 BUILD_RENDER_LINE(SSE_Blended_SP        , 1, 0, 0,  COLOR, SUBPIX,                       , BG_Blended_SSE ,            )
 BUILD_RENDER_LINE(SSE_Blended_Opaque_SP , 1, 1, 0,  COLOR, SUBPIX, BG_Blended_Opaque_SSE ,                ,            )
@@ -1293,6 +1298,7 @@ BUILD_RENDER_LINE(SSE_LCD_SP            , 0, 0, 1,    LCD, SUBPIX,
 BUILD_RENDER_LINE(NEON_Shaded           , 0, 0, 0, PIXMAP, 0     ,                       ,                , BG_NEON    )
 BUILD_RENDER_LINE(NEON_Blended          , 1, 0, 0,  COLOR, 0     ,                       , BG_Blended_NEON,            )
 BUILD_RENDER_LINE(NEON_Blended_Opaque   , 1, 1, 0,  COLOR, 0     , BG_Blended_Opaque_NEON,                ,            )
+BUILD_RENDER_LINE(NEON_Solid            , 0, 0, 0, BITMAP, 0     ,                       ,                , BG_NEON    )
 BUILD_RENDER_LINE(NEON_Shaded_SP        , 0, 0, 0, PIXMAP, SUBPIX,                       ,                , BG_NEON    )
 BUILD_RENDER_LINE(NEON_Blended_SP       , 1, 0, 0,  COLOR, SUBPIX,                       , BG_Blended_NEON,            )
 BUILD_RENDER_LINE(NEON_Blended_Opaque_SP, 1, 1, 0,  COLOR, SUBPIX, BG_Blended_Opaque_NEON,                ,            )
@@ -1304,6 +1310,7 @@ BUILD_RENDER_LINE(NEON_LCD_SP           , 0, 0, 1,    LCD, SUBPIX,
 BUILD_RENDER_LINE(64_Shaded             , 0, 0, 0, PIXMAP, 0     ,                       ,                , BG_64      )
 BUILD_RENDER_LINE(64_Blended            , 1, 0, 0,  COLOR, 0     ,                       , BG_Blended_32  ,            )
 BUILD_RENDER_LINE(64_Blended_Opaque     , 1, 1, 0,  COLOR, 0     , BG_Blended_Opaque_32  ,                ,            )
+BUILD_RENDER_LINE(64_Solid              , 0, 0, 0, BITMAP, 0     ,                       ,                , BG_64      )
 BUILD_RENDER_LINE(64_Shaded_SP          , 0, 0, 0, PIXMAP, SUBPIX,                       ,                , BG_64      )
 BUILD_RENDER_LINE(64_Blended_SP         , 1, 0, 0,  COLOR, SUBPIX,                       , BG_Blended_32  ,            )
 BUILD_RENDER_LINE(64_Blended_Opaque_SP  , 1, 1, 0,  COLOR, SUBPIX, BG_Blended_Opaque_32  ,                ,            )
@@ -1313,6 +1320,7 @@ BUILD_RENDER_LINE(64_LCD_SP             , 0, 0, 1,    LCD, SUBPIX,
 BUILD_RENDER_LINE(32_Shaded             , 0, 0, 0, PIXMAP, 0     ,                       ,                , BG_32      )
 BUILD_RENDER_LINE(32_Blended            , 1, 0, 0,  COLOR, 0     ,                       , BG_Blended_32  ,            )
 BUILD_RENDER_LINE(32_Blended_Opaque     , 1, 1, 0,  COLOR, 0     , BG_Blended_Opaque_32  ,                ,            )
+BUILD_RENDER_LINE(32_Solid              , 0, 0, 0, BITMAP, 0     ,                       ,                , BG_32      )
 BUILD_RENDER_LINE(32_Shaded_SP          , 0, 0, 0, PIXMAP, SUBPIX,                       ,                , BG_32      )
 BUILD_RENDER_LINE(32_Blended_SP         , 1, 0, 0,  COLOR, SUBPIX,                       , BG_Blended_32  ,            )
 BUILD_RENDER_LINE(32_Blended_Opaque_SP  , 1, 1, 0,  COLOR, SUBPIX, BG_Blended_Opaque_32  ,                ,            )
@@ -1322,6 +1330,7 @@ BUILD_RENDER_LINE(32_LCD_SP             , 0, 0, 1,    LCD, SUBPIX,
 BUILD_RENDER_LINE(8_Shaded              , 0, 0, 0, PIXMAP, 0     ,                       ,                , BG         )
 BUILD_RENDER_LINE(8_Blended             , 1, 0, 0,  COLOR, 0     ,                       , BG_Blended     ,            )
 BUILD_RENDER_LINE(8_Blended_Opaque      , 1, 1, 0,  COLOR, 0     , BG_Blended_Opaque     ,                ,            )
+BUILD_RENDER_LINE(8_Solid               , 0, 0, 0, BITMAP, 0     ,                       ,                , BG         )
 BUILD_RENDER_LINE(8_Shaded_SP           , 0, 0, 0, PIXMAP, SUBPIX,                       ,                , BG         )
 BUILD_RENDER_LINE(8_Blended_SP          , 1, 0, 0,  COLOR, SUBPIX,                       , BG_Blended     ,            )
 BUILD_RENDER_LINE(8_Blended_Opaque_SP   , 1, 1, 0,  COLOR, SUBPIX, BG_Blended_Opaque     ,                ,            )
@@ -1334,6 +1343,7 @@ BUILD_RENDER_LINE(8_LCD_SP              , 0, 0, 1,    LCD, SUBPIX,
 static int (*Render_Line_SDF_Shaded)(TTF_Font *font, SDL_Surface *textbuf, int xstart, int ystart, SDL_Color *fg) = NULL;
 BUILD_RENDER_LINE(SDF_Blended           , 1, 0, 0,  COLOR, 0     ,                       , BG_Blended_SDF ,            )
 BUILD_RENDER_LINE(SDF_Blended_Opaque    , 1, 1, 0,  COLOR, 0     , BG_Blended_Opaque_SDF ,                ,            )
+static int (*Render_Line_SDF_Solid)(TTF_Fon

(Patch may be truncated, please check the link at the top of this post.)