Browse Source

size refactor (sizeResponse prototype), multiline support, Y scroll support

master
Odilitime 5 years ago
parent
commit
685986f45a
  1. 220
      src/graphics/text/TextRasterizer.cpp
  2. 16
      src/graphics/text/TextRasterizer.h

220
src/graphics/text/TextRasterizer.cpp

@ -45,7 +45,7 @@ TextRasterizer::~TextRasterizer() { @@ -45,7 +45,7 @@ TextRasterizer::~TextRasterizer() {
FT_Done_FreeType(lib);
}
std::unique_ptr<std::pair<int, int>> TextRasterizer::size(const rasterizationRequest &request) const {
std::unique_ptr<sizeResponse> TextRasterizer::size(const rasterizationRequest &request) const {
if (!request.availableWidth) {
// window is likely minimized, so no output
return nullptr;
@ -81,18 +81,20 @@ std::unique_ptr<std::pair<int, int>> TextRasterizer::size(const rasterizationReq @@ -81,18 +81,20 @@ std::unique_ptr<std::pair<int, int>> TextRasterizer::size(const rasterizationReq
const hb_glyph_info_t *glyphInfo = hb_buffer_get_glyph_infos(buffer, &glyphCount);
const hb_glyph_position_t *glyphPos = hb_buffer_get_glyph_positions(buffer, &glyphCount);
std::unique_ptr<rasterizationResponse> response = std::make_unique<rasterizationResponse>();
std::unique_ptr<sizeResponse> response = std::make_unique<sizeResponse>();
// figure out width/height
int cx = 0;
int cy = 0;
int xmax = 0;
int y0max = 0, y1max = 0;
int lines = 1;
//int y0max = 0;
int y1max = 0;
//int lines = 1;
response->wrapped = false;
int lineXStart = request.startX;
int leftPadding = 0;
int wrapToX = 0;
//int leftPadding = 0;
//int wrapToX = 0;
int maxy0 = 0;
for (unsigned int i = 0; i < glyphCount; i++) {
if (FT_Load_Glyph(*face, glyphInfo[i].codepoint, FT_LOAD_DEFAULT)) {
std::cout << "Could not load glyph" << std::endl;
@ -108,12 +110,39 @@ std::unique_ptr<std::pair<int, int>> TextRasterizer::size(const rasterizationReq @@ -108,12 +110,39 @@ std::unique_ptr<std::pair<int, int>> TextRasterizer::size(const rasterizationReq
// how much space does this character take
const float xa = static_cast<float>(glyphPos[i].x_advance) / 64;
const float ya = static_cast<float>(glyphPos[i].y_advance) / 64; //mostly 0s
const float yo = static_cast<float>(glyphPos[i].y_offset) / 64;
int y0 = static_cast<int>(floor(yo + slot->bitmap_top));
//miny0 = std::min(y0, miny0);
maxy0 = std::max(y0, maxy0);
// do we need to padding the texture to the left for any lines
if (cx == 0) {
if (slot->bitmap_left < 0) {
// figure out max amount of padding we need
leftPadding = std::max(leftPadding, -slot->bitmap_left);
response->leftPadding = std::max(response->leftPadding, -slot->bitmap_left);
}
}
// manual request to wrap (new line)
//std::cout << "char " << request.text[i] << " codepoint: " << glyphInfo[i].codepoint << std::endl;
if (request.text[i] == '\n' || request.text[i] == '\r'){
//std::cout << "new line|return" << std::endl;
response->wrapped = true;
if (request.noWrap) {
glyphCount = i;
// we're done
std::cout << "TextRasterizer::rasterize - newline found no wrap is on" << std::endl;
break;
} else {
xmax=std::max(xmax, cx);
cx = response->wrapToX;
cy -= std::ceil(1.2f * fontSize); // 1.2 scalar from https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
response->lines++;
lineXStart = response->wrapToX; // change where we start
// don't add this character
continue;
}
}
@ -125,12 +154,12 @@ std::unique_ptr<std::pair<int, int>> TextRasterizer::size(const rasterizationReq @@ -125,12 +154,12 @@ std::unique_ptr<std::pair<int, int>> TextRasterizer::size(const rasterizationReq
} else {
//std::cout << "multine text: [" << text << "] new line:" << cy << " x: " << (int)x << "+ cx:" << (int)cx << std::endl;
//std::cout << "line #" << lines << " starts at " << lineXStart << " ends at " << lineXStart + cx << std::endl;
xmax = request.availableWidth - wrapToX; // the whole width of parent to the edge of windowWidth
xmax = request.availableWidth - response->wrapToX; // the whole width of parent to the edge of windowWidth
//std::cout << "new width: " << xmax << std::endl;
cx = wrapToX; // wrapToX (was 0) (was -= xmax)
cx = response->wrapToX; // wrapToX (was 0) (was -= xmax)
cy -= std::ceil(1.2f * fontSize); // 1.2 scalar from https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
lines++;
lineXStart = wrapToX; // change where we start
response->lines++;
lineXStart = response->wrapToX; // change where we start
}
}
@ -142,33 +171,43 @@ std::unique_ptr<std::pair<int, int>> TextRasterizer::size(const rasterizationReq @@ -142,33 +171,43 @@ std::unique_ptr<std::pair<int, int>> TextRasterizer::size(const rasterizationReq
// update glyph maxes
const FT_Bitmap ftBitmap = slot->bitmap;
const float yo = static_cast<float>(glyphPos[i].y_offset) / 64;
int y0 = static_cast<int>(floor(yo + slot->bitmap_top));
//const float yo = static_cast<float>(glyphPos[i].y_offset) / 64;
//int y0 = static_cast<int>(floor(yo + slot->bitmap_top));
int y1 = y0 + static_cast<int>(ftBitmap.rows);
y0max=std::max(y0max, y0);
response->y0max = std::max(response->y0max, y0);
y1max=std::max(y1max, y1);
// track new max width
xmax=std::max(xmax, cx);
}
if (leftPadding) {
xmax+=leftPadding; // increase width;
if (response->leftPadding) {
xmax += response->leftPadding; // increase width;
}
// at least one line
cy -= std::ceil(1.2f * fontSize); // 1.2 scalar from https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
response->height = -cy;
response->width = xmax;
//std::cout << "lines: " << lines << " wrapToX: " << wrapToX << " startX: " << x << " xmax: " << xmax << std::endl;
//std::cout << "y1max: " << y1max << " lines: " << lines << std::endl;
y1max *= lines;
if (response->y0max != maxy0) {
std::cout << "TextRasterizer::size - resp.y0max: " << response->y0max << " maxy0: " << maxy0 << std::endl;
}
//std::cout << "y1max: " << y1max << " lines: " << response->lines << std::endl;
int textureHeight = (y1max - response->y0max) * response->lines;
//int textureHeight = y1max * response->lines;
//y1max *= response->lines;
//std::cout << "initial:" << (int)width << "x" << (int)height << std::endl;
if (response->height < y1max) {
response->height = y1max;
if (response->height < textureHeight) {
response->height = textureHeight;
//std::cout << "adjusted:" << (int)width << "x" << (int)height << std::endl;
}
response->endingX = cx - request.sourceStartX;
response->endingY = cy + 2 + request.sourceStartY;
// FIXME: how about endingX,Y?
return std::make_unique<std::pair<int, int>>(std::pair<int, int>(response->width, response->height));
//return std::make_unique<std::pair<int, int>>(std::pair<int, int>(response->width, response->height));
return response;
}
#include <GL/glew.h>
@ -206,100 +245,12 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza @@ -206,100 +245,12 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza
const hb_glyph_position_t *glyphPos = hb_buffer_get_glyph_positions(buffer, &glyphCount);
std::unique_ptr<rasterizationResponse> response = std::make_unique<rasterizationResponse>();
std::unique_ptr<sizeResponse> sizeResponse = this->size(request);
// figure out width/height
int cx = 0;
int cy = 0;
int xmax = 0;
int y0max = 0, y1max = 0;
int lines = 1;
response->wrapped = false;
int lineXStart = request.startX;
int leftPadding = 0;
int wrapToX = 0;
for (unsigned int i = 0; i < glyphCount; i++) {
if (FT_Load_Glyph(*face, glyphInfo[i].codepoint, FT_LOAD_DEFAULT)) {
std::cout << "Could not load glyph" << std::endl;
return nullptr;
}
const FT_GlyphSlot slot = (*face)->glyph;
if (FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL)) {
std::cout << "Could not render glyph" << std::endl;
return nullptr;
}
// how much space does this character take
const float xa = static_cast<float>(glyphPos[i].x_advance) / 64;
const float ya = static_cast<float>(glyphPos[i].y_advance) / 64; //mostly 0s
// do we need to padding the texture to the left for any lines
if (cx == 0) {
if (slot->bitmap_left < 0) {
// figure out max amount of padding we need
leftPadding = std::max(leftPadding, -slot->bitmap_left);
}
}
// wrap to next line on width
if ((cx + lineXStart) - request.sourceStartX >= request.availableWidth) {
response->wrapped = true;
if (request.noWrap) {
std::cout << "TextRasterizer::rasterize - we've hit wrap & noWrap at " << cx << " + " << lineXStart << " < " << request.availableWidth << std::endl;
// we can only fit partial of the last char
std::cout << "TextRasterizer::rasterize - truncating " << glyphCount << " char(s) to " << i << " char(s)" << std::endl;
glyphCount = i;
// we're done
break;
} else {
//std::cout << "multine text: [" << text << "] new line:" << cy << " x: " << (int)x << "+ cx:" << (int)cx << std::endl;
//std::cout << "line #" << lines << " starts at " << lineXStart << " ends at " << lineXStart + cx << std::endl;
xmax = request.availableWidth - wrapToX; // the whole width of parent to the edge of windowWidth
//std::cout << "new width: " << xmax << std::endl;
cx = wrapToX; // wrapToX (was 0) (was -= xmax)
cy -= std::ceil(1.2f * fontSize); // 1.2 scalar from https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
lines++;
lineXStart = wrapToX; // change where we start
}
}
//std::cout << "glyph:" << xa << "x" << ya << std::endl;
// update glyph space allocation
cx += xa;
cy += ya; // is normal for y0 at bottom
// update glyph maxes
const FT_Bitmap ftBitmap = slot->bitmap;
const float yo = static_cast<float>(glyphPos[i].y_offset) / 64;
int y0 = static_cast<int>(floor(yo + slot->bitmap_top));
int y1 = y0 + static_cast<int>(ftBitmap.rows);
y0max=std::max(y0max, y0);
y1max=std::max(y1max, y1);
// track new max width
xmax=std::max(xmax, cx);
}
//std::cout << "TextRasterizer::rasterize - xmax exits loop at " << xmax << std::endl;
if (leftPadding) {
//std::cout << "TextRasterizer::rasterize - leftPadding " << leftPadding << std::endl;
xmax += leftPadding; // increase width;
}
// at least one line
cy -= std::ceil(1.2f * fontSize); // 1.2 scalar from https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
//std::cout << "TextRasterizer::rasterize - initial width " << xmax << std::endl;
response->width = xmax;
response->height = -cy;
//std::cout << "lines: " << lines << " wrapToX: " << wrapToX << " startX: " << x << " xmax: " << xmax << std::endl;
//std::cout << "y1max: " << y1max << " lines: " << lines << std::endl;
y1max *= lines;
//std::cout << "initial:" << (int)width << "x" << (int)height << std::endl;
if (response->height < y1max) {
response->height = y1max;
//std::cout << "adjusted:" << (int)width << "x" << (int)height << std::endl;
}
response->width = sizeResponse->width;
response->height = sizeResponse->height;
//std::cout << "after adjust:" << (int)response->width << "x" << (int)response->height << " lines" << lines << std::endl;
// adjust sourceStart
//std::cout << "TextRasterizer::rasterize - adjust sourceStart: " << request.sourceStartX << "," << request.sourceStartY << std::endl;
response->width -= request.sourceStartX;
@ -324,9 +275,9 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza @@ -324,9 +275,9 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza
}
// translation information
response->x0 = -leftPadding; // wrap to element start (wrapToX (0) or x)
response->x0 = -sizeResponse->leftPadding; // wrap to element start (wrapToX (0) or x)
response->y0 = 0;
response->x1 = -leftPadding + response->width;
response->x1 = -sizeResponse->leftPadding + response->width;
response->y1 = -response->height;
//std::cout << "xd: " << static_cast<int>(response->x1-response->x0) << " yd: " << static_cast<int>(response->y0-response->y1) << std::endl;
@ -345,8 +296,8 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza @@ -345,8 +296,8 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza
// copy all glyphs into one single glyph
// still neds to start at X
cx = response->wrapped ? request.startX : 0; // reset
cy = 0;
int cx = response->wrapped ? request.startX : 0; // reset
int cy = 0;
//std::cout << "[" << request.text << "] wrapped? " << response->wrapped << " starting at: " << cx << std::endl;
//int miny0 = 99;
int maxy0 = 0;
@ -371,11 +322,26 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza @@ -371,11 +322,26 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza
//miny0 = std::min(y0, miny0);
maxy0 = std::max(y0, maxy0);
int bump = y0max - y0; // Y adjust for this glyph
int bump = sizeResponse->y0max - y0; // Y adjust for this glyph
const float xa = static_cast<float>(glyphPos[i].x_advance) / 64;
if (request.text[i] == '\n' || request.text[i] == '\r'){
//std::cout << "new line" << std::endl;
if (request.noWrap) {
// we're done
//std::cout << "TextRasterize::rasterize - noWrap on, ending" << std::endl;
break;
} else {
cx = sizeResponse->wrapToX;
cy += std::ceil(1.2f * fontSize); // 1.2 scalar from https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
// no need to write new line char
continue;
}
}
// if this char is too width for this line, advance to next line
if (!request.noWrap && cx + xa >= request.availableWidth) {
cx = wrapToX;
cx = sizeResponse->wrapToX;
cy += std::ceil(1.2f * fontSize);// 1.2 scalar from https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
//std::cout << "textWrap - cx reset to: " << cx << " cy is now: " << cy << std::endl;
}
@ -386,13 +352,20 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza @@ -386,13 +352,20 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza
cx += xa;
continue;
}
if (cy < request.sourceStartY) {
// skip ahead
// seems to just an optimization
//std::cout << "cy: " << cy << " < sourceStartY: " << request.sourceStartY << std::endl;
continue;
}
//std::cout << "Writing " << request.text[i] << " to " << cx << ", " << cy << std::endl;
// place glyph bitmap data into texture
for (unsigned int iy = 0; iy < ftBitmap.rows; iy++) { // line by line
// source is 0 to (0:iy:rows)
// dest is cx+bl, (0:iy:rows)+(0:cy:height)+bump
//std::cout << "placing glyph row at " << (cx + slot->bitmap_left) << "x" << ((iy + cy) + bump) << std::endl;
unsigned int destPos = static_cast<unsigned int>(cx - request.sourceStartX + leftPadding + slot->bitmap_left) + ((iy + static_cast<unsigned int>(cy - request.sourceStartY)) + static_cast<unsigned int>(bump)) * response->textureWidth;
unsigned int destPos = static_cast<unsigned int>(cx - request.sourceStartX + sizeResponse->leftPadding + slot->bitmap_left) + ((iy + static_cast<unsigned int>(cy - request.sourceStartY)) + static_cast<unsigned int>(bump)) * response->textureWidth;
if (destPos >= size) {
// we're done with this line
continue;
@ -405,8 +378,9 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza @@ -405,8 +378,9 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza
continue;
}
//std::cout << "putting:" << (int)src[ix] << " over " << (int)dest[ix] << std::endl;
if (src[ix] && src[ix]>dest[ix]) {
dest[ix]=src[ix];
// probably could be or'd
if (src[ix] && src[ix] > dest[ix]) {
dest[ix] = src[ix];
}
}
}

16
src/graphics/text/TextRasterizer.h

@ -37,12 +37,26 @@ struct rasterizationRequest { @@ -37,12 +37,26 @@ struct rasterizationRequest {
int startX; // starting x point (relative to 0) this is currently
//int wrapToX; // next line starts at X (was always 0)
// scrolling basically:
int sourceStartX = 0; // start reading text source at and place at destination 0
int sourceStartY = 0;
bool noWrap = false; // different than overflow but related
unsigned int maxTextureSize = 0;
};
struct sizeResponse {
float width;
float height;
int glyphCount;
int endingX;
int endingY;
bool wrapped;
int leftPadding = 0;
int y0max = 0;
int wrapToX = 0;
unsigned int lines = 1;
};
struct rasterizationResponse {
float width;
float height;
@ -71,7 +85,7 @@ public: @@ -71,7 +85,7 @@ public:
TextRasterizer(const std::string &fontPath, const int size, const unsigned int resolution, const bool bold);
~TextRasterizer();
//std::unique_ptr<Glyph[]> rasterize(const std::string &text, const int x, const int windowWidth, const int wrapToX, float &width, float &height, unsigned int &glyphCount, int &endingX, int &endingY, bool &wrapped) const;
std::unique_ptr<std::pair<int, int>> size(const rasterizationRequest &request) const;
std::unique_ptr<sizeResponse> size(const rasterizationRequest &request) const;
std::unique_ptr<rasterizationResponse> rasterize(const rasterizationRequest &request) const;
bool isUnicodeBMP(const FT_Face &face) const;
FT_Library lib;

Loading…
Cancel
Save