LearnOpenGL

Translation in progress of learnopengl.com.
git clone https://git.mtkn.jp/LearnOpenGL
Log | Files | Refs

Text-Rendering.html (36806B)


      1 <!DOCTYPE html>
      2 <html lang="ja"> 
      3 <head>
      4     <meta charset="utf-8"/>
      5     <title>LearnOpenGL</title>
      6     <link rel="shortcut icon" type="image/ico" href="/favicon.ico"  />
      7 	<link rel="stylesheet" href="../static/style.css" />
      8 	<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"> </script>
      9 	<script src="/static/functions.js"></script>
     10 </head>
     11 <body>
     12 	<nav>
     13 <ol>
     14 	<li id="Introduction">
     15 		<a href="https://learnopengl.com/Introduction">はじめに</a>
     16 	</li>
     17 	<li id="Getting-started">
     18 		<span class="closed">入門</span>
     19 		<ol>
     20 			<li id="Getting-started/OpenGL">
     21 				<a href="https://learnopengl.com/Getting-started/OpenGL">OpenGL </a>
     22 			</li>
     23 			<li id="Getting-started/Creating-a-window">
     24 				<a href="https://learnopengl.com/Getting-started/Creating-a-window">ウィンドウの作成</a>
     25 			</li>
     26 			<li id="Getting-started/Hello-Window">
     27 				<a href="https://learnopengl.com/Getting-started/Hello-Window">最初のウィンドウ</a>
     28 			</li>
     29 			<li id="Getting-started/Hello-Triangle">
     30 				<a href="https://learnopengl.com/Getting-started/Hello-Triangle">最初の三角形</a>
     31 			</li>
     32 			<li id="Getting-started/Shaders">
     33 				<a href="https://learnopengl.com/Getting-started/Shaders">シェーダー</a>
     34 			</li>
     35 			<li id="Getting-started/Textures">
     36 				<a href="https://learnopengl.com/Getting-started/Textures">テクスチャ</a>
     37 			</li>
     38 			<li id="Getting-started/Transformations">
     39 				<a href="https://learnopengl.com/Getting-started/Transformations">座標変換</a>
     40 			</li>
     41 			<li id="Getting-started/Coordinate-Systems">
     42 				<a href="https://learnopengl.com/Getting-started/Coordinate-Systems">座標系</a>
     43 			</li>
     44 			<li id="Getting-started/Camera">
     45 				<a href="https://learnopengl.com/Getting-started/Camera">カメラ</a>
     46 			</li>
     47 			<li id="Getting-started/Review">
     48 				<a href="https://learnopengl.com/Getting-started/Review">まとめ</a>
     49 			</li>
     50 		</ol>
     51 	</li>
     52 	<li id="Lighting">
     53 		<span class="closed">Lighting </span>
     54 		<ol>
     55 			<li id="Lighting/Colors">
     56 				<a href="https://learnopengl.com/Lighting/Colors">Colors </a>
     57 			</li>
     58 			<li id="Lighting/Basic-Lighting">
     59 				<a href="https://learnopengl.com/Lighting/Basic-Lighting">Basic Lighting </a>
     60 			</li>
     61 			<li id="Lighting/Materials">
     62 				<a href="https://learnopengl.com/Lighting/Materials">Materials </a>
     63 			</li>
     64 			<li id="Lighting/Lighting-maps">
     65 				<a href="https://learnopengl.com/Lighting/Lighting-maps">Lighting maps </a>
     66 			</li>
     67 			<li id="Lighting/Light-casters">
     68 				<a href="https://learnopengl.com/Lighting/Light-casters">Light casters </a>
     69 			</li>
     70 			<li id="Lighting/Multiple-lights">
     71 				<a href="https://learnopengl.com/Lighting/Multiple-lights">Multiple lights </a>
     72 			</li>
     73 			<li id="Lighting/Review">
     74 				<a href="https://learnopengl.com/Lighting/Review">Review </a>
     75 			</li>
     76 		</ol>
     77 	</li>
     78 	<li id="Model-Loading">
     79 		<span class="closed">Model Loading </span>
     80 		<ol>
     81 			<li id="Model-Loading/Assimp">
     82 				<a href="https://learnopengl.com/Model-Loading/Assimp">Assimp </a>
     83 			</li>
     84 			<li id="Model-Loading/Mesh">
     85 				<a href="https://learnopengl.com/Model-Loading/Mesh">Mesh </a>
     86 			</li>
     87 			<li id="Model-Loading/Model">
     88 				<a href="https://learnopengl.com/Model-Loading/Model">Model </a>
     89 			</li>
     90 		</ol>
     91 	</li>
     92 	<li id="Advanced-OpenGL">
     93 		<span class="closed">Advanced OpenGL </span>
     94 		<ol>
     95 			<li id="Advanced-OpenGL/Depth-testing">
     96 				<a href="https://learnopengl.com/Advanced-OpenGL/Depth-testing">Depth testing </a>
     97 			</li>
     98 			<li id="Advanced-OpenGL/Stencil-testing">
     99 				<a href="https://learnopengl.com/Advanced-OpenGL/Stencil-testing">Stencil testing </a>
    100 			</li>
    101 			<li id="Advanced-OpenGL/Blending">
    102 				<a href="https://learnopengl.com/Advanced-OpenGL/Blending">Blending </a>
    103 			</li>
    104 			<li id="Advanced-OpenGL/Face-culling">
    105 				<a href="https://learnopengl.cm/Advanced-OpenGL/Face-culling">Face culling </a>
    106 			</li>
    107 			<li id="Advanced-OpenGL/Framebuffers">
    108 				<a href="https://learnopengl.com/Advanced-OpenGL/Framebuffers">Framebuffers </a>
    109 			</li>
    110 			<li id="Advanced-OpenGL/Cubemaps">
    111 				<a href="https://learnopengl.com/Advanced-OpenGL/Cubemaps">Cubemaps </a>
    112 			</li>
    113 			<li id="Advanced-OpenGL/Advanced-Data">
    114 				<a href="https://learnopengl.com/Advanced-OpenGL/Advanced-Data">Advanced Data </a>
    115 			</li>
    116 			<li id="Advanced-OpenGL/Advanced-GLSL">
    117 				<a href="https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL">Advanced GLSL </a>
    118 			</li>
    119 			<li id="Advanced-OpenGL/Geometry-Shader">
    120 				<a href="https://learnopengl.com/Advanced-OpenGL/Geometry-Shader">Geometry Shader </a>
    121 			</li>
    122 			<li id="Advanced-OpenGL/Instancing">
    123 				<a href="https://learnopengl.com/Advanced-OpenGL/Instancing">Instancing </a>
    124 			</li>
    125 			<li id="Advanced-OpenGL/Anti-Aliasing">
    126 				<a href="https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing">Anti Aliasing </a>
    127 			</li>
    128 		</ol>
    129 	</li>
    130 	<li id="Advanced-Lighting">
    131 		<span class="closed">Advanced Lighting </span>
    132 		<ol>
    133 			<li id="Advanced-Lighting/Advanced-Lighting">
    134 				<a href="https://learnopengl.com/Advanced-Lighting/Advanced-Lighting">Advanced Lighting </a>
    135 			</li>
    136 			<li id="Advanced-Lighting/Gamma-Correction">
    137 				<a href="https://learnopengl.com/Advanced-Lighting/Gamma-Correction">Gamma Correction </a>
    138 			</li>
    139 			<li id="Advanced-Lighting/Shadows">
    140 				<span class="closed">Shadows </span>
    141 				<ol>
    142 					<li id="Advanced-Lighting/Shadows/Shadow-Mapping">
    143 						<a href="https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping">Shadow Mapping </a>
    144 					</li>
    145 					<li id="Advanced-Lighting/Shadows/Point-Shadows">
    146 						<a href="https://learnopengl.com/Advanced-Lighting/Shadows/Point-Shadows">Point Shadows </a>
    147 					</li>
    148 				</ol>
    149 			</li>
    150 			<li id="Advanced-Lighting/Normal-Mapping">
    151 				<a href="https://learnopengl.com/Advanced-Lighting/Normal-Mapping">Normal Mapping </a>
    152 			</li>
    153 			<li id="Advanced-Lighting/Parallax-Mapping">
    154 				<a href="https://learnopengl.com/Advanced-Lighting/Parallax-Mapping">Parallax Mapping </a>
    155 			</li>
    156 			<li id="Advanced-Lighting/HDR">
    157 				<a href="https://learnopengl.com/Advanced-Lighting/HDR">HDR </a>
    158 			</li>
    159 			<li id="Advanced-Lighting/Bloom">
    160 				<a href="https://learnopengl.com/Advanced-Lighting/Bloom">Bloom </a>
    161 			</li>
    162 			<li id="Advanced-Lighting/Deferred-Shading">
    163 				<a href="https://learnopengl.com/Advanced-Lighting/Deferred-Shading">Deferred Shading </a>
    164 			</li>
    165 			<li id="Advanced-Lighting/SSAO">
    166 				<a href="https://learnopengl.com/Advanced-Lighting/SSAO">SSAO </a>
    167 			</li>
    168 		</ol>
    169 	</li>
    170 	<li id="PBR">
    171 		<span class="closed">PBR </span>
    172 		<ol>
    173 			<li id="PBR/Theory">
    174 				<a href="https://learnopengl.com/PBR/Theory">Theory </a>
    175 			</li>
    176 			<li id="PBR/Lighting">
    177 				<a href="https://learnopengl.com/PBR/Lighting">Lighting </a>
    178 			</li>
    179 			<li id="PBR/IBL">
    180 				<span class="closed">IBL </span>
    181 				<ol>
    182 					<li id="PBR/IBL/Diffuse-irradiance">
    183 						<a href="https://learnopengl.com/PBR/IBL/Diffuse-irradiance">Diffuse irradiance </a>
    184 					</li>
    185 					<li id="PBR/IBL/Specular-IBL">
    186 						<a href="https://learnopengl.com/PBR/IBL/Specular-IBL">Specular IBL </a>
    187 					</li>
    188 				</ol>
    189 			</li>
    190 		</ol>
    191 	</li>
    192 	<li id="In-Practice">
    193 		<span class="closed">In Practice </span>
    194 		<ol>
    195 			<li id="In-Practice/Debugging">
    196 				<a href="https://learnopengl.com/In-Practice/Debugging">Debugging </a>
    197 			</li>
    198 			<li id="In-Practice/Text-Rendering">
    199 				<a href="https://learnopengl.com/In-Practice/Text-Rendering">Text Rendering </a>
    200 			</li>
    201 			<li id="In-Practice/2D-Game">
    202 				<span class="closed">2D Game </span>
    203 				<ol>
    204 					<li id="In-Practice/2D-Game/Breakout">
    205 						<a href="https://learnopengl.com/In-Practice/2D-Game/Breakout">Breakout </a>
    206 					</li>
    207 					<li id="In-Practice/2D-Game/Setting-up">
    208 						<a href="https://learnopengl.com/In-Practice/2D-Game/Setting-up">Setting up </a>
    209 					</li>
    210 					<li id="In-Practice/2D-Game/Rendering-Sprites">
    211 						<a href="https://learnopengl.com/In-Practice/2D-Game/Rendering-Sprites">Rendering Sprites </a>
    212 					</li>
    213 					<li id="In-Practice/2D-Game/Levels">
    214 						<a href="https://learnopengl.com/In-Practice/2D-Game/Levels">Levels </a>
    215 					</li>
    216 					<li id="In-Practice/2D-Game/Collisions">
    217 						<span class="closed">Collisions </span>
    218 						<ol>
    219 							<li id="In-Practice/2D-Game/Collisions/Ball">
    220 								<a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Ball">Ball </a>
    221 							</li>
    222 							<li id="In-Practice/2D-Game/Collisions/Collision-detection">
    223 								<a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Collision-detection">Collision detection </a>
    224 							</li>
    225 							<li id="In-Practice/2D-Game/Collisions/Collision-resolution">
    226 								<a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Collision-resolution">Collision resolution </a>
    227 							</li>
    228 						</ol>
    229 					</li>
    230 					<li id="In-Practice/2D-Game/Particles">
    231 						<a href="https://learnopengl.com/In-Practice/2D-Game/Particles">Particles </a>
    232 					</li>
    233 					<li id="In-Practice/2D-Game/Postprocessing">
    234 						<a href="https://learnopengl.com/In-Practice/2D-Game/Postprocessing">Postprocessing </a>
    235 					</li>
    236 					<li id="In-Practice/2D-Game/Powerups">
    237 						<a href="https://learnopengl.com/In-Practice/2D-Game/Powerups">Powerups </a>
    238 					</li>
    239 					<li id="In-Practice/2D-Game/Audio">
    240 						<a href="https://learnopengl.com/In-Practice/2D-Game/Audio">Audio </a>
    241 					</li>
    242 					<li id="In-Practice/2D-Game/Render-text">
    243 						<a href="https://learnopengl.com/In-Practice/2D-Game/Render-text">Render text </a>
    244 					</li>
    245 					<li id="In-Practice/2D-Game/Final-thoughts">
    246 						<a href="https://learnopengl.com/In-Practice/2D-Game/Final-thoughts">Final thoughts </a>
    247 					</li>
    248 				</ol>
    249 			</li>
    250 		</ol>
    251 	</li>
    252 	<li id="Guest-Articles">
    253 		<span class="closed">Guest Articles </span>
    254 		<ol>
    255 			<li id="Guest-Articles/How-to-publish">
    256 				<a href="https://learnopengl.com/Guest-Articles/How-to-publish">How to publish </a>
    257 			</li>
    258 			<li id="Guest-Articles/2020">
    259 				<span class="closed">2020 </span>
    260 				<ol>
    261 					<li id="Guest-Articles/2020/OIT">
    262 						<span class="closed">OIT </span>
    263 						<ol>
    264 							<li id="Guest-Articles/2020/OIT/Introduction">
    265 								<a href="https://learnopengl.com/Guest-Articles/2020/OIT/Introduction">Introduction </a>
    266 							</li>
    267 							<li id="Guest-Articles/2020/OIT/Weighted-Blended">
    268 								<a href="https://learnopengl.com/Guest-Articles/2020/OIT/Weighted-Blended">Weighted Blended </a>
    269 							</li>
    270 						</ol>
    271 					</li>
    272 					<li id="Guest-Articles/2020/Skeletal-Animation">
    273 						<a href="https://learnopengl.com/Guest-Articles/2020/Skeletal-Animation">Skeletal Animation </a>
    274 					</li>
    275 				</ol>
    276 			</li>
    277 			<li id="Guest-Articles/2021">
    278 				<span class="closed">2021 </span>
    279 				<ol>
    280 					<li id="Guest-Articles/2021/CSM">
    281 						<a href="https://learnopengl.com/Guest-Articles/2021/CSM">CSM </a>
    282 					</li>
    283 					<li id="Guest-Articles/2021/Scene">
    284 						<span class="closed">Scene </span>
    285 						<ol>
    286 							<li id="Guest-Articles/2021/Scene/Scene-Graph">
    287 								<a href="https://learnopengl.com/Guest-Articles/2021/Scene/Scene-Graph">Scene Graph </a>
    288 							</li>
    289 							<li id="Guest-Articles/2021/Scene/Frustum-Culling">
    290 								<a href="https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling">Frustum Culling </a>
    291 							</li>
    292 						</ol>
    293 					</li>
    294 					<li id="Guest-Articles/2021/Tessellation">
    295 						<span class="closed">Tessellation </span>
    296 						<ol>
    297 							<li id="Guest-Articles/2021/Tessellation/Height-map">
    298 								<a href="https://learnopengl.com/Guest-Articles/2021/Tessellation/Height-map">Height map </a>
    299 							</li>
    300 						</ol>
    301 					</li>
    302 				</ol>
    303 			</li>
    304 		</ol>
    305 	</li>
    306 	<li id="Code-repository">
    307 		<a href="https://learnopengl.com/Code-repository">Code repository </a>
    308 	</li>
    309 	<li id="Translations">
    310 		<a href="https://learnopengl.com/Translations">Translations </a>
    311 	</li>
    312 	<li id="About">
    313 		<a href="https://learnopengl.com/About">About </a>
    314 	</li>
    315 </ol>
    316 	</nav>
    317 	<main>
    318     <h1 id="content-title">Text Rendering</h1>
    319 <h1 id="content-url" style='display:none;'>In-Practice/Text-Rendering</h1>
    320 <p>
    321   At some stage of your graphics adventures you will want to draw text in OpenGL. Contrary to what you may expect, getting a simple string to render on screen is all but easy with a low-level API like OpenGL. If you don't care about rendering more than 128 different same-sized characters, then it's probably not too difficult. Things are getting difficult as soon as each character has a different width, height, and margin. Based on where you live, you may also need more than 128 characters, and what if you want to express special symbols for like mathematical expressions or sheet music symbols, and what about rendering text from top to bottom? Once you think about all these complicated matters of text, it wouldn't surprise you that this probably doesn't belong in a low-level API like OpenGL.
    322 </p>
    323 
    324 <p>
    325   Since there is no support for text capabilities within OpenGL, it is up to us to define a system for rendering text to the screen. There are no graphical primitives for text characters, we have to get creative. Some example techniques are: drawing letter shapes via <var>GL_LINES</var>, create 3D meshes of letters, or render character textures to 2D quads in a 3D environment.
    326 </p>
    327 
    328 <p>
    329   Most developers choose to render character textures onto quads. Rendering textured quads by itself shouldn't be too difficult, but getting the relevant character(s) onto a texture could prove challenging. In this chapter we'll explore several methods and implement a more advanced, but flexible technique for rendering text using the FreeType library.
    330 </p>
    331 
    332 <h2>Classical text rendering: bitmap fonts</h2>
    333 <p>
    334   In the early days, rendering text involved selecting a font (or create one yourself) you'd like for your application and extracting all relevant characters out of this font to place them within a single large texture. Such a texture, that we call a <def>bitmap font</def>, contains all character symbols we want to use in predefined regions of the texture. These character symbols of the font are known as <def>glyphs</def>. Each glyph has a specific region of texture coordinates associated with them. Whenever you want to render a character, you  select the corresponding glyph by rendering this section of the bitmap font to a 2D quad.
    335 </p>
    336 
    337 <img src="/img/in-practice/bitmapfont.png" alt="Sprite sheet of characters"/>
    338 
    339 <p>
    340   Here you can see how we would render the text 'OpenGL' by taking a bitmap font and sampling the corresponding glyphs from the texture (carefully choosing the texture coordinates) that we render on top of several quads. By enabling <a href="https://learnopengl.com/Advanced-OpenGL/Blending" target="_blank">blending</a> and keeping the background transparent, we will end up with just a string of characters rendered to the screen. This particular bitmap font was generated using Codehead's Bitmap <a href="http://www.codehead.co.uk/cbfg/" target="_blank">Font Generator</a>.
    341 </p>
    342   
    343 <p>
    344   This approach has several advantages and disadvantages. It is relatively easy to implement and because bitmap fonts are pre-rasterized, they're quite efficient. However, it is not particularly flexible. When you want to use a different font, you need to recompile a complete new bitmap font and the system is limited to a single resolution; zooming will quickly show pixelated edges. Furthermore, it is limited to a small character set, so Extended or Unicode characters are often out of the question.
    345 </p>
    346   
    347 <p>
    348   This approach was quite popular back in the day (and still is) since it is fast and works on any platform, but as of today more flexible approaches exist. One of these approaches is loading TrueType fonts using the FreeType library.
    349 </p>
    350   
    351 <h2>Modern text rendering: FreeType</h2>
    352 <p>
    353   FreeType is a software development library that is able to load fonts, render them to bitmaps, and provide support for several font-related operations. It is a popular library used by Mac OS X, Java, PlayStation, Linux, and Android to name a few. What makes FreeType particularly attractive is that it is able to load TrueType fonts.
    354 </p>
    355   
    356 <p>
    357   A TrueType font is a collection of character glyphs not defined by pixels or any other non-scalable solution, but by mathematical equations (combinations of splines). Similar to vector images, the rasterized font images can be procedurally generated based on the preferred font height you'd like to obtain them in. By using TrueType fonts you can easily render character glyphs of various sizes without any loss of quality.
    358 </p>
    359   
    360 <p>
    361   FreeType can be downloaded from their <a href="http://www.freetype.org/" target="_blank">website</a>. You can choose to compile the library yourself or use one of their precompiled libraries if your target platform is listed. Be sure to link to <code>freetype.lib</code> and make sure your compiler knows where to find the header files.
    362   </p>
    363   
    364 <p>
    365   Then include the appropriate headers:
    366 </p>
    367   
    368 <pre><code>
    369 #include &lt;ft2build.h&gt;
    370 #include FT_FREETYPE_H  
    371 </code></pre>
    372   
    373 <warning>
    374   Due to how FreeType is developed (at least at the time of this writing), you cannot put their header files in a new directory; they should be located at the root of your include directories. Including FreeType like <code>#include &lt;FreeType/ft2build.h&gt;</code> will likely cause several header conflicts.
    375 </warning>
    376   
    377 <p>
    378   FreeType loads these TrueType fonts and, for each glyph, generates a bitmap image and calculates several metrics. We can extract these bitmap images for generating textures and position each character glyph appropriately using the loaded metrics.
    379 </p>
    380   
    381 <p>
    382   To load a font, all we have to do is initialize the FreeType library and load the font as a <def>face</def> as FreeType likes to call it. Here we load the <code>arial.ttf</code> TrueType font file that was copied from the <code>Windows/Fonts</code> directory:
    383 </p>
    384   
    385 <pre><code>
    386 FT_Library ft;
    387 if (FT_Init_FreeType(&ft))
    388 {
    389     std::cout &lt;&lt; "ERROR::FREETYPE: Could not init FreeType Library" &lt;&lt; std::endl;
    390     return -1;
    391 }
    392 
    393 FT_Face face;
    394 if (FT_New_Face(ft, "fonts/arial.ttf", 0, &face))
    395 {
    396     std::cout &lt;&lt; "ERROR::FREETYPE: Failed to load font" &lt;&lt; std::endl;  
    397     return -1;
    398 }
    399 </code></pre>
    400   
    401 <p>
    402   Each of these FreeType functions returns a non-zero integer whenever an error occurred. 
    403   </p>
    404   
    405   <p>
    406     Once we've loaded the face, we should define the pixel font size we'd like to extract from this face:
    407 </p>
    408 
    409 <pre class="cpp"><code>
    410 FT_Set_Pixel_Sizes(face, 0, 48);  
    411 </code></pre>
    412   
    413 <p>
    414   The function sets the font's width and height parameters. Setting the width to <code>0</code> lets the face dynamically calculate the width based on the given height.
    415 </p>
    416   
    417 <p>
    418   A FreeType face hosts a collection of glyphs. We can set one of those glyphs as the active glyph by calling <fun>FT_Load_Char</fun>. Here we choose to load the character glyph 'X':
    419 </p>
    420     
    421 <pre><code>
    422 if (FT_Load_Char(face, 'X', FT_LOAD_RENDER))
    423 {
    424     std::cout &lt;&lt; "ERROR::FREETYTPE: Failed to load Glyph" &lt;&lt; std::endl;  
    425     return -1;
    426 }
    427 </code></pre>
    428   
    429 <p>
    430   By setting <var>FT_LOAD_RENDER</var> as one of the loading flags, we tell FreeType to create an 8-bit grayscale bitmap image for us that we can access via <code>face-&gt;glyph-&gt;bitmap</code>. 
    431 </p>
    432   
    433 <p>
    434   Each of the glyphs we load with FreeType however, do not have the same size (as we had with bitmap fonts). The bitmap image generated by FreeType is just large enough to contain the visible part of a character. For example, the bitmap image of the dot character '.' is much smaller in dimensions than the bitmap image of the character 'X'. For this reason, FreeType also loads several metrics that specify how large each character should be and how to properly position them. Next is an image from FreeType that shows all of the metrics it calculates for each character glyph:
    435 </p>
    436   
    437   <img src="/img/in-practice/glyph.png" alt="Image of metrics of a Glyph as loaded by FreeType"/>
    438   
    439 <p>
    440   Each of the glyphs reside on a horizontal <def>baseline</def> (as depicted by the horizontal arrow) where some glyphs sit exactly on top of this baseline (like 'X') or some slightly below the baseline (like 'g' or 'p'). These metrics define the exact offsets to properly position each glyph on the baseline, how large each glyph should be, and how many pixels we need to advance to render the next glyph. Next is a small list of the properties we'll be needing:
    441 </p>
    442     
    443 <ul>
    444   <li><strong>width</strong>: the width (in pixels) of the bitmap accessed via <code>face-&gt;glyph-&gt;bitmap.width</code>.</li>
    445   <li><strong>height</strong>: the height (in pixels) of the bitmap accessed via <code>face-&gt;glyph-&gt;bitmap.rows</code>.</li>
    446   <li><strong>bearingX</strong>: the horizontal bearing e.g. the horizontal position (in pixels) of the bitmap relative to the origin accessed via <code>face-&gt;glyph-&gt;bitmap_left</code>.</li>
    447   <li><strong>bearingY</strong>: the vertical bearing e.g. the vertical position (in pixels) of the bitmap relative to the baseline accessed via <code>face-&gt;glyph-&gt;bitmap_top</code>.</li>
    448   <li><strong>advance</strong>: the horizontal advance e.g. the horizontal distance (in 1/64th pixels) from the origin to the origin of the next glyph. Accessed via <code>face-&gt;glyph-&gt;advance.x</code>.</li>
    449 </ul>
    450     
    451 <p>
    452   We could load a character glyph, retrieve its metrics, and generate a texture each time we want to render a character to the screen, but it would be inefficient to do this each frame. We'd rather store the generated data somewhere in the application and query it whenever we want to render a character. We'll define a convenient <code>struct</code> that we'll store in a <fun>map</fun>:  
    453 </p>
    454     
    455 <pre><code>
    456 struct Character {
    457     unsigned int TextureID;  // ID handle of the glyph texture
    458     glm::ivec2   Size;       // Size of glyph
    459     glm::ivec2   Bearing;    // Offset from baseline to left/top of glyph
    460     unsigned int Advance;    // Offset to advance to next glyph
    461 };
    462 
    463 std::map&lt;char, Character&gt; Characters;
    464 </code></pre>
    465     
    466 <p>
    467     For this chapter we'll keep things simple by restricting ourselves to the first 128 characters of the ASCII character set. For each character, we generate a texture and store its relevant data into a <fun>Character</fun> struct that we add to the <var>Characters</var> map. This way, all data required to render each character is stored for later use.
    468 </p>
    469     
    470 <pre><code>
    471 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction
    472   
    473 for (unsigned char c = 0; c &lt; 128; c++)
    474 {
    475     // load character glyph 
    476     if (FT_Load_Char(face, c, FT_LOAD_RENDER))
    477     {
    478         std::cout &lt;&lt; "ERROR::FREETYTPE: Failed to load Glyph" &lt;&lt; std::endl;
    479         continue;
    480     }
    481     // generate texture
    482     unsigned int texture;
    483     <function id='50'>glGenTextures</function>(1, &texture);
    484     <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, texture);
    485     <function id='52'>glTexImage2D</function>(
    486         GL_TEXTURE_2D,
    487         0,
    488         GL_RED,
    489         face-&gt;glyph-&gt;bitmap.width,
    490         face-&gt;glyph-&gt;bitmap.rows,
    491         0,
    492         GL_RED,
    493         GL_UNSIGNED_BYTE,
    494         face-&gt;glyph-&gt;bitmap.buffer
    495     );
    496     // set texture options
    497     <function id='15'>glTexParameter</function>i(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    498     <function id='15'>glTexParameter</function>i(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    499     <function id='15'>glTexParameter</function>i(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    500     <function id='15'>glTexParameter</function>i(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    501     // now store character for later use
    502     Character character = {
    503         texture, 
    504         glm::ivec2(face-&gt;glyph-&gt;bitmap.width, face-&gt;glyph-&gt;bitmap.rows),
    505         glm::ivec2(face-&gt;glyph-&gt;bitmap_left, face-&gt;glyph-&gt;bitmap_top),
    506         face-&gt;glyph-&gt;advance.x
    507     };
    508     Characters.insert(std::pair&lt;char, Character&gt;(c, character));
    509 }
    510 </code></pre>
    511     
    512 <p>
    513   Within the for loop we list over all the 128 characters of the ASCII set and retrieve their corresponding character glyphs. For each character: we generate a texture, set its options, and store its metrics. What is interesting to note here is that we use <var>GL_RED</var> as the texture's <code>internalFormat</code> and <code>format</code> arguments. The bitmap generated from the glyph is a grayscale 8-bit image where each color is represented by a single byte. For this reason we'd like to store each byte of the bitmap buffer as the texture's single color value. We accomplish this by creating a texture where each byte corresponds to the texture color's red component (first byte of its color vector). If we use a single byte to represent the colors of a texture we do need to take care of a restriction of OpenGL:
    514 </p>
    515     
    516 <pre class="cpp"><code>
    517 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);   
    518 </code></pre>
    519     
    520 <p>
    521   OpenGL requires that textures all have a 4-byte alignment e.g. their size is always a multiple of 4 bytes. Normally this won't be a problem since most textures have a width that is a multiple of 4 and/or use 4 bytes per pixel, but since we now only use a single byte per pixel, the texture can have any possible width. By setting its unpack alignment to <code>1</code> we ensure there are no  alignment issues (which could cause segmentation faults).
    522 </p>
    523     
    524 <p>
    525   Be sure to clear FreeType's resources once you're finished processing the glyphs:
    526 </p>
    527     
    528 <pre><code>
    529 FT_Done_Face(face);
    530 FT_Done_FreeType(ft);
    531 </code></pre>
    532     
    533 <h3>Shaders</h3>
    534 <p>
    535   To render the glyphs we'll be using the following vertex shader:
    536 </p>
    537     
    538 <pre><code>
    539 #version 330 core
    540 layout (location = 0) in vec4 vertex; // &lt;vec2 pos, vec2 tex&gt;
    541 out vec2 TexCoords;
    542 
    543 uniform mat4 projection;
    544 
    545 void main()
    546 {
    547     gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
    548     TexCoords = vertex.zw;
    549 }  
    550 </code></pre>
    551     
    552 <p>
    553   We combine both the position and texture coordinate data into one <fun>vec4</fun>. The vertex shader multiplies the coordinates with a projection matrix and forwards the texture coordinates to the fragment shader:
    554 </p>
    555   
    556 <pre><code>
    557 #version 330 core
    558 in vec2 TexCoords;
    559 out vec4 color;
    560 
    561 uniform sampler2D text;
    562 uniform vec3 textColor;
    563 
    564 void main()
    565 {    
    566     vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
    567     color = vec4(textColor, 1.0) * sampled;
    568 }  
    569 </code></pre>
    570     
    571 <p>
    572   The fragment shader takes two uniforms: one is the mono-colored bitmap image of the glyph, and the other is a color uniform for adjusting the text's final color. We first sample the color value of the bitmap texture. Because the texture's data is stored in just its red component, we sample the <code>r</code> component of the texture as the sampled alpha value. By varying the output color's alpha value, the resulting pixel will be transparent for all the glyph's background colors and non-transparent for the actual character pixels. We also multiply the RGB colors by the <var>textColor</var> uniform to vary the text color.
    573 </p>
    574     
    575 <p>
    576   We do need to enable <a href="https://learnopengl.com/Advanced-OpenGL/Blending" target="_blank">blending</a> for this to work though: 
    577 </p>
    578     
    579 <pre><code>
    580 <function id='60'>glEnable</function>(GL_BLEND);
    581 <function id='70'>glBlendFunc</function>(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  
    582 </code></pre>
    583     
    584 <p>
    585   For the projection matrix we'll be using an orthographic projection matrix. For rendering text we (usually) do not need perspective, and using an orthographic projection matrix also allows us to specify all vertex coordinates in screen coordinates if we set it up as follows:
    586 </p>
    587     
    588 <pre><code>
    589 glm::mat4 projection = <function id='59'>glm::ortho</function>(0.0f, 800.0f, 0.0f, 600.0f);
    590 </code></pre>
    591     
    592 <p>
    593   We set the projection matrix's bottom parameter to <code>0.0f</code> and its top parameter equal to the window's height. The result is that we specify coordinates with <code>y</code> values ranging from the bottom part of the screen (<code>0.0f</code>) to the top part of the screen (<code>600.0f</code>). This means that the point (<code>0.0</code>, <code>0.0</code>) now corresponds to the bottom-left corner.
    594 </p>
    595      
    596 <p>
    597   Last up is creating a VBO and VAO for rendering the quads. For now we reserve enough memory when initiating the VBO so that we can later update the VBO's memory when rendering characters:
    598 </p>
    599 
    600 <pre><code>
    601 unsigned int VAO, VBO;
    602 <function id='33'>glGenVertexArrays</function>(1, &VAO);
    603 <function id='12'>glGenBuffers</function>(1, &VBO);
    604 <function id='27'>glBindVertexArray</function>(VAO);
    605 <function id='32'>glBindBuffer</function>(GL_ARRAY_BUFFER, VBO);
    606 <function id='31'>glBufferData</function>(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
    607 <function id='29'><function id='60'>glEnable</function>VertexAttribArray</function>(0);
    608 <function id='30'>glVertexAttribPointer</function>(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
    609 <function id='32'>glBindBuffer</function>(GL_ARRAY_BUFFER, 0);
    610 <function id='27'>glBindVertexArray</function>(0);      
    611 </code></pre>
    612   
    613 <p>
    614   The 2D quad requires <code>6</code> vertices of <code>4</code> floats each, so we reserve <code>6 * 4</code> floats of memory. Because we'll be updating the content of the VBO's memory quite often we'll allocate the memory with <var>GL_DYNAMIC_DRAW</var>.
    615 </p>
    616     
    617 <h3>Render line of text</h3>
    618 <p>
    619   To render a character, we extract the corresponding <fun>Character</fun> struct of the <var>Characters</var> map and calculate the quad's dimensions using the character's metrics. With the quad's calculated dimensions we dynamically generate a set of 6 vertices that we use to update the content of the memory managed by the VBO using <fun><function id='90'>glBufferSubData</function></fun>.
    620 </p>
    621  
    622 <p>
    623   We create a function called <fun>RenderText</fun> that renders a string of characters:
    624 </p>
    625     
    626 <pre><code>
    627 void RenderText(Shader &s, std::string text, float x, float y, float scale, glm::vec3 color)
    628 {
    629     // activate corresponding render state	
    630     s.Use();
    631     <function id='44'>glUniform</function>3f(<function id='45'>glGetUniformLocation</function>(s.Program, "textColor"), color.x, color.y, color.z);
    632     <function id='49'>glActiveTexture</function>(GL_TEXTURE0);
    633     <function id='27'>glBindVertexArray</function>(VAO);
    634 
    635     // iterate through all characters
    636     std::string::const_iterator c;
    637     for (c = text.begin(); c != text.end(); c++)
    638     {
    639         Character ch = Characters[*c];
    640 
    641         float xpos = x + ch.Bearing.x * scale;
    642         float ypos = y - (ch.Size.y - ch.Bearing.y) * scale;
    643 
    644         float w = ch.Size.x * scale;
    645         float h = ch.Size.y * scale;
    646         // update VBO for each character
    647         float vertices[6][4] = {
    648             { xpos,     ypos + h,   0.0f, 0.0f },            
    649             { xpos,     ypos,       0.0f, 1.0f },
    650             { xpos + w, ypos,       1.0f, 1.0f },
    651 
    652             { xpos,     ypos + h,   0.0f, 0.0f },
    653             { xpos + w, ypos,       1.0f, 1.0f },
    654             { xpos + w, ypos + h,   1.0f, 0.0f }           
    655         };
    656         // render glyph texture over quad
    657         <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, ch.textureID);
    658         // update content of VBO memory
    659         <function id='32'>glBindBuffer</function>(GL_ARRAY_BUFFER, VBO);
    660         <function id='90'>glBufferSubData</function>(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); 
    661         <function id='32'>glBindBuffer</function>(GL_ARRAY_BUFFER, 0);
    662         // render quad
    663         <function id='1'>glDrawArrays</function>(GL_TRIANGLES, 0, 6);
    664         // now advance cursors for next glyph (note that advance is number of 1/64 pixels)
    665         x += (ch.Advance &gt;&gt; 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64)
    666     }
    667     <function id='27'>glBindVertexArray</function>(0);
    668     <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, 0);
    669 }
    670 </code></pre>
    671     
    672 <p>
    673   Most of the content of the function should be relatively self-explanatory: we first calculate the origin position of the quad (as <var>xpos</var> and <var>ypos</var>) and the quad's size (as <var>w</var> and <var>h</var>) and generate a set of 6 vertices to form the 2D quad; note that we scale each metric by <var>scale</var>. We then update the content of the VBO and render the quad.   
    674 </p>
    675     
    676 <p>
    677   The following line of code requires some extra attention though:
    678 </p>
    679     
    680 <pre><code>
    681 float ypos = y - (ch.Size.y - ch.Bearing.y);   
    682 </code></pre>
    683     
    684 <p>
    685   Some characters (like 'p' or 'g') are rendered slightly below the baseline, so the quad should also be positioned slightly below <fun>RenderText</fun>'s <var>y</var> value. The exact amount we need to offset <var>ypos</var> below the baseline can be figured out from the glyph metrics:
    686 </p>
    687     
    688 <img src="/img/in-practice/glyph_offset.png" alt="Offset below baseline of glyph to position 2D quad"/>
    689 
    690 <p>
    691   To calculate this distance e.g. offset we need to figure out the distance a glyph extends below the baseline; this distance is indicated by the red arrow. As you can see from the glyph metrics, we can calculate the length of this vector by subtracting <code>bearingY</code> from the glyph's (bitmap) height. This value is then <code>0.0</code> for characters that rest on the baseline (like 'X') and positive for characters that reside slightly below the baseline (like 'g' or 'j').
    692 </p>
    693   
    694 <p>
    695   If you did everything correct you should now be able to successfully render strings of text with the following statements:
    696 </p>
    697   
    698 <pre><code>
    699 RenderText(shader, "This is sample text", 25.0f, 25.0f, 1.0f, glm::vec3(0.5, 0.8f, 0.2f));
    700 RenderText(shader, "(C) LearnOpenGL.com", 540.0f, 570.0f, 0.5f, glm::vec3(0.3, 0.7f, 0.9f));
    701 </code></pre>
    702   
    703 <p>
    704   This should then look similar to the following image:
    705 </p>
    706   
    707   <img src="/img/in-practice/text_rendering.png" class="clean" alt="Image of text rendering with OpenGL using FreeType"/>
    708     
    709 <p>
    710   You can find the code of this example <a href="/code_viewer_gh.php?code=src/7.in_practice/2.text_rendering/text_rendering.cpp" target="_blank">here</a>.
    711 </p>
    712   
    713 <p>
    714   To give you a feel for how we calculated the quad's vertices, we can disable blending to see what the actual rendered quads look like:
    715 </p>  
    716     
    717     <img src="/img/in-practice/text_rendering_quads.png" class="clean" alt="Image of quads without transparency for text rendering in OpenGL"/>
    718 
    719 <p>
    720   Here you can clearly see most quads resting on the (imaginary) baseline while the quads that corresponds to glyphs like 'p' or '(' are shifted downwards.
    721 </p>
    722       
    723 <h2>Going further</h2>
    724 <p>
    725   This chapter demonstrated a text rendering technique with TrueType fonts using the FreeType library. The approach is flexible, scalable, and works with many character encodings. However, this approach is likely going to be overkill for your application as we generate and render textures for each glyph. Performance-wise, bitmap fonts are preferable as we only need one texture for all our glyphs. The best approach would be to combine the two approaches by dynamically generating a bitmap font texture featuring all character glyphs as loaded with FreeType.  This saves the renderer from a significant amount of texture switches and, based on how tight each glyph is packed, could save quite some performance.
    726 </p>
    727       
    728 <p>
    729   Another issue with FreeType font bitmaps is that the glyph textures are stored with a fixed font size, so a significant amount of scaling may introduce jagged edges. Furthermore, rotations applied to the glyphs will cause them to appear blurry. This can be mitigated by, instead of storing the actual rasterized pixel colors, storing the distance to the closest glyph outline per pixel. This technique is called <def>signed distance field fonts</def> and Valve published a <a href="https://steamcdn-a.akamaihd.net/apps/valve/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf" target="_blank">paper</a> a few years ago about their implementation of this technique which works surprisingly well for 3D rendering applications.
    730 </p>
    731       
    732 <h2>Further reading</h2>
    733 <ul>
    734     <li><a href="https://www.websiteplanet.com/blog/best-free-fonts/" target="_blank">70+ Best Free Fonts for Designers</a>: summarized list of a large group of fonts to use in your project for personal or commercial use.</li>
    735 </ul>       
    736 
    737     </div>
    738     
    739     <div id="hover">
    740         HI
    741     </div>
    742    <!-- 728x90/320x50 sticky footer -->
    743 <div id="waldo-tag-6196"></div>
    744 
    745    <div id="disqus_thread"></div>
    746 
    747     
    748 
    749 
    750 </div> <!-- container div -->
    751 
    752 
    753 </div> <!-- super container div -->
    754 </body>
    755 </html>
    756 	</main>
    757 </body>
    758 </html>