Last active
April 27, 2016 07:31
-
-
Save matthewjberger/464281d2e9101d13f0c8e931948a2f4b to your computer and use it in GitHub Desktop.
Text Rendering with OpenGL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
auto ReadAllBytes = [](const std::string& filename) | |
{ | |
using namespace std; | |
ifstream file(filename.c_str(), ios::binary | ios::ate); | |
file >> noskipws; | |
streampos fileSize = file.tellg(); | |
file.seekg(0, ios::beg); | |
vector<BYTE> bytes; | |
bytes.reserve(fileSize); | |
copy(istream_iterator<BYTE>(file), | |
istream_iterator<BYTE>(), | |
back_inserter(bytes)); | |
return bytes; | |
}; | |
auto bytes = ReadAllBytes("c:/windows/fonts/arialbd.ttf"); | |
unsigned char* data = bytes.data(); | |
stbtt_fontinfo font; | |
stbtt_InitFont(&font, data, 0); | |
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
int scale = 20; int character = 'A'; | |
unsigned char *bitmap = stbtt_GetCodepointBitmap(&font, 0, stbtt_ScaleForPixelHeight(&font, scale), character, &width_, &height_, 0, 0); | |
glEnable(GL_BLEND); | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
create_from_data(width_, height_, bitmap, GL_RED, target); | |
return true; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 330 core | |
in vec2 f_texCoord; | |
out vec4 fragColor; | |
uniform sampler2D quadTexture; | |
uniform vec3 color; | |
void main() | |
{ | |
vec4 sampled = vec4(1.0f, 1.0f, 1.0f, texture(quadTexture, f_texCoord).r); // use the red intensity as alpha channel | |
fragColor = vec4(color, 1.0f) * sampled; // color would be better suited for a uniform | |
/* | |
// Same thing as above, but in one line. Untested. | |
fragColor = vec4(color, texture(quadTexture, f_texCoord).r); // use only the r channel | |
*/ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 330 core | |
layout (location = 0) in vec3 v_position; | |
layout (location = 1) in vec2 v_texCoord; | |
out vec2 f_texCoord; | |
uniform mat4 mvpMatrix; | |
void main() | |
{ | |
gl_Position = mvpMatrix * vec4(v_position, 1.0f); | |
f_texCoord = vec2(v_texCoord.x, 1.0 - v_texCoord.y); // necessary to flip texture | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define STB_TRUETYPE_IMPLEMENTATION | |
#include "stb_truetype.h" | |
typedef unsigned char BYTE; | |
std::vector<BYTE> ReadAllBytes(const std::string& filename) | |
{ | |
using namespace std; | |
ifstream file(filename.c_str(), ios::binary | ios::ate); | |
file >> noskipws; | |
streampos fileSize = file.tellg(); | |
file.seekg(0, ios::beg); | |
vector<BYTE> bytes; | |
bytes.reserve(fileSize); | |
copy(istream_iterator<BYTE>(file), | |
istream_iterator<BYTE>(), | |
back_inserter(bytes)); | |
return bytes; | |
} | |
// Read the file in as an array of bytes | |
auto bytes = ReadAllBytes("c:/windows/fonts/arialbd.ttf"); | |
unsigned char* data = bytes.data(); // needs one level of indirection to work properly | |
/* STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); | |
* Given an offset into the file that defines a font, this function builds | |
* the necessary cached info for the rest of the system. You must allocate | |
* the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't | |
* need to do anything special to free it, because the contents are pure | |
* value data with no additional data structures. Returns 0 on failure. | |
*/ | |
// Load the font information | |
stbtt_fontinfo font; | |
stbtt_InitFont(&font, data, 0); | |
/* STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); | |
allocates a large-enough single-channel 8bpp bitmap and renders the | |
specified character/glyph at the specified scale into it, with | |
antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). | |
*width & *height are filled out with the width & height of the bitmap, | |
which is stored left-to-right, top-to-bottom. | |
xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap | |
*/ | |
// Create the glyph bitmap | |
int scale = 20; int character = 'A'; | |
unsigned char *bitmap = stbtt_GetCodepointBitmap(&font, 0, stbtt_ScaleForPixelHeight(&font, scale), character, &width, &height, 0, 0); | |
/* The bitmap we just generated is a single channel, 8bit per pixel bitmap. | |
* 8 bits is equivalent to 1 byte. Since we are using 1 byte to describe each pixel's color | |
* and OpenGL's default unpacking alignment is 4 bytes to describe each pixel's color (32 bits per pixel) | |
* we have to manually change the unpacking alignment to unpack 1 byte at a time. | |
* This allows for 1 byte to describe each pixel. | |
*/ | |
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
// Use our bitmap data to create a texture. Since we are using a single byte per pixel, it corresponds to the red component. | |
//(4 bytes would use r,g,b,a and each component is 1 byte) | |
glTexImage2D(target, 0, GL_RED, width_, height_, 0, GL_RED, GL_UNSIGNED_BYTE, bitmap); | |
// Enable blending. This will allow the alpha channel to take effect in the shader. | |
glEnable(GL_BLEND); | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
/* STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); | |
* leftSideBearing is the offset from the current horizontal position to the left edge of the character | |
* advanceWidth is the offset from the current horizontal position to the next horizontal position | |
* these are expressed in unscaled coordinates SO MAKE SURE TO MULTIPLY BY SCALE VALUE | |
*/ | |
int advanceWidth, leftSideBearing; | |
stbtt_GetCodepointHMetrics(&info, 'A', &advanceWidth, &leftSideBearing); | |
/* NOTE: The following code isn't necessary, but it may be useful. | |
* The width and height are filled out when you create the bitmap from the codepoint. | |
* STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); | |
* Gets the bounding box of the visible part of the glyph, in unscaled coordinates SO MAKE SURE TO MULTIPLY BY SCALE VALUE | |
*/ | |
int x0, y0, x1, y1; | |
stbtt_GetCodepointBox(&info, 'A', &x0, &y0, &x1, &y1); | |
// Reset the unpacking alignment back to 4 bytes (32 bits per pixel) | |
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); | |
// Disable blending when finished | |
glEnable(GL_BLEND); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment