Text rendering with line wrapping inside of area
This commit is contained in:
parent
e9e05d5ed1
commit
29d8bf474a
@ -68,36 +68,105 @@ void Font::render_glyphs(const std::string& text, unsigned size, const glm::vec4
|
||||
|
||||
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
|
||||
std::u32string converted = converter.from_bytes(text);
|
||||
unsigned x_pos = 0;
|
||||
unsigned text_line_y = 0;
|
||||
for(char32_t ch : converted) {
|
||||
output.push_back(std::move(render_glyph(ch, size, color)));
|
||||
RasterizedGlyph* glyph = output.back().get();
|
||||
if(glyph->m_height>text_line_y)
|
||||
text_line_y = glyph->m_height;
|
||||
}
|
||||
|
||||
unsigned x_pos = 0;
|
||||
for(std::unique_ptr<RasterizedGlyph>& glyph : output) {
|
||||
glyph->m_x = x_pos;
|
||||
glyph->m_y = 0; // TODO: Update this when multiline text rendering will be supported
|
||||
x_pos+=glyph->m_advance_x;
|
||||
glyph->m_y = text_line_y - glyph->m_height;
|
||||
x_pos+=glyph->m_width;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Surface> Font::render_text(const std::vector<std::unique_ptr<RasterizedGlyph>>& glyphs) {
|
||||
void Font::render_glyphs_in_area(const glm::vec2& area_size, const std::string& text, unsigned size, const glm::vec4ub& color, std::vector<std::unique_ptr<RasterizedGlyph>>& output) {
|
||||
if(text.empty())
|
||||
return;
|
||||
if(size!=m_prev_size) {
|
||||
if(FT_Set_Char_Size(m_face, 0, size*64, 0, 0)) {
|
||||
LOG_ERROR("Failed to set size %d for Font %p", size, this);
|
||||
return;
|
||||
}
|
||||
m_prev_size = size;
|
||||
}
|
||||
|
||||
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
|
||||
std::u32string converted = converter.from_bytes(text);
|
||||
unsigned x_pos = 0;
|
||||
unsigned y_pos = 0;
|
||||
unsigned text_line_y = 0;
|
||||
unsigned glyph_in_line_count = 0;
|
||||
std::vector<GlyphPositionInfo> glyph_positions;
|
||||
|
||||
for(char32_t ch : converted) {
|
||||
output.push_back(std::move(render_glyph(ch, size, color)));
|
||||
RasterizedGlyph* glyph = output.back().get();
|
||||
x_pos+=glyph->m_width;
|
||||
if(y_pos>area_size.y)
|
||||
break;
|
||||
if(x_pos+glyph->m_width<area_size.x) {
|
||||
if(glyph->m_height>text_line_y)
|
||||
text_line_y = glyph->m_height;
|
||||
}
|
||||
else {
|
||||
x_pos = 0;
|
||||
glyph_positions.push_back(GlyphPositionInfo{text_line_y, glyph_in_line_count});
|
||||
glyph_in_line_count = 0;
|
||||
y_pos+=text_line_y;
|
||||
text_line_y = 0;
|
||||
}
|
||||
glyph_in_line_count++;
|
||||
}
|
||||
if(glyph_in_line_count>0)
|
||||
glyph_positions.push_back(GlyphPositionInfo{text_line_y, glyph_in_line_count});
|
||||
|
||||
size_t glyph_counter = 0;
|
||||
unsigned glyph_line = 0;
|
||||
x_pos = 0;
|
||||
y_pos = 0;
|
||||
for(std::unique_ptr<RasterizedGlyph>& glyph : output) {
|
||||
const GlyphPositionInfo& position_info = glyph_positions[glyph_line];
|
||||
glyph->m_x = x_pos;
|
||||
glyph->m_y = y_pos+position_info.m_text_line_y-glyph->m_height;
|
||||
x_pos+=glyph->m_width;
|
||||
|
||||
glyph_counter++;
|
||||
if(glyph_counter==position_info.m_glyph_count) {
|
||||
glyph_counter = 0;
|
||||
x_pos = 0;
|
||||
y_pos+=position_info.m_text_line_y+12;
|
||||
glyph_line++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Surface> Font::render_text(const std::vector<std::unique_ptr<RasterizedGlyph>>& glyphs, const glm::vec2& final_size) {
|
||||
std::unique_ptr<Surface> result;
|
||||
unsigned final_surface_width = 0;
|
||||
int final_surface_height = 0;
|
||||
int surface_text_line = 0;
|
||||
for(const std::unique_ptr<RasterizedGlyph>& glyph : glyphs) {
|
||||
final_surface_width+=glyph->m_advance_x;
|
||||
if(static_cast<unsigned>(surface_text_line)<glyph->m_surface->get_height())
|
||||
surface_text_line = glyph->m_surface->get_height();
|
||||
const int current_surface_height = surface_text_line-glyph->m_top+glyph->m_surface->get_height();
|
||||
if(current_surface_height>final_surface_height)
|
||||
final_surface_height = current_surface_height;
|
||||
unsigned final_surface_height = 0;
|
||||
if(final_size.x!=0 && final_size.y!=0) {
|
||||
final_surface_width = final_size.x;
|
||||
final_surface_height = final_size.y;
|
||||
}
|
||||
else {
|
||||
for(const std::unique_ptr<RasterizedGlyph>& glyph : glyphs) {
|
||||
const unsigned right_point = glyph->m_x+glyph->m_width;
|
||||
const unsigned bottom_point = glyph->m_y+glyph->m_height;
|
||||
if(right_point>final_surface_width)
|
||||
final_surface_width = right_point;
|
||||
if(bottom_point>final_surface_height)
|
||||
final_surface_height = bottom_point;
|
||||
}
|
||||
}
|
||||
|
||||
result = std::make_unique<Surface>(final_surface_width, final_surface_height, glm::vec4ub(0, 0, 0, 0));
|
||||
unsigned x_pos = 0;
|
||||
for(const std::unique_ptr<RasterizedGlyph>& glyph : glyphs) {
|
||||
result->blit_surface(glyph->m_x, surface_text_line-glyph->m_top, *glyph->m_surface);
|
||||
x_pos+=glyph->m_advance_x;
|
||||
}
|
||||
for(const std::unique_ptr<RasterizedGlyph>& glyph : glyphs)
|
||||
result->blit_surface(glyph->m_x, glyph->m_y, *glyph->m_surface);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -109,6 +178,13 @@ std::unique_ptr<Surface> Font::render_text(const std::string& text, unsigned siz
|
||||
return render_text(character_surfaces);
|
||||
}
|
||||
|
||||
std::unique_ptr<Surface> Font::render_text_in_area(const glm::vec2& area_size, const std::string& text, unsigned size, const glm::vec4ub& color) {
|
||||
std::vector<std::unique_ptr<RasterizedGlyph>> character_surfaces;
|
||||
render_glyphs_in_area(area_size, text, size, color, character_surfaces);
|
||||
|
||||
return render_text(character_surfaces, area_size);
|
||||
}
|
||||
|
||||
std::unique_ptr<Font::RasterizedGlyph> Font::render_glyph(unsigned charcode, unsigned size, const glm::vec4ub& color) {
|
||||
std::unique_ptr<RasterizedGlyph> result = std::make_unique<Font::RasterizedGlyph>();
|
||||
|
||||
@ -127,25 +203,27 @@ std::unique_ptr<Font::RasterizedGlyph> Font::render_glyph(unsigned charcode, uns
|
||||
uint8_t* pixels = new uint8_t[pixels_size];
|
||||
memset(pixels, 0, pixels_size);
|
||||
|
||||
switch(bitmap.pixel_mode) {
|
||||
case FT_PIXEL_MODE_NONE:
|
||||
LOG_ERROR("Invalid glyph pixel mode");
|
||||
return result;
|
||||
case FT_PIXEL_MODE_MONO:
|
||||
convert_ft_mono_pixels(bitmap, color, pixels);
|
||||
break;
|
||||
case FT_PIXEL_MODE_GRAY:
|
||||
convert_ft_gray_pixels(bitmap, color, pixels);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("(FIXME) Unsupported glyph pixel mode: %d", bitmap.pixel_mode);
|
||||
return result;
|
||||
if(!isspace(charcode)) {
|
||||
switch(bitmap.pixel_mode) {
|
||||
case FT_PIXEL_MODE_NONE:
|
||||
LOG_ERROR("Invalid glyph pixel mode");
|
||||
return result;
|
||||
case FT_PIXEL_MODE_MONO:
|
||||
convert_ft_mono_pixels(bitmap, color, pixels);
|
||||
break;
|
||||
case FT_PIXEL_MODE_GRAY:
|
||||
convert_ft_gray_pixels(bitmap, color, pixels);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("(FIXME) Unsupported glyph pixel mode: %d", bitmap.pixel_mode);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
result->m_surface = std::make_unique<Surface>(bitmap.width, bitmap.rows, pixels);
|
||||
delete[] pixels;
|
||||
result->m_advance_x = m_face->glyph->advance.x>>6;
|
||||
result->m_top = m_face->glyph->bitmap_top;
|
||||
result->m_width = m_face->glyph->advance.x>>6;
|
||||
result->m_height = m_face->glyph->bitmap_top;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -42,8 +42,14 @@ namespace polygun::renderer {
|
||||
std::unique_ptr<Surface> m_surface;
|
||||
unsigned m_x;
|
||||
unsigned m_y;
|
||||
unsigned m_advance_x;
|
||||
unsigned m_top;
|
||||
unsigned m_width;
|
||||
unsigned m_height;
|
||||
};
|
||||
|
||||
private:
|
||||
struct GlyphPositionInfo {
|
||||
unsigned m_text_line_y;
|
||||
size_t m_glyph_count;
|
||||
};
|
||||
|
||||
public:
|
||||
@ -52,8 +58,10 @@ namespace polygun::renderer {
|
||||
|
||||
bool load_from_file(const std::string& path);
|
||||
void render_glyphs(const std::string& text, unsigned size, const glm::vec4ub& color, std::vector<std::unique_ptr<RasterizedGlyph>>& output);
|
||||
std::unique_ptr<Surface> render_text(const std::vector<std::unique_ptr<RasterizedGlyph>>& glyphs);
|
||||
void render_glyphs_in_area(const glm::vec2& area_size, const std::string& text, unsigned size, const glm::vec4ub& color, std::vector<std::unique_ptr<RasterizedGlyph>>& output);
|
||||
std::unique_ptr<Surface> render_text(const std::vector<std::unique_ptr<RasterizedGlyph>>& glyphs, const glm::vec2& final_size = glm::vec2(0, 0));
|
||||
std::unique_ptr<Surface> render_text(const std::string& text, unsigned size, const glm::vec4ub& color);
|
||||
std::unique_ptr<Surface> render_text_in_area(const glm::vec2& area_size, const std::string& text, unsigned size, const glm::vec4ub& color);
|
||||
|
||||
private:
|
||||
FT_Face m_face;
|
||||
|
Loading…
x
Reference in New Issue
Block a user