34. Drawing Text
Learn how to draw text in various styles using fonts.
34.1 Font Basics
- Fonts are managed by the
Font
class when drawing text on screen
34.1.1 Rendering Method
- Regular fonts can choose from 3 rendering methods:
- Bitmap method: Stores font character image data as bitmaps. Quality degrades when drawn larger than the base size. Suitable for drawing fonts at a fixed size or when using typefaces with complex glyphs
- SDF method: Stores font character image data as single-channel SDF (Signed Distance Field). Quality is maintained even when drawn larger than the base size. Can add shadow and outline effects. Has a side effect of slightly rounding character corners
- MSDF method: Stores font character image data as 3-channel MSDF (Multi-channel Signed Distance Field). Quality is maintained even when drawn larger than the base size. Can add shadow and outline effects
Rendering Method |
Quality |
Scaling Down |
Scaling Up |
Shadow |
Outline |
Runtime Load |
Bitmap method |
◎ |
〇 |
△ |
〇 (2 draws) |
× |
Low |
SDF method |
△ |
〇 |
〇 |
◎ |
◎ |
Medium |
MSDF method |
〇 |
◎ |
◎ |
〇 |
〇 |
High |
- If no rendering method is specified, bitmap method is used
- Some typefaces can only use the bitmap method
- The rendering method is specified when creating the font and cannot be changed later
34.1.2 Base Size
- Individual character image data is created internally by the engine and cached in memory
- The size of the cached character images is called the base size
- The base size is specified when creating the font and cannot be changed later
Rendering Method and Base Size
- When text is drawn at a different size than the base size, scaling is performed
- With bitmap method, when scaling up occurs, the character appearance becomes rough like when enlarging a low-resolution image
- Bitmap method is intended to draw at the same size as the base size
- With SDF/MSDF methods, quality is maintained even when drawing text scaled larger than the base size
- SDF/MSDF methods require a reasonably large base size
- For complex characters with small base sizes, quality may degrade and glyph shapes may collapse
- For SDF/MSDF methods, base size of
40
is recommended for alphanumeric characters and 48
for Japanese fonts
- However, large base sizes increase memory consumption and runtime character image cache creation time, so balance must be considered
Runtime Cost
- Character image data is created and cached as needed during runtime (see 34.27)
- When drawing many new character types that don't exist in the cache in a single frame, all that character image data must be created at once, increasing processing time for that frame
- Especially with SDF/MSDF methods, creating each character image takes time, potentially causing noticeable delays during runtime
- Using the preload feature in 34.28 to create necessary character image data in advance can reduce runtime delays
34.1.3 Typeface
- The font type such as "Meiryo" or "Arial" is called a typeface
- The typeface is specified when creating the font and cannot be changed later
- If no typeface is specified, the standard typeface (regular) bundled with Siv3D is used
34.1.4 Font Style
- Some typefaces can change styles like bold, italic, or bitmap fonts by specifying a font style
- Font style is specified when creating the font and cannot be changed later
- If no font style is specified, a regular font is created
34.1.5 Text Style
- SDF/MSDF method fonts can apply text styles during text drawing such as:
- Shadow: Adds shadows in any direction
- Outline: Adds outlines to characters
- Text style is specified during individual text drawing using the font
- If no text style is specified, drawing is done with normal style
34.1.6 Image Buffer Width
- Image buffer width is the margin width around characters when creating character image data
- By default,
2
is used
- For SDF/MSDF methods when creating large shadows or outlines, if the image buffer width is too small, shadows or outlines may be clipped
- Image buffer width is specified with
.setBufferThickness()
after font creation
- Large image buffer widths increase memory consumption and runtime character image cache creation time, so balance must be considered
34.1.7 Font Fallback
- A single typeface may not cover all necessary characters
- You can register a font of a different typeface as a fallback to cover characters that the main typeface cannot handle
- This is mainly used when text contains multiple languages or emoji
34.2 Font Creation and Drawing
Font Creation
- There are several ways to create fonts:
- 34.3, 34.4 Create from standard typeface
- 34.5 Create from font file
- 34.6 Create from font file installed on PC
- Font creation has a cost, so it's usually done before the main loop
- When creating in the main loop, control is needed to prevent creation every frame
Text Drawing
- Passing text to the
()
operator of a Font
object returns a DrawableText
object
- To actually draw text, use member functions of
DrawableText
:
- 34.10 Drawing with top-left coordinates
.draw()
- 34.11 Drawing with center coordinates
.drawAt()
- 34.12 Drawing with baseline
.drawBase()
- 34.13 Drawing with other coordinates
.draw(Args::...)
- 34.14 Drawing within a rectangle
.draw(rect)
font(U"Hello, Siv3D!").draw(40, Vec2{ 40, 40 });
34.3 Standard Typeface (1)
- Siv3D includes several standard typefaces
- If no typeface is specified when creating a font, the standard typeface (regular) is used
- Fonts can be created with 3 rendering methods:
- Bitmap method
- SDF method
- MSDF method
- If no method is specified when creating a font, bitmap method is used
Code |
Description |
Font font{ base_size }; |
Create bitmap method font with standard typeface (regular) |
Font font{ FontMethod::Bitmap, base_size }; |
Create bitmap method font with standard typeface (regular) |
Font font{ FontMethod::SDF, base_size }; |
Create SDF method font with standard typeface (regular) |
Font font{ FontMethod::MSDF, base_size }; |
Create MSDF method font with standard typeface (regular) |

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font fontBitmap{ 48 };
const Font fontSDF{ FontMethod::SDF, 48 };
const Font fontMSDF{ FontMethod::MSDF, 48 };
while (System::Update())
{
fontBitmap(U"Hello, Siv3D!").draw(Vec2{ 40, 100 }, ColorF{ 0.2 });
fontSDF(U"Hello, Siv3D!").draw(Vec2{ 40, 200 }, ColorF{ 0.2 });
fontMSDF(U"Hello, Siv3D!").draw(Vec2{ 40, 300 }, ColorF{ 0.2 });
}
}
34.4 Standard Typeface (2)
- Siv3D includes the following typefaces as standard:
- 7 types of Japanese typefaces with different weights
- CJK (Chinese, Korean, Japanese) typefaces for 5 regions
- Monochrome emoji typeface
- Color emoji typeface
- You can create fonts from standard typefaces by specifying
Typeface::
in the Font
constructor
Code |
Description |
Typeface::Thin |
Thin Japanese typeface |
Typeface::Light |
Light Japanese typeface |
Typeface::Regular |
Regular Japanese typeface |
Typeface::Medium |
Medium Japanese typeface |
Typeface::Bold |
Bold Japanese typeface |
Typeface::Heavy |
Heavy Japanese typeface |
Typeface::Black |
Black Japanese typeface |
Typeface::CJK_Regular_JP |
Japanese design CJK typeface |
Typeface::CJK_Regular_KR |
Korean design CJK typeface |
Typeface::CJK_Regular_SC |
Simplified Chinese design CJK typeface |
Typeface::CJK_Regular_TC |
Traditional Chinese (Taiwan) design CJK typeface |
Typeface::CJK_Regular_HK |
Traditional Chinese (Hong Kong) design CJK typeface |
Typeface::MonochromeEmoji |
Monochrome emoji typeface |
Typeface::ColorEmoji |
Color emoji typeface |

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font fontThin{ FontMethod::MSDF, 48, Typeface::Thin };
const Font fontLight{ FontMethod::MSDF, 48, Typeface::Light };
const Font fontRegular{ FontMethod::MSDF, 48, Typeface::Regular };
const Font fontMedium{ FontMethod::MSDF, 48, Typeface::Medium };
const Font fontBold{ FontMethod::MSDF, 48, Typeface::Bold };
const Font fontHeavy{ FontMethod::MSDF, 48, Typeface::Heavy };
const Font fontBlack{ FontMethod::MSDF, 48, Typeface::Black };
const Font fontJP{ FontMethod::MSDF, 48, Typeface::CJK_Regular_JP };
const Font fontKR{ FontMethod::MSDF, 48, Typeface::CJK_Regular_KR };
const Font fontSC{ FontMethod::MSDF, 48, Typeface::CJK_Regular_SC };
const Font fontTC{ FontMethod::MSDF, 48, Typeface::CJK_Regular_TC };
const Font fontHK{ FontMethod::MSDF, 48, Typeface::CJK_Regular_HK };
const Font fontMono{ FontMethod::MSDF, 48, Typeface::MonochromeEmoji };
// Color emoji fonts ignore method and base size
const Font fontEmoji{ FontMethod::MSDF, 48, Typeface::ColorEmoji };
const String s0 = U"Hello, Siv3D!";
const String s1 = U"こんにちは 你好 안녕하세요 骨曜喝愛遙扇";
const String s2 = U"🐈🐕🚀";
while (System::Update())
{
fontThin(s0).draw(36, Vec2{ 40, 20 }, ColorF{ 0.2 });
fontLight(s0).draw(36, Vec2{ 40, 60 }, ColorF{ 0.2 });
fontRegular(s0).draw(36, Vec2{ 40, 100 }, ColorF{ 0.2 });
fontMedium(s0).draw(36, Vec2{ 40, 140 }, ColorF{ 0.2 });
fontBold(s0).draw(36, Vec2{ 40, 180 }, ColorF{ 0.2 });
fontHeavy(s0).draw(36, Vec2{ 40, 220 }, ColorF{ 0.2 });
fontBlack(s0).draw(36, Vec2{ 40, 260 }, ColorF{ 0.2 });
fontJP(s1).draw(36, Vec2{ 40, 300 }, ColorF{ 0.2 });
fontKR(s1).draw(36, Vec2{ 40, 340 }, ColorF{ 0.2 });
fontSC(s1).draw(36, Vec2{ 40, 380 }, ColorF{ 0.2 });
fontTC(s1).draw(36, Vec2{ 40, 420 }, ColorF{ 0.2 });
fontHK(s1).draw(36, Vec2{ 40, 460 }, ColorF{ 0.2 });
fontMono(s2).draw(36, Vec2{ 340, 20 }, ColorF{ 0.2 });
fontEmoji(s2).draw(36, Vec2{ 500, 20 });
}
}
34.5 Creating from Font File
- To create a font from your own font file, specify the font file path in the
Font
constructor
- File paths should use relative paths based on the folder containing the executable (the
App
folder during development) or absolute paths
- For example,
U"example/font/RocknRoll/RocknRollOne-Regular.ttf"
refers to the RocknRollOne-Regular.ttf
file in the example/font/RocknRoll/
folder of the executable's folder (App
folder)

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
// Load and use RocknRollOne-Regular.ttf
const Font font{ FontMethod::MSDF, 48, U"example/font/RocknRoll/RocknRollOne-Regular.ttf" };
while (System::Update())
{
font(U"Hello, Siv3D!\nこんにちは!").draw(60, Vec2{ 40, 40 }, ColorF{ 0.2 });
}
}
34.6 Creating from Font File Installed on PC
- Fonts installed on PC are stored in different locations depending on the OS
- You can get the folder path with
FileSystem::GetFolderPath()
and construct an absolute path by joining it with the font filename
- The correspondence between arguments passed to
FileSystem::GetFolderPath()
and the paths obtained is as follows:
Argument |
Windows |
macOS |
Linux |
SpecialFolder::SystemFonts |
(OS):/WINDOWS/Fonts/ |
/System/Library/Fonts/ |
/usr/share/fonts/ |
SpecialFolder::LocalFonts |
(OS):/WINDOWS/Fonts/ |
/Library/Fonts/ |
/usr/local/share/fonts/ (if exists) |
SpecialFolder::UserFonts |
(OS):/WINDOWS/Fonts/ |
~/Library/Fonts/ |
/usr/local/share/fonts/ (if exists) |

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
# if SIV3D_PLATFORM(WINDOWS)
const FilePath path = (FileSystem::GetFolderPath(SpecialFolder::SystemFonts) + U"arial.ttf");
# elif SIV3D_PLATFORM(MACOS)
const FilePath path = (FileSystem::GetFolderPath(SpecialFolder::SystemFonts) + U"Helvetica.dfont");
# endif
Print << path;
const Font font{ FontMethod::MSDF, 48, path };
while (System::Update())
{
# if SIV3D_PLATFORM(WINDOWS)
font(U"Arial").draw(80, Vec2{ 40, 40 }, ColorF{ 0.2 });
# elif SIV3D_PLATFORM(MACOS)
font(U"Helvetica").draw(80, Vec2{ 40, 40 }, ColorF{ 0.2 });
# endif
}
}
34.7 Empty Font
- By default,
Font
type objects hold an empty font
- Using an empty font does not cause an error, but nothing is drawn
- Empty fonts also result when font file loading fails
- To check if a font is empty, use
if (font.isEmpty())
, if (font)
, or if (not font)

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
Font font1;
Print << font1.isEmpty();
// Assign a font
font1 = Font{ FontMethod::MSDF, 48 };
Print << font1.isEmpty();
// Specify a non-existent font file
const Font font2{ FontMethod::MSDF, 48, U"example/aaa.ttf" };
if (not font2)
{
Print << U"Failed to load the font file";
}
while (System::Update())
{
// Draw using empty font
font2(U"Arial").draw(80, Vec2{ 40, 40 }, ColorF{ 0.2 });
}
}
- Using a created font
font
, display text with specified size, position, and color using font(text).draw(size, pos, color);
- The text part of
font(text)
can contain not only strings but any number of Print
-able values (numbers, Point
, etc.)

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
while (System::Update())
{
font(U"Hello, Siv3D!").draw(60, Vec2{ 40, 40 }, ColorF{ 1.0 });
// Non-string values are formatted (converted to strings)
font(Cursor::Pos()).draw(60, Vec2{ 40, 200 }, ColorF{ 0.2 });
// Multiple values are formatted and concatenated
font(123, U"ABC").draw(40, Vec2{ 40, 360 }, Palette::Seagreen);
font(U"{}/{}/{}"_fmt(2025, 12, 31)).draw(40, Vec2{ 40, 420 }, Palette::Deepskyblue);
}
}
34.9 Line Breaks
- If the text contains newline characters
'\n'
, line breaks occur at those positions

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
while (System::Update())
{
font(U"Hello,\nSiv3D!\n\n!!").draw(60, Vec2{ 40, 40 }, ColorF{ 0.2 });
}
}
34.10 Drawing with Top-Left Coordinates
- To draw text by specifying the top-left coordinates, use
font(text).draw()
- This function returns the area where the text was drawn as a
RectF
Code |
Description |
.draw(x, y, color); |
Draw text from top-left coordinates (x, y) |
.draw(pos, color); |
Draw text from top-left coordinates pos |
.draw(fontSize, x, y, color); |
Draw text with font size fontSize from top-left coordinates (x, y) |
.draw(fontSize, pos, color); |
Draw text with font size fontSize from top-left coordinates pos |

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
while (System::Update())
{
font(U"Siv3D").draw(80, Vec2{ 0, 0 }, ColorF{ 0.2 });
font(U"Siv3D").draw(60, Vec2{ 200, 200 }, ColorF{ 0.2 });
font(U"Siv3D").draw(40, Cursor::Pos(), ColorF{0.2});
}
}
34.11 Drawing with Center Coordinates
- To draw text by specifying the center coordinates, use
font(text).drawAt()
- This function returns the area where the text was drawn as a
RectF
Code |
Description |
.drawAt(x, y, color); |
Draw text from center coordinates (x, y) |
.drawAt(pos, color); |
Draw text from center coordinates pos |
.drawAt(fontSize, x, y, color); |
Draw text with font size fontSize from center coordinates (x, y) |
.drawAt(fontSize, pos, color); |
Draw text with font size fontSize from center coordinates pos |

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
const Rect rect{ 100, 300, 280, 80 };
const Circle circle{ 600, 400, 80 };
while (System::Update())
{
font(U"Siv3D").drawAt(80, Vec2{ 400, 60 }, ColorF{ 0.2 });
rect.draw();
font(U"Siv3D").drawAt(60, rect.center(), ColorF{ 0.2 });
circle.draw();
font(U"Siv3D").drawAt(40, circle.center, ColorF{ 0.2 });
}
}
34.12 Drawing with Baseline
- To draw text by specifying the baseline start position, use
font(text).drawBase()
- When drawing text with different font sizes, baselines can be aligned
- This function returns the area where the text was drawn as a
RectF
Code |
Description |
.drawBase(x, y, color); |
Draw text from baseline start position (x, y) |
.drawBase(pos, color); |
Draw text from baseline start position pos |
.drawBase(fontSize, x, y, color); |
Draw text with font size fontSize from baseline start position (x, y) |
.drawBase(fontSize, pos, color); |
Draw text with font size fontSize from baseline start position pos |

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font1{ FontMethod::MSDF, 48, U"example/font/RocknRoll/RocknRollOne-Regular.ttf" };
const Font font2{ FontMethod::MSDF, 48, Typeface::Bold };
const String text = U"Hello, Siv3D!";
while (System::Update())
{
// Baselines don't align
font1(text).draw(30, Vec2{ 40, 100 }, ColorF{ 0.2 });
font2(text).draw(20, Vec2{ 280, 100 }, ColorF{ 0.2 });
font2(text).draw(50, Vec2{ 440, 100 }, ColorF{ 0.2 });
Rect{ 0, 400, 800, 10 }.draw(Palette::Skyblue);
// Draw text so that (40, 400) becomes the baseline start position
font1(text).drawBase(30, Vec2{ 40, 400 }, ColorF{ 0.2 });
Circle{ 40, 400 , 5 }.drawFrame(2, Palette::Red);
// Draw text so that (280, 400) becomes the baseline start position
font2(text).drawBase(20, Vec2{ 280, 400 }, ColorF{ 0.2 });
Circle{ 280, 400 , 5 }.drawFrame(2, Palette::Red);
// Draw text so that (440, 400) becomes the baseline start position
font2(text).drawBase(50, Vec2{ 440, 400 }, ColorF{ 0.2 });
Circle{ 440, 400 , 5 }.drawFrame(2, Palette::Red);
}
}
34.13 Drawing with Other Coordinate References
- To specify the right-center position and draw text aligned to it, use:
.draw(Arg::topRight = pos, ...)
.draw(Arg::topRight(x, y), ...)
- There are 9 types of reference positions that can be specified
- These functions return the area where the text was drawn as a
RectF
Reference Position |
Description |
Arg::topLeft |
Top-left. Same as .draw() |
Arg::topCenter |
Top-center |
Arg::topRight |
Top-right |
Arg::leftCenter |
Left-center |
Arg::center |
Center. Same as .drawAt() |
Arg::rightCenter |
Right-center |
Arg::bottomLeft |
Bottom-left |
Arg::bottomCenter |
Bottom-center |
Arg::bottomRight |
Bottom-right |

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
const Rect rect{ 100, 300, 280, 80 };
while (System::Update())
{
font(U"C++").draw(60, Arg::topCenter = Vec2{ 400, 20 }, ColorF{ 0.2 });
font(U"Hello, Siv3D!").draw(30, Arg::topRight(780, 20), ColorF{ 0.2 });
rect.draw();
// Draw text right-aligned within the rectangle
font(U"Siv3D").draw(32, Arg::rightCenter = rect.rightCenter().movedBy(-20, 0), ColorF{0.2});
}
}
34.14 Drawing Within a Rectangle
- To draw text so it fits within a specified rectangle, use
font(text).draw(rect)
- If all text characters fit within the rectangle, the function returns
true
- If text overflows, the overflowing part is replaced with "…" and the function returns
false
Code |
Description |
.draw(rect, color); |
Draw text to fit within rectangle rect |
.draw(fontSize, rect, color); |
Draw text with font size fontSize to fit within rectangle rect |

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
const String text = U"The quick brown fox jumps over the lazy dog.";
const Rect rect1{ 60, 40, 200, 100 };
const Rect rect2{ 60, 200, 300, 100 };
const Rect rect3{ 60, 360, 420, 120 };
while (System::Update())
{
{
rect1.draw();
const bool ok = font(text).draw(24, rect1.stretched(-10), ColorF{ 0.2 });
if (not ok)
{
rect1.drawFrame(8, ColorF{ 1.0, 0.0, 0.0, 0.5 });
}
}
{
rect2.draw();
const bool ok = font(text).draw(24, rect2.stretched(-10), ColorF{ 0.2 });
if (not ok)
{
rect2.drawFrame(8, ColorF{ 1.0, 0.0, 0.0, 0.5 });
}
}
{
rect3.draw();
const bool ok = font(text).draw(24, rect3.stretched(-20), ColorF{ 0.2 });
if (not ok)
{
rect3.drawFrame(8, ColorF{ 1.0, 0.0, 0.0, 0.5 });
}
}
}
}
34.15 Getting the Drawing Area
- To get the area that would be drawn without actually drawing, use the following member functions of
font(text)
:
Code |
Description |
.region(x, y); |
Return the area as RectF when drawing text from (x, y) |
.region(pos); |
Return the area as RectF when drawing text from pos |
.region(fontSize, x, y); |
Return the area as RectF when drawing text with font size fontSize from (x, y) |
.region(fontSize, pos); |
Return the area as RectF when drawing text with font size fontSize from pos |
.regionAt(x, y); |
Return the area as RectF when drawing text centered at (x, y) |
.regionAt(pos); |
Return the area as RectF when drawing text centered at pos |
.regionAt(fontSize, x, y); |
Return the area as RectF when drawing text with font size fontSize centered at (x, y) |
.regionAt(fontSize, pos); |
Return the area as RectF when drawing text with font size fontSize centered at pos |
.regionBase(x, y); |
Return the area as RectF when drawing text with (x, y) as baseline start position |
.regionBase(pos); |
Return the area as RectF when drawing text with pos as baseline start position |
.regionBase(fontSize, x, y); |
Return the area as RectF when drawing text with font size fontSize with (x, y) as baseline start position |
.regionBase(fontSize, pos); |
Return the area as RectF when drawing text with font size fontSize with pos as baseline start position |

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
const String text = U"Hello, Siv3D!";
const Vec2 pos{ 40, 40 };
// Get the text area when drawing text at pos position using font
const RectF rect = font(text).region(60, pos);
while (System::Update())
{
// Fill the drawing area rectangle in advance
rect.draw(Palette::Skyblue);
// Draw text on top of the rectangle
font(text).draw(60, pos, ColorF{ 0.2 });
// Text area
font(text)
.drawAt(80, Vec2{ 400, 300 }, ColorF{ 1.0 })
.stretched(40, 0) // Stretch horizontally
.shearedX(20) // Make parallelogram
.drawFrame(2); // Draw frame
}
}
34.16 Font Style (Bold/Italic)
- You can apply styles like bold and italic to fonts by specifying
FontStyle
in the Font
constructor
- If the typeface doesn't support them, bold and italic are simulated, which may cause glyph abnormalities in SDF/MSDF methods
Code |
Description |
FontStyle::Bold |
Bold |
FontStyle::Italic |
Italic |
FontStyle::BoldItalic |
Bold and italic |

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ 48, Typeface::CJK_Regular_JP };
const Font fontBold{ 48, Typeface::CJK_Regular_JP, FontStyle::Bold };
const Font fontItalic{ 48, Typeface::CJK_Regular_JP, FontStyle::Italic };
const Font fontBoldItalic{ 48, Typeface::CJK_Regular_JP, FontStyle::BoldItalic };
const String text = U"Hello, Siv3D! こんにちは。";
while (System::Update())
{
font(text).draw(48, Vec2{ 40, 40 }, ColorF{ 0.2 });
fontBold(text).draw(48, Vec2{ 40, 100 }, ColorF{ 0.2 });
fontItalic(text).draw(48, Vec2{ 40, 160 }, ColorF{ 0.2 });
fontBoldItalic(text).draw(48, Vec2{ 40, 220 }, ColorF{ 0.2 });
}
}
34.17 Font Style (Bitmap)
- If the typeface supports bitmap fonts, you can draw characters that preserve the pixel feel by specifying
FontStyle
in the Font
constructor
- Uses the bitmap rendering method
Code |
Description |
FontStyle::Bitmap |
Bitmap font |
FontStyle::BoldBitmap |
Bold bitmap font |
FontStyle::ItalicBitmap |
Italic bitmap font |
FontStyle::BoldItalicBitmap |
Bold and italic bitmap font |

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font1{ 32, U"example/font/DotGothic16/DotGothic16-Regular.ttf", FontStyle::Bitmap };
const Font font2{ 32, U"example/font/DotGothic16/DotGothic16-Regular.ttf", FontStyle::ItalicBitmap };
const Font font3{ 60, U"example/font/DotGothic16/DotGothic16-Regular.ttf", FontStyle::Bitmap };
const Font font4{ 60, U"example/font/DotGothic16/DotGothic16-Regular.ttf", FontStyle::ItalicBitmap };
# if SIV3D_PLATFORM(WINDOWS)
const FilePath path = (FileSystem::GetFolderPath(SpecialFolder::SystemFonts) + U"msgothic.ttc");
const Font font5{ 16, path, FontStyle::Bitmap };
# endif
const String text = U"こんにちは、Siv3D!";
while (System::Update())
{
font1(text).draw(32, Vec2{ 40, 40 }, ColorF{ 0.2 });
font2(text).draw(32, Vec2{ 40, 100 }, ColorF{ 0.2 });
font3(text).draw(60, Vec2{ 40, 160 }, ColorF{ 0.2 });
font4(text).draw(60, Vec2{ 40, 240 }, ColorF{ 0.2 });
# if SIV3D_PLATFORM(WINDOWS)
{
// Preserve pixel feel when scaling up
const ScopedRenderStates2D states{ SamplerState::ClampNearest };
font5(text).draw(64, Vec2{ 40, 360 }, ColorF{ 0.2 });
}
# endif
}
}
34.18 Adding Shadow to Text (Double Drawing)
- You can create a shadow effect by drawing text twice with offset coordinates

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
const Vec2 pos{ 40, 40 };
const String text = U"Hello, Siv3D!";
while (System::Update())
{
font(text).draw(100, pos.movedBy(4, 4), ColorF{ 0.2, 0.4, 0.3 });
font(text).draw(100, pos, ColorF{ 1.0 });
}
}
34.19 Adding Shadow to Text (Text Style)
- SDF/MSDF method fonts can add shadow effects by specifying
TextStyle::Shadow(shadow offset, shadow color)
during drawing
- The offset value is relative to the base size
- If the image buffer width is insufficient, large shadow offsets may cause shadows to be clipped

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font = Font{ FontMethod::MSDF, 48, Typeface::Bold }.setBufferThickness(4);
const String text = U"Hello, Siv3D!";
while (System::Update())
{
font(text).draw(TextStyle::Shadow(Vec2{ 2, 2 }, ColorF{ 0.2, 0.4, 0.3 }), 100, Vec2{ 40, 40 }, ColorF{ 1.0 });
}
}
34.20 Adding Outline to Text
- SDF/MSDF method fonts can add outline effects by specifying the following styles during drawing:
TextStyle::Outline(outline scale, outline color)
TextStyle::Outline(inner outline scale, outer outline scale, outline color)
- If the outline scale is too large, the drawing result will have noise
- The maximum is around 0.2-0.25 depending on the typeface

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font = Font{ FontMethod::MSDF, 48, Typeface::Bold }.setBufferThickness(4);
const String text = U"Hello, Siv3D!";
while (System::Update())
{
font(text).draw(TextStyle::Outline(0.2, ColorF{ 0.0 }), 100, Vec2{ 40, 40 }, ColorF{ 1.0 });
}
}
34.21 Adding Shadow and Outline to Text
- SDF/MSDF method fonts can add both shadow and outline effects by specifying the following styles during drawing:
TextStyle::OutlineShadow(outline scale, outline color, shadow offset, shadow color)
TextStyle::OutlineShadow(inner outline scale, outer outline scale, outline color, shadow offset, shadow color)
- If the outline scale is too large, the drawing result will have noise
- The maximum is around 0.2-0.25 depending on the typeface

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font = Font{ FontMethod::MSDF, 48, Typeface::Bold }.setBufferThickness(4);
const String text = U"Hello, Siv3D!";
while (System::Update())
{
font(text).draw(TextStyle::OutlineShadow(0.2, ColorF{ 0.0 }, Vec2{ 2, 2 }, ColorF{ 0.2, 0.4, 0.3 }), 100, Vec2{ 40, 40 }, ColorF{ 1.0 });
font(text).draw(TextStyle::OutlineShadow(0.15, ColorF{ 0.0 }, Vec2{ 1.0, 1.5 }, ColorF{ 0.0 }), 80, Vec2{ 40, 200 }, ColorF{ 1.0 });
}
}
34.22 (Reference) Text Style Preview
- This is a sample to preview text style effects for each method
- You can move and zoom the view with right-click and wheel

# include <Siv3D.hpp>
void Main()
{
Window::Resize(1280, 720);
// Base size: larger makes scaled drawing cleaner but increases runtime cost
const int32 baseSize = 70;
// Image buffer width: larger allows large shadow text styles but increases runtime cost
const int32 bufferThickness = 5;
// Bitmap method cannot use outline or shadow effects
const Font fontBitmap{ FontMethod::Bitmap, baseSize, U"example/font/RocknRoll/RocknRollOne-Regular.ttf" };
// SDF method
const Font fontSDF{ FontMethod::SDF, baseSize, U"example/font/RocknRoll/RocknRollOne-Regular.ttf" };
fontSDF.setBufferThickness(bufferThickness);
// MSDF method
const Font fontMSDF{ FontMethod::MSDF, baseSize, U"example/font/RocknRoll/RocknRollOne-Regular.ttf" };
fontMSDF.setBufferThickness(bufferThickness);
bool outline = false;
bool shadow = false;
double inner = 0.1, outer = 0.1;
Vec2 shadowOffset{ 2.0, 2.0 };
ColorF textColor{ 1.0 };
ColorF outlineColor{ 0.0 };
ColorF shadowColor{ 0.0, 0.5 };
HSV background = ColorF{ 0.6, 0.8, 0.7 };
Camera2D camera{ Vec2{ 640, 360 }, 1.0 };
while (System::Update())
{
Scene::SetBackground(background);
TextStyle textStyle;
{
if (outline && shadow)
{
textStyle = TextStyle::OutlineShadow(inner, outer, outlineColor, shadowOffset, shadowColor);
}
else if (outline)
{
textStyle = TextStyle::Outline(inner, outer, outlineColor);
}
else if (shadow)
{
textStyle = TextStyle::Shadow(shadowOffset, shadowColor);
}
}
camera.update();
{
auto t = camera.createTransformer();
fontBitmap(U"Siv3D, 渋三次元 (Bitmap)").draw(Vec2{ 100, 250 }, textColor);
fontSDF(U"Siv3D, 渋三次元 (SDF)").draw(textStyle, Vec2{ 100, 330 }, textColor);
fontMSDF(U"Siv3D, 渋三次元 (MSDF)").draw(textStyle, Vec2{ 100, 410 }, textColor);
}
SimpleGUI::CheckBox(outline, U"Outline", Vec2{ 20, 20 }, 130);
SimpleGUI::Slider(U"Inner: {:.2f}"_fmt(inner), inner, -0.5, 0.5, Vec2{ 160, 20 }, 120, 120, outline);
SimpleGUI::Slider(U"Outer: {:.2f}"_fmt(outer), outer, -0.5, 0.5, Vec2{ 160, 60 }, 120, 120, outline);
SimpleGUI::CheckBox(shadow, U"Shadow", Vec2{ 20, 100 }, 130);
SimpleGUI::Slider(U"offsetX: {:.1f}"_fmt(shadowOffset.x), shadowOffset.x, -5.0, 5.0, Vec2{ 160, 100 }, 120, 120, shadow);
SimpleGUI::Slider(U"offsetY: {:.1f}"_fmt(shadowOffset.y), shadowOffset.y, -5.0, 5.0, Vec2{ 160, 140 }, 120, 120, shadow);
SimpleGUI::Headline(U"Text", Vec2{ 420, 20 });
SimpleGUI::Slider(U"R", textColor.r, Vec2{ 420, 60 }, 20, 80);
SimpleGUI::Slider(U"G", textColor.g, Vec2{ 420, 100 }, 20, 80);
SimpleGUI::Slider(U"B", textColor.b, Vec2{ 420, 140 }, 20, 80);
SimpleGUI::Slider(U"A", textColor.a, Vec2{ 420, 180 }, 20, 80);
SimpleGUI::Headline(U"Outline", Vec2{ 540, 20 });
SimpleGUI::Slider(U"R", outlineColor.r, Vec2{ 540, 60 }, 20, 80, outline);
SimpleGUI::Slider(U"G", outlineColor.g, Vec2{ 540, 100 }, 20, 80, outline);
SimpleGUI::Slider(U"B", outlineColor.b, Vec2{ 540, 140 }, 20, 80, outline);
SimpleGUI::Slider(U"A", outlineColor.a, Vec2{ 540, 180 }, 20, 80, outline);
SimpleGUI::Headline(U"Shadow", Vec2{ 660, 20 });
SimpleGUI::Slider(U"R", shadowColor.r, Vec2{ 660, 60 }, 20, 80, shadow);
SimpleGUI::Slider(U"G", shadowColor.g, Vec2{ 660, 100 }, 20, 80, shadow);
SimpleGUI::Slider(U"B", shadowColor.b, Vec2{ 660, 140 }, 20, 80, shadow);
SimpleGUI::Slider(U"A", shadowColor.a, Vec2{ 660, 180 }, 20, 80, shadow);
SimpleGUI::ColorPicker(background, Vec2{ 780, 20 });
}
}
34.23 Drawing Text Character by Character
- You can create a substring from the beginning to
count
characters using the .substr(0, count)
member function of the String
class
- If
count
is larger than the actual string length, a substring up to the end is created
- See Tutorial 33.20
- By increasing
count
using a stopwatch or similar, you can display text character by character

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
const String text = U"The quick brown fox\njumps over the lazy dog.";
Stopwatch stopwatch{ StartImmediately::Yes };
while (System::Update())
{
const int32 count = (stopwatch.ms() / 30);
font(text.substr(0, count)).draw(40, Vec2{ 40, 40 }, ColorF{ 0.2 });
}
}
34.24 Free Drawing by Character
- Normal text drawing cannot control color, position, size, or rotation on a per-character basis
- For free per-character drawing, use
Array<Glyph>
obtained from the font's .getGlyphs(text)
Glyph
provides the information needed to freely control and draw individual characters
34.24.1 Basic Free Drawing (Bitmap Method)
Glyph
has the following members:
Code |
Description |
.codePoint |
UTF-32 code point of the character |
.texture |
Character image TextureRegion |
.getOffset(scale) |
Additional offset needed from pen position (with scale factor) |
.xAdvance |
X-coordinate distance to advance for current character |
- The following code uses
Glyph
information for free per-character drawing while reproducing normal text drawing:
# include <Siv3D.hpp>
void DrawGlyphs(const Font& font, const String& text, const double fontSize, const Vec2& basePos, const ColorF& color)
{
const Array<Glyph> glyphs = font.getGlyphs(text);
const double scale = (fontSize / font.fontSize());
const double fontHeight = (font.height() * scale);
Vec2 penPos{ basePos };
// Loop for per-character drawing control
for (const auto& glyph : glyphs)
{
// If newline character
if (glyph.codePoint == U'\n')
{
// Reset pen X coordinate
penPos.x = basePos.x;
// Advance pen Y coordinate by font height
penPos.y += fontHeight;
continue;
}
// Uncomment to visualize penPos
//penPos.asCircle(3).drawFrame(1, Palette::Red);
//(penPos + glyph.getOffset(scale)).asCircle(3).drawFrame(1, Palette::Green);
// Draw character texture at pen position plus character-specific offset
if (scale == 1.0)
{
// For bitmap method only at 1x scale, adjusting to integer coordinates with Math::Round() improves quality
glyph.texture.draw(Math::Round(penPos + glyph.getOffset()), color);
}
else
{
glyph.texture.scaled(scale).draw((penPos + glyph.getOffset(scale)), color);
}
// Advance pen X coordinate by character width
penPos.x += (glyph.xAdvance * scale);
}
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ 48, Typeface::Bold };
const String text = U"The quick brown fox\njumps over the lazy dog.";
while (System::Update())
{
DrawGlyphs(font, text, 48, Vec2{ 40, 40 }, ColorF{ 0.2 });
DrawGlyphs(font, text, 36, Vec2{ 40, 240 }, ColorF{ 1.0 });
DrawGlyphs(font, text, 24, Vec2{ 40, 440 }, Palette::Seagreen);
}
}
34.24.2 Basic Free Drawing (SDF/MSDF Method)
- SDF/MSDF methods require special shader application, so use code like this:
- Note that shape drawing is not available while the shader is applied
# include <Siv3D.hpp>
void DrawGlyphs(const Font& font, const String& text, const double fontSize, const Vec2& basePos, const ColorF& color)
{
const Array<Glyph> glyphs = font.getGlyphs(text);
const double scale = (fontSize / font.fontSize());
const double fontHeight = (font.height() * scale);
// While this object exists, SDF/MSDF shader is applied to all 2D drawing
const ScopedCustomShader2D shader{ Font::GetPixelShader(font.method()) };
Vec2 penPos{ basePos };
// Loop for per-character drawing control
for (const auto& glyph : glyphs)
{
// If newline character
if (glyph.codePoint == U'\n')
{
// Reset pen X coordinate
penPos.x = basePos.x;
// Advance pen Y coordinate by font height
penPos.y += fontHeight;
continue;
}
// Draw character texture at pen position plus character-specific offset
glyph.texture.scaled(scale).draw((penPos + glyph.getOffset(scale)), color);
// Advance pen X coordinate by character width
penPos.x += (glyph.xAdvance * scale);
}
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
const String text = U"The quick brown fox\njumps over the lazy dog.";
while (System::Update())
{
DrawGlyphs(font, text, 48, Vec2{ 40, 40 }, ColorF{ 0.2 });
DrawGlyphs(font, text, 36, Vec2{ 40, 240 }, ColorF{ 1.0 });
DrawGlyphs(font, text, 24, Vec2{ 40, 440 }, Palette::Seagreen);
}
}
34.24.3 Advanced Free Drawing
- Sample controlling coordinates and colors per character
# include <Siv3D.hpp>
void DrawGlyphs(const Font& font, const String& text, const double fontSize, const Vec2& basePos)
{
const Array<Glyph> glyphs = font.getGlyphs(text);
const double scale = (fontSize / font.fontSize());
const double fontHeight = (font.height() * scale);
const ScopedCustomShader2D shader{ Font::GetPixelShader(font.method()) };
Vec2 penPos{ basePos };
int32 index = 0;
for (const auto& glyph : glyphs)
{
if (glyph.codePoint == U'\n')
{
penPos.x = basePos.x;
penPos.y += fontHeight;
++index;
continue;
}
const Vec2 offset{ 0, (Periodic::Sine1_1(2s, (Scene::Time() + index * 0.3)) * 8.0) };
glyph.texture.scaled(scale).draw((penPos + glyph.getOffset(scale) + offset), HSV{ (index * 10) });
penPos.x += (glyph.xAdvance * scale);
++index;
}
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
const String text = U"The quick brown fox\njumps over the lazy dog.";
while (System::Update())
{
DrawGlyphs(font, text, 55, Vec2{ 40, 40 });
}
}
34.24.4 Text Style Support
- To support text styles in free drawing with SDF/MSDF method fonts, do this:
# include <Siv3D.hpp>
void DrawGlyphs(const Font& font, const TextStyle& textStyle, const String& text, const double fontSize, const Vec2& basePos)
{
const Array<Glyph> glyphs = font.getGlyphs(text);
const double scale = (fontSize / font.fontSize());
const double fontHeight = (font.height() * scale);
const ScopedCustomShader2D shader{ Font::GetPixelShader(font.method(), textStyle.type) };
Graphics2D::SetSDFParameters(textStyle);
Vec2 penPos{ basePos };
int32 index = 0;
for (const auto& glyph : glyphs)
{
if (glyph.codePoint == U'\n')
{
penPos.x = basePos.x;
penPos.y += fontHeight;
++index;
continue;
}
const Vec2 offset{ 0, (Periodic::Sine1_1(2s, (Scene::Time() + index * 0.3)) * 8.0) };
glyph.texture.scaled(scale).draw((penPos + glyph.getOffset(scale) + offset), HSV{ (index * 10) });
penPos.x += (glyph.xAdvance * scale);
++index;
}
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
const String text = U"The quick brown fox\njumps over the lazy dog.";
while (System::Update())
{
DrawGlyphs(font, TextStyle::Default(), text, 55, Vec2{ 40, 40 });
DrawGlyphs(font, TextStyle::OutlineShadow(0.2, ColorF{ 0.0 }, Vec2{ 2, 2 }, ColorF{ 0.0 }), text, 55, Vec2{ 40, 240 });
}
}
34.25 Vertical Writing
- Vertical text writing functionality is not yet implemented. It's planned for future versions
- You can reproduce it with free drawing as follows, but there's a limitation that quotes and punctuation don't become vertical-style

# include <Siv3D.hpp>
void DrawGlyphs(const Font& font, const String& text, const double fontSize, const Vec2& basePos, const ColorF& color)
{
const Array<Glyph> glyphs = font.getGlyphs(text);
const double scale = (fontSize / font.fontSize());
const double fontHeight = (font.height() * scale);
// While this object exists, SDF/MSDF shader is applied to all 2D drawing
const ScopedCustomShader2D shader{ Font::GetPixelShader(font.method()) };
Vec2 penPos{ basePos };
// Loop for per-character drawing control
for (const auto& glyph : glyphs)
{
// If newline character
if (glyph.codePoint == U'\n')
{
// Reset pen Y coordinate
penPos.y = basePos.y;
// Advance pen X coordinate
penPos.x -= fontHeight;
continue;
}
// Draw character texture at pen position plus character-specific offset
glyph.texture.scaled(scale).draw((penPos + glyph.getOffset(scale)), color);
// Advance pen Y coordinate by character height
penPos.y += (glyph.yAdvance * scale);
}
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
const String text = U"古池や\n蛙飛び込む\n水の音";
while (System::Update())
{
DrawGlyphs(font, text, 48, Vec2{ 600, 40 }, ColorF{ 0.2 });
DrawGlyphs(font, text, 36, Vec2{ 400, 40 }, ColorF{ 1.0 });
DrawGlyphs(font, text, 24, Vec2{ 200, 40 }, Palette::Seagreen);
}
}
34.26 Fallback Fonts
- A single typeface may not cover all characters that appear in text
- You can register a font of a different typeface as a fallback to draw characters that the main typeface can't cover with another typeface
- When a fallback font is set, if there's a character that can't be drawn with the base font but can be drawn with the fallback font, that font is used
- Set fallback fonts using
.addFallback()
to pass a created Font
- You can set any number of fallback fonts; earlier registered ones take priority
- When a color emoji font is set as a fallback font, the drawing size is adjusted to match the registered font's size
- Fallback fonts are mainly used when text contains emoji or multiple languages
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font0{ FontMethod::MSDF, 48, Typeface::Regular };
const Font font1{ FontMethod::MSDF, 48, Typeface::Regular };
const Font font2{ FontMethod::MSDF, 48, Typeface::Regular };
const Font fontCJK{ FontMethod::MSDF, 48, Typeface::CJK_Regular_JP };
const Font fontEmoji{ 48, Typeface::ColorEmoji };
// Add one fallback font to font1
font1.addFallback(fontCJK);
// Add two fallback fonts to font2
font2.addFallback(fontCJK);
font2.addFallback(fontEmoji);
const String text = U"Hello! こんにちは 你好 안녕하세요 🐈🐕🚀";
while (System::Update())
{
font0(U"font0:\n" + text).draw(36, Vec2{40, 40}, ColorF{ 0.2 });
font1(U"font1:\n" + text).draw(36, Vec2{ 40, 200 }, ColorF{ 0.2 });
font2(U"font2:\n" + text).draw(36, Vec2{ 40, 360 }, ColorF{ 0.2 });
}
}
34.27 Accessing Font Cache
- Fonts render and cache character image data when drawing characters for the first time
- You can get the font cache as a
Texture
using .getTexture()
to check its contents
- Bitmap method uses white + alpha channel images, while SDF/MSDF methods use Distance field format images
- Running the following sample shows characters being added to the font cache over time

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ 24, Typeface::Bold };
const String text = U"Siv3D(シブスリーディー)は、音や画像、AI を使ったゲームやアプリを、モダンな C++ コードで楽しく簡単に開発できるオープンソースのフレームワークです。豊富なサンプルコードとチュートリアルが用意され、オンラインのユーザコミュニティで気軽に質問や相談ができます。";
Stopwatch stopwatch{ StartImmediately::Yes };
while (System::Update())
{
const int32 count = (stopwatch.ms() / 50);
font(text.substr(0, count)).draw(Rect{ 20, 20, 760, 240 }, Palette::Seagreen);
Rect{ 20, 300, font.getTexture().size() }.draw(ColorF{ 0.0 });
font.getTexture().draw(20, 300);
}
}
34.28 Font Preloading
- When displaying large amounts of text for the first time during real-time games, many characters need to be rendered and cached at once
- This causes frame time spikes (only that frame takes extremely long), which can affect gameplay experience
- Using
.preload(text)
you can pre-render and cache characters contained in text
- Performing preloading during game startup or loading screens can prevent frame time spikes during gameplay
- The
String
member function .sorted_and_uniqued()
returns a string with characters sorted and duplicates removed. Applying this preprocessing to preload strings reduces preloading load
- The following sample preloads all characters at startup

# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ 24, Typeface::Bold };
const String text = U"Siv3D(シブスリーディー)は、音や画像、AI を使ったゲームやアプリを、モダンな C++ コードで楽しく簡単に開発できるオープンソースのフレームワークです。豊富なサンプルコードとチュートリアルが用意され、オンラインのユーザコミュニティで気軽に質問や相談ができます。";
// Removing duplicates with .sorted_and_uniqued() reduces preload load
font.preload(text.sorted_and_uniqued());
Stopwatch stopwatch{ StartImmediately::Yes };
while (System::Update())
{
const int32 count = (stopwatch.ms() / 50);
font(text.substr(0, count)).draw(Rect{ 20, 20, 760, 240 }, Palette::Seagreen);
Rect{ 20, 300, font.getTexture().size() }.draw(ColorF{ 0.0 });
font.getTexture().draw(20, 300);
}
}
34.29 Getting Characters as Polygons
- You can get and draw characters as
Polygon
format instead of image format
- This can be used for vertex-level processing or effects using character shapes
- Using the
Font
member function .renderPolygons()
you can get PolygonGlyph
for each character when drawing a string
- The rendering method doesn't affect this function
- Larger font base sizes increase polygon vertex count (giving higher quality polygons)

# include <Siv3D.hpp>
// Function returning Polygon for each character when drawing a string
Array<Polygon> ToPolygons(const Vec2& basePos, const Array<PolygonGlyph>& glyphs)
{
Array<Polygon> polygons;
Vec2 penPos{ basePos };
for (const auto& glyph : glyphs)
{
for (const auto& polygon : glyph.polygons)
{
polygons << polygon.movedBy(penPos + glyph.getOffset());
}
penPos.x += glyph.xAdvance;
}
return polygons;
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ 80, Typeface::Bold };
const String text = U"こんにちは、Siv3D!";
const Array<Polygon> polygons = ToPolygons(Vec2{ 20, 20 }, font.renderPolygons(text));
while (System::Update())
{
for (size_t i = 0; i < polygons.size(); ++i)
{
polygons[i].draw(HSV{ (i * 50) });
polygons[i].drawWireframe(1, ColorF{ 0.2, Periodic::Square0_1(2s) });
}
}
}
34.30 Getting Characters as LineStrings
- You can get and draw characters as
LineString
format
- This can be used for outline processing or effects using character shapes
- Using the
Font
member function .renderOutlines()
you can get OutlineGlyph
for each character when drawing a string
- The rendering method doesn't affect this function
- Larger font base sizes increase vertex count (giving higher quality line segments)

# include <Siv3D.hpp>
// Function returning LineString for each character when drawing a string
Array<LineString> ToLineStrings(const Vec2& basePos, const Array<OutlineGlyph>& glyphs)
{
Array<LineString> lines;
Vec2 penPos{ basePos };
for (const auto& glyph : glyphs)
{
for (const auto& ring : glyph.rings)
{
lines << ring.movedBy(penPos + glyph.getOffset());
}
penPos.x += glyph.xAdvance;
}
return lines;
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ 80, Typeface::Bold };
const String text = U"こんにちは、Siv3D!";
const Array<LineString> lines = ToLineStrings(Vec2{ 20, 20 }, font.renderOutlines(text));
while (System::Update())
{
for (size_t i = 0; i < lines.size(); ++i)
{
lines[i].drawClosed(2, HSV{ (i * 50) });
}
}
}