Last active
June 15, 2020 06:43
-
-
Save matjam/0281990eb80bda5547a53f0972d7fffb to your computer and use it in GitHub Desktop.
This file contains hidden or 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
inline bool | |
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; | |
sf::Image glyph; | |
glyph.create(m_character_width, m_character_height, m_palette_colors[m_current_bg]); | |
for (uint32_t y = 0; y < m_height; y++) { | |
for (uint32_t x = 0; x < m_width; x++) { | |
if (!m_console_dirty[x + y * m_width]) | |
continue; // skip this character as it doesn't need to be rendered. | |
auto &[character, fg, bg] = peek(sf::Vector2i(x, y)); | |
auto &bitmap = m_glyph_bitmap[character]; | |
auto fg_color = m_palette_colors[fg]; | |
auto bg_color = m_palette_colors[bg]; | |
if (bitmap.size() == 0) { | |
cache_misses++; | |
bitmap.resize(m_character_width * m_character_height, 0); | |
// no bitmap exists for this, we need to build the bitmap from the FreeType font | |
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); | |
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; | |
} | |
} | |
} | |
} else { | |
cache_hits++; | |
} | |
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 (bitmap[offset_x + offset_y * m_character_width] == 255) { | |
glyph.setPixel(offset_x, offset_y, fg_color); | |
} else { | |
glyph.setPixel(offset_x, offset_y, bg_color); | |
} | |
} | |
} | |
m_console_texture.update(glyph, x * m_character_width, y * m_character_height); | |
m_console_dirty[x + y * m_width] = false; // it's clean now! | |
} | |
} | |
update_time = timer.getElapsedTime().asMilliseconds(); | |
} | |
void | |
ConsoleScreen::loadFont(const std::string font_file, uint32_t pixel_size) | |
{ | |
auto font_data = file_cache->Get(font_file); | |
auto error = FT_Init_FreeType(&m_library); | |
if (error != FT_Err_Ok) { | |
SPDLOG_ERROR("unable to initialize freetype"); | |
return; | |
} | |
const auto font_data_bytes = (FT_Byte *)font_data->data(); | |
error = FT_New_Memory_Face(m_library, font_data_bytes, font_data->size(), 0, &m_face); | |
if (error == FT_Err_Unknown_File_Format) { | |
SPDLOG_ERROR("unable to load unknown font data format"); | |
return; | |
} else if (error != FT_Err_Ok) { | |
SPDLOG_ERROR("unable to load font data, unknown error"); | |
return; | |
} | |
if (FT_Set_Pixel_Sizes(m_face, 0, pixel_size) != FT_Err_Ok) { | |
SPDLOG_ERROR("unable to set pixel size"); | |
return; | |
} | |
SPDLOG_INFO("loaded font {}", m_face->family_name); | |
return; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment