Last active
June 16, 2020 23:08
-
-
Save matjam/fd6596de18c62affe0c32cc73c58ff25 to your computer and use it in GitHub Desktop.
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
glyphBit(const FT_GlyphSlot &glyph, const int x, const int y) | |
{ | |
int pitch = abs(glyph->bitmap.pitch); | |
unsigned char *row = &glyph->bitmap.buffer[pitch * y]; | |
char cValue = row[x >> 3]; | |
return (cValue & (128 >> (x & 7))) != 0; | |
} | |
// When update() is called, we scan through each character and look in the m_glyph_images map | |
// for the image that holds the glyph. If we don't find one, we construct it from the sf::Font | |
// that we loaded on start. This is slow for the first time we render that character, but is | |
// cached after that so should be fast. | |
// | |
// These images are then rendered directly to the texture backing the m_console_sprite. | |
void | |
ConsoleScreen::update() | |
{ | |
sf::Clock timer; | |
std::vector<uint8_t> bitmap; | |
for (uint32_t y = 0; y < m_height; y++) { | |
for (uint32_t x = 0; x < m_width; x++) { | |
uint32_t atlas_offset = 0; | |
auto &[character, fg, bg] = peek(sf::Vector2i(x, y)); | |
auto fg_color = m_palette_colors[fg]; | |
auto bg_color = m_palette_colors[bg]; | |
auto atlas_offset_it = m_console_atlas_offset.find(character); | |
if (atlas_offset_it == m_console_atlas_offset.end()) { | |
// We need to generate a new image for this glyph and write it to the atlas. | |
// I think this is larger than what we need | |
bitmap.resize(m_character_width * m_character_height, 0); | |
if (FT_Load_Char(m_face, character, FT_LOAD_RENDER | FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO) != | |
FT_Err_Ok) { | |
continue; | |
} | |
FT_GlyphSlot glyph = m_face->glyph; | |
int pitch = abs(glyph->bitmap.pitch); | |
// the glyphs coming out of FreeType are bitmap mode so each bit is a pixel. | |
for (size_t y = 0; y < glyph->bitmap.rows; ++y) { | |
for (size_t x = 0; x < glyph->bitmap.width; ++x) { | |
int imageIndex = (glyph->bitmap.width * y) + x; | |
if (glyphBit(glyph, x, y)) { | |
bitmap[imageIndex] = 255; | |
} else { | |
bitmap[imageIndex] = 0; | |
} | |
} | |
} | |
// we can probably do both of this in a single operation but I've had a horrible | |
// time doing that. so above, we're wasting a whole byte to represent a bit.. | |
sf::Image glyph_image; | |
glyph_image.create(m_character_width, m_character_height, sf::Color::Transparent); | |
for (uint32_t offset_y = 0; offset_y < m_character_height; offset_y++) { | |
for (uint32_t offset_x = 0; offset_x < m_character_width; offset_x++) { | |
uint32_t pixel_offset = 4 * offset_x + offset_y * m_character_width; | |
// if the pixel is set then write the color as white. We will apply | |
// color to the vertex. | |
if (bitmap[offset_x + offset_y * m_character_width] == 255) { | |
glyph_image.setPixel(offset_x, offset_y, sf::Color::White); | |
} | |
} | |
} | |
// ok so now we have an image with the rendered glyph in white with a transparent bg. | |
atlas_offset = setAtlasGlyph(character, glyph_image); | |
} else { | |
atlas_offset = atlas_offset_it->second; | |
} | |
setQuadColorForScreenLocation(m_console_bg_vertices, sf::Vector2i(x, y), bg_color); | |
setQuadColorForScreenLocation(m_console_fg_vertices, sf::Vector2i(x, y), fg_color); | |
setTexCoordsForScreenLocation(m_console_fg_vertices, | |
sf::Vector2i(x, y), | |
getAtlasCoordsForOffset(atlas_offset)); | |
m_console_dirty[x + y * m_width] = false; // it's clean now! | |
} | |
} | |
assert(m_console_bg_vertex_buffer.update(m_console_bg_vertices.data(), m_width * m_height * 4, 0)); | |
assert(m_console_fg_vertex_buffer.update(m_console_fg_vertices.data(), m_width * m_height * 4, 0)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment