Added per-character color support to love.graphics.print/printf and Text objects. Resolves issue #865.

The aforementioned functions now optionally accept an array instead of a plain string. The array is in the format of: {{r, g, b [, a]}, "first colored text, ", {r, g, b [, a]}, "second colored text", ...}, where the color values specify the color to use in the next section of the text.
This commit is contained in:
Alex Szpakowski
2015-11-01 23:17:46 -04:00
parent 799e303673
commit 389b91cf6f
9 changed files with 399 additions and 195 deletions
+237 -127
View File
@@ -38,6 +38,11 @@ namespace graphics
namespace opengl namespace opengl
{ {
static inline uint16 normToUint16(double n)
{
return (uint16) (n * LOVE_UINT16_MAX);
}
int Font::fontCount = 0; int Font::fontCount = 0;
Font::Font(love::font::Rasterizer *r, const Texture::Filter &filter) Font::Font(love::font::Rasterizer *r, const Texture::Filter &filter)
@@ -272,18 +277,20 @@ const Font::Glyph &Font::addGlyph(uint32 glyph)
g.texture = t; g.texture = t;
float tX = (float) textureX, tY = (float) textureY; double tX = (double) textureX, tY = (double) textureY;
float tWidth = (float) textureWidth, tHeight = (float) textureHeight; double tWidth = (double) textureWidth, tHeight = (double) textureHeight;
Color c(255, 255, 255, 255);
// 0----2 // 0----2
// | / | // | / |
// | / | // | / |
// 1----3 // 1----3
const GlyphVertex verts[4] = { const GlyphVertex verts[4] = {
{ 0.0f, 0.0f, tX/tWidth, tY/tHeight}, {float(0), float(0), normToUint16((tX+0)/tWidth), normToUint16((tY+0)/tHeight), c},
{ 0.0f, float(h), tX/tWidth, (tY+h)/tHeight}, {float(0), float(h), normToUint16((tX+0)/tWidth), normToUint16((tY+h)/tHeight), c},
{float(w), 0.0f, (tX+w)/tWidth, tY/tHeight}, {float(w), float(0), normToUint16((tX+w)/tWidth), normToUint16((tY+0)/tHeight), c},
{float(w), float(h), (tX+w)/tWidth, (tY+h)/tHeight} {float(w), float(h), normToUint16((tX+w)/tWidth), normToUint16((tY+h)/tHeight), c}
}; };
// Copy vertex data to the glyph and set proper bearing. // Copy vertex data to the glyph and set proper bearing.
@@ -341,7 +348,7 @@ float Font::getKerning(uint32 leftglyph, uint32 rightglyph)
return k; return k;
} }
void Font::codepointsFromString(const std::string &text, Codepoints &codepoints) void Font::getCodepointsFromString(const std::string &text, Codepoints &codepoints)
{ {
codepoints.reserve(text.size()); codepoints.reserve(text.size());
@@ -362,12 +369,36 @@ void Font::codepointsFromString(const std::string &text, Codepoints &codepoints)
} }
} }
void Font::getCodepointsFromString(const std::vector<ColoredString> &strs, ColoredCodepoints &codepoints)
{
if (strs.empty())
return;
codepoints.cps.reserve(strs[0].str.size());
for (const ColoredString &cstr : strs)
{
IndexedColor c = {cstr.color, (int) codepoints.cps.size()};
codepoints.colors.push_back(c);
getCodepointsFromString(cstr.str, codepoints.cps);
}
if (codepoints.colors.size() == 1)
{
IndexedColor c = codepoints.colors[0];
if (c.index == 0 && c.color == Color(255, 255, 255, 255))
codepoints.colors.pop_back();
}
}
float Font::getHeight() const float Font::getHeight() const
{ {
return (float) height; return (float) height;
} }
std::vector<Font::DrawCommand> Font::generateVertices(const Codepoints &codepoints, std::vector<GlyphVertex> &vertices, float extra_spacing, Vector offset, TextInfo *info) Font::DrawCommands Font::generateVertices(const ColoredCodepoints &codepoints, std::vector<GlyphVertex> &vertices, float extra_spacing, Vector offset, TextInfo *info)
{ {
// Spacing counter and newline handling. // Spacing counter and newline handling.
float dx = offset.x; float dx = offset.x;
@@ -377,17 +408,29 @@ std::vector<Font::DrawCommand> Font::generateVertices(const Codepoints &codepoin
int maxwidth = 0; int maxwidth = 0;
// Keeps track of when we need to switch textures in our vertex array. // Keeps track of when we need to switch textures in our vertex array.
std::vector<DrawCommand> drawcommands; DrawCommands drawcmds;
// Pre-allocate space for the maximum possible number of vertices. // Pre-allocate space for the maximum possible number of vertices.
size_t vertstartsize = vertices.size(); size_t vertstartsize = vertices.size();
vertices.reserve(vertstartsize + codepoints.size()); vertices.reserve(vertstartsize + codepoints.cps.size() * 4);
uint32 prevglyph = 0; uint32 prevglyph = 0;
for (int i = 0; i < (int) codepoints.size(); i++) Color curcolor(255, 255, 255, 255);
int curcolori = -1;
int ncolors = (int) codepoints.colors.size();
if (ncolors == 0 || (ncolors == 1 && codepoints.colors[0].color == curcolor))
drawcmds.usecolors = false;
else
drawcmds.usecolors = true;
for (int i = 0; i < (int) codepoints.cps.size(); i++)
{ {
uint32 g = codepoints[i]; uint32 g = codepoints.cps[i];
if (curcolori + 1 < ncolors && codepoints.colors[curcolori + 1].index == i)
curcolor = codepoints.colors[++curcolori].color;
if (g == '\n') if (g == '\n')
{ {
@@ -411,9 +454,11 @@ std::vector<Font::DrawCommand> Font::generateVertices(const Codepoints &codepoin
maxwidth = 0; maxwidth = 0;
dx = offset.x; dx = offset.x;
dy = offset.y; dy = offset.y;
drawcommands.clear(); drawcmds.commands.clear();
vertices.resize(vertstartsize); vertices.resize(vertstartsize);
prevglyph = 0; prevglyph = 0;
curcolori = -1;
curcolor = Color(255, 255, 255, 255);
continue; continue;
} }
@@ -422,26 +467,27 @@ std::vector<Font::DrawCommand> Font::generateVertices(const Codepoints &codepoin
if (glyph.texture != 0) if (glyph.texture != 0)
{ {
// Copy the vertices and set their proper relative positions. // Copy the vertices and set their colors and relative positions.
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
vertices.push_back(glyph.vertices[j]); vertices.push_back(glyph.vertices[j]);
vertices.back().x += dx; vertices.back().x += dx;
vertices.back().y += dy + lineheight; vertices.back().y += dy + lineheight;
vertices.back().color = curcolor;
} }
// Check if glyph texture has changed since the last iteration. // Check if glyph texture has changed since the last iteration.
if (drawcommands.empty() || drawcommands.back().texture != glyph.texture) if (drawcmds.commands.empty() || drawcmds.commands.back().texture != glyph.texture)
{ {
// Add a new draw command if the texture has changed. // Add a new draw command if the texture has changed.
DrawCommand cmd; DrawCommand cmd;
cmd.startvertex = (int) vertices.size() - 4; cmd.startvertex = (int) vertices.size() - 4;
cmd.vertexcount = 0; cmd.vertexcount = 0;
cmd.texture = glyph.texture; cmd.texture = glyph.texture;
drawcommands.push_back(cmd); drawcmds.commands.push_back(cmd);
} }
drawcommands.back().vertexcount += 4; drawcmds.commands.back().vertexcount += 4;
} }
// Advance the x position for the next glyph. // Advance the x position for the next glyph.
@@ -464,7 +510,7 @@ std::vector<Font::DrawCommand> Font::generateVertices(const Codepoints &codepoin
return a.startvertex < b.startvertex; return a.startvertex < b.startvertex;
}; };
std::sort(drawcommands.begin(), drawcommands.end(), drawsort); std::sort(drawcmds.commands.begin(), drawcmds.commands.end(), drawsort);
if (dx > maxwidth) if (dx > maxwidth)
maxwidth = (int) dx; maxwidth = (int) dx;
@@ -475,28 +521,28 @@ std::vector<Font::DrawCommand> Font::generateVertices(const Codepoints &codepoin
info->height = (int) dy + (dx > 0.0f ? floorf(getHeight() * getLineHeight() + 0.5f) : 0) - offset.y; info->height = (int) dy + (dx > 0.0f ? floorf(getHeight() * getLineHeight() + 0.5f) : 0) - offset.y;
} }
return drawcommands; return drawcmds;
} }
std::vector<Font::DrawCommand> Font::generateVertices(const std::string &text, std::vector<GlyphVertex> &vertices, float extra_spacing, Vector offset, TextInfo *info) Font::DrawCommands Font::generateVertices(const std::string &text, std::vector<GlyphVertex> &vertices, float extra_spacing, Vector offset, TextInfo *info)
{ {
Codepoints codepoints; ColoredCodepoints codepoints;
codepointsFromString(text, codepoints); getCodepointsFromString(text, codepoints.cps);
return generateVertices(codepoints, vertices, extra_spacing, offset, info); return generateVertices(codepoints, vertices, extra_spacing, offset, info);
} }
std::vector<Font::DrawCommand> Font::generateVerticesFormatted(const std::string &text, float wrap, AlignMode align, std::vector<GlyphVertex> &vertices, TextInfo *info) Font::DrawCommands Font::generateVerticesFormatted(const ColoredCodepoints &text, float wrap, AlignMode align, std::vector<GlyphVertex> &vertices, TextInfo *info)
{ {
wrap = std::max(wrap, 0.0f); wrap = std::max(wrap, 0.0f);
uint32 cacheid = textureCacheID; uint32 cacheid = textureCacheID;
std::vector<DrawCommand> drawcommands; DrawCommands drawcmds;
vertices.reserve(text.length() * 4); vertices.reserve(text.cps.size() * 4);
std::vector<int> widths; std::vector<int> widths;
std::vector<Codepoints> lines; std::vector<ColoredCodepoints> lines;
getWrap(text, wrap, lines, &widths); getWrap(text, wrap, lines, &widths);
@@ -523,7 +569,7 @@ std::vector<Font::DrawCommand> Font::generateVerticesFormatted(const std::string
break; break;
case ALIGN_JUSTIFY: case ALIGN_JUSTIFY:
{ {
float numspaces = (float) std::count(line.begin(), line.end(), ' '); float numspaces = (float) std::count(line.cps.begin(), line.cps.end(), ' ');
if (width < wrap && numspaces >= 1) if (width < wrap && numspaces >= 1)
extraspacing = (wrap - width) / numspaces; extraspacing = (wrap - width) / numspaces;
else else
@@ -535,27 +581,29 @@ std::vector<Font::DrawCommand> Font::generateVerticesFormatted(const std::string
break; break;
} }
std::vector<DrawCommand> commands = generateVertices(line, vertices, extraspacing, offset); DrawCommands cmds = generateVertices(line, vertices, extraspacing, offset);
if (!commands.empty()) if (!cmds.commands.empty())
{ {
auto firstcmd = commands.begin(); auto firstcmd = cmds.commands.begin();
// If the first draw command in the new list has the same texture // If the first draw command in the new list has the same texture
// as the last one in the existing list we're building and its // as the last one in the existing list we're building and its
// vertices are in-order, we can combine them (saving a draw call.) // vertices are in-order, we can combine them (saving a draw call.)
if (!drawcommands.empty()) if (!drawcmds.commands.empty())
{ {
auto prevcmd = drawcommands.back(); auto prevcmd = drawcmds.commands.back();
if (prevcmd.texture == firstcmd->texture && (prevcmd.startvertex + prevcmd.vertexcount) == firstcmd->startvertex) if (prevcmd.texture == firstcmd->texture && (prevcmd.startvertex + prevcmd.vertexcount) == firstcmd->startvertex)
{ {
drawcommands.back().vertexcount += firstcmd->vertexcount; drawcmds.commands.back().vertexcount += firstcmd->vertexcount;
++firstcmd; ++firstcmd;
} }
} }
// Append the new draw commands to the list we're building. // Append the new draw commands to the list we're building.
drawcommands.insert(drawcommands.end(), firstcmd, commands.end()); drawcmds.commands.insert(drawcmds.commands.end(), firstcmd, cmds.commands.end());
drawcmds.usecolors = drawcmds.usecolors || cmds.usecolors;
} }
y += getHeight() * getLineHeight(); y += getHeight() * getLineHeight();
@@ -570,19 +618,19 @@ std::vector<Font::DrawCommand> Font::generateVerticesFormatted(const std::string
if (cacheid != textureCacheID) if (cacheid != textureCacheID)
{ {
vertices.clear(); vertices.clear();
drawcommands = generateVerticesFormatted(text, wrap, align, vertices); drawcmds = generateVerticesFormatted(text, wrap, align, vertices);
} }
return drawcommands; return drawcmds;
} }
void Font::drawVertices(const std::vector<DrawCommand> &drawcommands) void Font::drawVertices(const DrawCommands &drawcommands)
{ {
// Vertex attribute pointers need to be set before calling this function. // Vertex attribute pointers need to be set before calling this function.
// This assumes that the attribute pointers are constant for all vertices. // This assumes that the attribute pointers are constant for all vertices.
int totalverts = 0; int totalverts = 0;
for (const DrawCommand &cmd : drawcommands) for (const DrawCommand &cmd : drawcommands.commands)
totalverts = std::max(cmd.startvertex + cmd.vertexcount, totalverts); totalverts = std::max(cmd.startvertex + cmd.vertexcount, totalverts);
if ((size_t) totalverts / 4 > quadIndices.getSize()) if ((size_t) totalverts / 4 > quadIndices.getSize())
@@ -597,7 +645,7 @@ void Font::drawVertices(const std::vector<DrawCommand> &drawcommands)
// We need a separate draw call for every section of the text which uses a // We need a separate draw call for every section of the text which uses a
// different texture than the previous section. // different texture than the previous section.
for (const DrawCommand &cmd : drawcommands) for (const DrawCommand &cmd : drawcommands.commands)
{ {
GLsizei count = (cmd.vertexcount / 4) * 6; GLsizei count = (cmd.vertexcount / 4) * 6;
size_t offset = (cmd.startvertex / 4) * 6 * elemsize; size_t offset = (cmd.startvertex / 4) * 6 * elemsize;
@@ -608,9 +656,9 @@ void Font::drawVertices(const std::vector<DrawCommand> &drawcommands)
} }
} }
void Font::printv(const Matrix4 &t, const std::vector<DrawCommand> &drawcommands, const std::vector<GlyphVertex> &vertices) void Font::printv(const Matrix4 &t, const DrawCommands &drawcommands, const std::vector<GlyphVertex> &vertices)
{ {
if (vertices.empty() || drawcommands.empty()) if (vertices.empty() || drawcommands.commands.empty())
return; return;
OpenGL::TempDebugGroup debuggroup("Font print"); OpenGL::TempDebugGroup debuggroup("Font print");
@@ -618,28 +666,42 @@ void Font::printv(const Matrix4 &t, const std::vector<DrawCommand> &drawcommands
OpenGL::TempTransform transform(gl); OpenGL::TempTransform transform(gl);
transform.get() *= t; transform.get() *= t;
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(GlyphVertex), &vertices[0].x); glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(GlyphVertex), &vertices[0].x);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(GlyphVertex), &vertices[0].s); glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(GlyphVertex), &vertices[0].s);
uint32 enabledattribs = ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD;
if (drawcommands.usecolors)
{
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(GlyphVertex), &vertices[0].color.r);
enabledattribs |= ATTRIBFLAG_COLOR;
}
gl.useVertexAttribArrays(enabledattribs);
drawVertices(drawcommands); drawVertices(drawcommands);
} }
void Font::print(const std::string &text, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) void Font::print(const std::vector<ColoredString> &text, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
ColoredCodepoints codepoints;
getCodepointsFromString(text, codepoints);
std::vector<GlyphVertex> vertices; std::vector<GlyphVertex> vertices;
std::vector<DrawCommand> drawcommands = generateVertices(text, vertices); DrawCommands drawcommands = generateVertices(codepoints, vertices);
Matrix4 t(x, y, angle, sx, sy, ox, oy, kx, ky); Matrix4 t(x, y, angle, sx, sy, ox, oy, kx, ky);
printv(t, drawcommands, vertices); printv(t, drawcommands, vertices);
} }
void Font::printf(const std::string &text, float x, float y, float wrap, AlignMode align, float angle, float sx, float sy, float ox, float oy, float kx, float ky) void Font::printf(const std::vector<ColoredString> &text, float x, float y, float wrap, AlignMode align, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
ColoredCodepoints codepoints;
getCodepointsFromString(text, codepoints);
std::vector<GlyphVertex> vertices; std::vector<GlyphVertex> vertices;
std::vector<DrawCommand> drawcommands = generateVerticesFormatted(text, wrap, align, vertices); DrawCommands drawcommands = generateVerticesFormatted(codepoints, wrap, align, vertices);
Matrix4 t(x, y, angle, sx, sy, ox, oy, kx, ky); Matrix4 t(x, y, angle, sx, sy, ox, oy, kx, ky);
@@ -690,104 +752,149 @@ int Font::getWidth(char character)
return g.spacing; return g.spacing;
} }
void Font::getWrap(const std::string &text, float wraplimit, std::vector<Codepoints> &lines, std::vector<int> *linewidths) void Font::getWrap(const ColoredCodepoints &codepoints, float wraplimit, std::vector<ColoredCodepoints> &lines, std::vector<int> *linewidths)
{ {
// Split text at newlines. // Per-line info.
std::string line; float width = 0.0f;
std::istringstream iss(text); float widthbeforelastspace = 0.0f;
float widthoftrailingspace = 0.0f;
uint32 prevglyph = 0;
int lastspaceindex = -1;
// Keeping the indexed colors "in sync" is a bit tricky, since we split
// things up and we might skip some glyphs but we don't want to skip any
// color which starts at those indices.
Color curcolor(255, 255, 255, 255);
bool addcurcolor = false;
int curcolori = -1;
int endcolori = (int) codepoints.colors.size() - 1;
// A wrapped line of text. // A wrapped line of text.
Codepoints wline; ColoredCodepoints wline;
while (std::getline(iss, line, '\n')) int i = 0;
while (i < (int) codepoints.cps.size())
{ {
float width = 0.0f; uint32 c = codepoints.cps[i];
float widthbeforelastspace = 0.0f;
float widthoftrailingspace = 0.0f;
uint32 prevglyph = 0;
wline.clear(); // Determine the current color before doing anything else, to make sure
wline.reserve(line.length()); // it's still applied to future glyphs even if this one is skipped.
if (curcolori < endcolori && codepoints.colors[curcolori + 1].index == i)
try
{ {
utf8::iterator<std::string::const_iterator> i(line.begin(), line.begin(), line.end()); curcolor = codepoints.colors[curcolori + 1].color;
utf8::iterator<std::string::const_iterator> end(line.end(), line.begin(), line.end()); curcolori++;
addcurcolor = true;
}
utf8::iterator<std::string::const_iterator> lastspaceit = end; // Split text at newlines.
if (c == '\n')
{
lines.push_back(wline);
while (i != end) // Ignore the width of any trailing spaces, for individual lines.
if (linewidths)
linewidths->push_back(width - widthoftrailingspace);
// Make sure the new line keeps any color that was set previously.
addcurcolor = true;
width = widthbeforelastspace = widthoftrailingspace = 0.0f;
prevglyph = 0; // Reset kerning information.
lastspaceindex = -1;
wline.cps.clear();
wline.colors.clear();
i++;
continue;
}
const Glyph &g = findGlyph(c);
float charwidth = g.spacing + getKerning(prevglyph, c);
float newwidth = width + charwidth;
// Wrap the line if it exceeds the wrap limit. Don't wrap yet if we're
// processing a newline character, though.
if (c != ' ' && newwidth > wraplimit)
{
// If this is the first character in the line and it exceeds the
// limit, skip it completely.
if (wline.cps.empty())
i++;
else if (lastspaceindex != -1)
{ {
uint32 c = *i; // 'Rewind' to the last seen space, if the line has one.
// FIXME: This could be more efficient...
while (!wline.cps.empty() && wline.cps.back() != ' ')
wline.cps.pop_back();
const Glyph &g = findGlyph(c); while (!wline.colors.empty() && wline.colors.back().index >= (int) wline.cps.size())
float charwidth = g.spacing + getKerning(prevglyph, c); wline.colors.pop_back();
float newwidth = width + charwidth;
// Wrap the line if it exceeds the wrap limit. Don't wrap yet if // Also 'rewind' to the color that the last character is using.
// we're processing a newline character, though. for (int colori = curcolori; colori >= 0; colori--)
if (c != ' ' && newwidth > wraplimit)
{ {
// If this is the first character in the line and it exceeds if (codepoints.colors[colori].index <= lastspaceindex)
// the limit, skip it completely.
if (wline.empty())
++i;
else if (lastspaceit != end)
{ {
// 'Rewind' to the last seen space, if the line has one. curcolor = codepoints.colors[colori].color;
// FIXME: This should preferably use vector::erase. curcolori = colori;
while (!wline.empty() && wline.back() != ' ') break;
wline.pop_back();
// Ignore the width of trailing spaces in wrapped lines.
width = widthbeforelastspace;
i = lastspaceit;
++i; // Start the next line after the space.
} }
lines.push_back(wline);
if (linewidths)
linewidths->push_back(width);
prevglyph = 0; // Reset kerning information.
width = widthbeforelastspace = widthoftrailingspace = 0.0f;
wline.clear();
lastspaceit = end;
continue;
} }
if (prevglyph != ' ' && c == ' ') // Ignore the width of trailing spaces in wrapped lines.
widthbeforelastspace = width; width = widthbeforelastspace;
width = newwidth; i = lastspaceindex;
prevglyph = c; i++; // Start the next line after the space.
wline.push_back(c);
// Keep track of the last seen space, so we can "rewind" to it
// when wrapping.
if (c == ' ')
{
lastspaceit = i;
widthoftrailingspace += charwidth;
}
else if (c != '\n')
widthoftrailingspace = 0.0f;
++i;
} }
lines.push_back(wline);
if (linewidths)
linewidths->push_back(width);
addcurcolor = true;
prevglyph = 0;
width = widthbeforelastspace = widthoftrailingspace = 0.0f;
wline.cps.clear();
wline.colors.clear();
lastspaceindex = -1;
continue;
} }
catch (utf8::exception &e)
if (prevglyph != ' ' && c == ' ')
widthbeforelastspace = width;
width = newwidth;
prevglyph = c;
if (addcurcolor)
{ {
throw love::Exception("UTF-8 decoding error: %s", e.what()); wline.colors.push_back({curcolor, (int) wline.cps.size()});
addcurcolor = false;
} }
// Remove trailing newlines. wline.cps.push_back(c);
if (!wline.empty() && wline.back() == '\n')
wline.pop_back();
// Keep track of the last seen space, so we can "rewind" to it when
// wrapping.
if (c == ' ')
{
lastspaceindex = i;
widthoftrailingspace += charwidth;
}
else if (c != '\n')
widthoftrailingspace = 0.0f;
i++;
}
// Push the last line.
if (!wline.cps.empty())
{
lines.push_back(wline); lines.push_back(wline);
// Ignore the width of any trailing spaces, for individual lines. // Ignore the width of any trailing spaces, for individual lines.
@@ -798,17 +905,20 @@ void Font::getWrap(const std::string &text, float wraplimit, std::vector<Codepoi
void Font::getWrap(const std::string &text, float wraplimit, std::vector<std::string> &lines, std::vector<int> *linewidths) void Font::getWrap(const std::string &text, float wraplimit, std::vector<std::string> &lines, std::vector<int> *linewidths)
{ {
std::vector<Codepoints> codepointlines; ColoredCodepoints codepoints;
getWrap(text, wraplimit, codepointlines, linewidths); getCodepointsFromString(text, codepoints.cps);
std::vector<ColoredCodepoints> codepointlines;
getWrap(codepoints, wraplimit, codepointlines, linewidths);
std::string line; std::string line;
for (const Codepoints &codepoints : codepointlines) for (const ColoredCodepoints &codepoints : codepointlines)
{ {
line.clear(); line.clear();
line.reserve(codepoints.size()); line.reserve(codepoints.cps.size());
for (uint32 codepoint : codepoints) for (uint32 codepoint : codepoints.cps)
{ {
char character[5] = {'\0'}; char character[5] = {'\0'};
char *end = utf8::unchecked::append(codepoint, character); char *end = utf8::unchecked::append(codepoint, character);
+38 -11
View File
@@ -61,10 +61,29 @@ public:
ALIGN_MAX_ENUM ALIGN_MAX_ENUM
}; };
struct ColoredString
{
std::string str;
Color color;
};
struct IndexedColor
{
Color color;
int index;
};
struct ColoredCodepoints
{
std::vector<uint32> cps;
std::vector<IndexedColor> colors;
};
struct GlyphVertex struct GlyphVertex
{ {
float x, y; float x, y;
float s, t; uint16 s, t;
Color color;
}; };
struct TextInfo struct TextInfo
@@ -81,16 +100,25 @@ public:
int vertexcount; int vertexcount;
}; };
struct DrawCommands
{
std::vector<DrawCommand> commands;
bool usecolors;
};
Font(love::font::Rasterizer *r, const Texture::Filter &filter = Texture::getDefaultFilter()); Font(love::font::Rasterizer *r, const Texture::Filter &filter = Texture::getDefaultFilter());
virtual ~Font(); virtual ~Font();
std::vector<DrawCommand> generateVertices(const Codepoints &str, std::vector<GlyphVertex> &vertices, float extra_spacing = 0.0f, Vector offset = {}, TextInfo *info = nullptr); DrawCommands generateVertices(const ColoredCodepoints &codepoints, std::vector<GlyphVertex> &vertices, float extra_spacing = 0.0f, Vector offset = {}, TextInfo *info = nullptr);
std::vector<DrawCommand> generateVertices(const std::string &text, std::vector<GlyphVertex> &vertices, float extra_spacing = 0.0f, Vector offset = Vector(), TextInfo *info = nullptr); DrawCommands generateVertices(const std::string &text, std::vector<GlyphVertex> &vertices, float extra_spacing = 0.0f, Vector offset = Vector(), TextInfo *info = nullptr);
std::vector<DrawCommand> generateVerticesFormatted(const std::string &text, float wrap, AlignMode align, std::vector<GlyphVertex> &vertices, TextInfo *info = nullptr); DrawCommands generateVerticesFormatted(const ColoredCodepoints &text, float wrap, AlignMode align, std::vector<GlyphVertex> &vertices, TextInfo *info = nullptr);
void drawVertices(const std::vector<DrawCommand> &drawcommands); void drawVertices(const DrawCommands &drawcommands);
static void getCodepointsFromString(const std::string &str, Codepoints &codepoints);
static void getCodepointsFromString(const std::vector<ColoredString> &strs, ColoredCodepoints &codepoints);
/** /**
* Prints the text at the designated position with rotation and scaling. * Prints the text at the designated position with rotation and scaling.
@@ -106,9 +134,9 @@ public:
* @param kx Shear along the x axis. * @param kx Shear along the x axis.
* @param ky Shear along the y axis. * @param ky Shear along the y axis.
**/ **/
void print(const std::string &text, float x, float y, float angle = 0.0f, float sx = 1.0f, float sy = 1.0f, float ox = 0.0f, float oy = 0.0f, float kx = 0.0f, float ky = 0.0f); void print(const std::vector<ColoredString> &text, float x, float y, float angle = 0.0f, float sx = 1.0f, float sy = 1.0f, float ox = 0.0f, float oy = 0.0f, float kx = 0.0f, float ky = 0.0f);
void printf(const std::string &text, float x, float y, float wrap, AlignMode align, float angle = 0.0f, float sx = 1.0f, float sy = 1.0f, float ox = 0.0f, float oy = 0.0f, float kx = 0.0f, float ky = 0.0f); void printf(const std::vector<ColoredString> &text, float x, float y, float wrap, AlignMode align, float angle = 0.0f, float sx = 1.0f, float sy = 1.0f, float ox = 0.0f, float oy = 0.0f, float kx = 0.0f, float ky = 0.0f);
/** /**
* Returns the height of the font. * Returns the height of the font.
@@ -139,7 +167,7 @@ public:
* Returns a vector with the lines. * Returns a vector with the lines.
**/ **/
void getWrap(const std::string &text, float wraplimit, std::vector<std::string> &lines, std::vector<int> *line_widths = nullptr); void getWrap(const std::string &text, float wraplimit, std::vector<std::string> &lines, std::vector<int> *line_widths = nullptr);
void getWrap(const std::string &text, float wraplimit, std::vector<Codepoints> &lines, std::vector<int> *line_widths = nullptr); void getWrap(const ColoredCodepoints &codepoints, float wraplimit, std::vector<ColoredCodepoints> &lines, std::vector<int> *line_widths = nullptr);
/** /**
* Sets the line height (which should be a number to multiply the font size by, * Sets the line height (which should be a number to multiply the font size by,
@@ -205,8 +233,7 @@ private:
const Glyph &addGlyph(uint32 glyph); const Glyph &addGlyph(uint32 glyph);
const Glyph &findGlyph(uint32 glyph); const Glyph &findGlyph(uint32 glyph);
float getKerning(uint32 leftglyph, uint32 rightglyph); float getKerning(uint32 leftglyph, uint32 rightglyph);
void codepointsFromString(const std::string &str, Codepoints &codepoints); void printv(const Matrix4 &t, const DrawCommands &drawcommands, const std::vector<GlyphVertex> &vertices);
void printv(const Matrix4 &t, const std::vector<DrawCommand> &drawcommands, const std::vector<GlyphVertex> &vertices);
std::vector<StrongRef<love::font::Rasterizer>> rasterizers; std::vector<StrongRef<love::font::Rasterizer>> rasterizers;
+3 -3
View File
@@ -814,7 +814,7 @@ Mesh *Graphics::newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, con
return new Mesh(vertexformat, data, datasize, drawmode, usage); return new Mesh(vertexformat, data, datasize, drawmode, usage);
} }
Text *Graphics::newText(Font *font, const std::string &text) Text *Graphics::newText(Font *font, const std::vector<Font::ColoredString> &text)
{ {
return new Text(font, text); return new Text(font, text);
} }
@@ -1105,7 +1105,7 @@ bool Graphics::isWireframe() const
return states.back().wireframe; return states.back().wireframe;
} }
void Graphics::print(const std::string &str, float x, float y , float angle, float sx, float sy, float ox, float oy, float kx, float ky) void Graphics::print(const std::vector<Font::ColoredString> &str, float x, float y , float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
checkSetDefaultFont(); checkSetDefaultFont();
@@ -1115,7 +1115,7 @@ void Graphics::print(const std::string &str, float x, float y , float angle, flo
state.font->print(str, x, y, angle, sx, sy, ox, oy, kx, ky); state.font->print(str, x, y, angle, sx, sy, ox, oy, kx, ky);
} }
void Graphics::printf(const std::string &str, float x, float y, float wrap, Font::AlignMode align, float angle, float sx, float sy, float ox, float oy, float kx, float ky) void Graphics::printf(const std::vector<Font::ColoredString> &str, float x, float y, float wrap, Font::AlignMode align, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
checkSetDefaultFont(); checkSetDefaultFont();
+3 -3
View File
@@ -183,7 +183,7 @@ public:
Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, Mesh::DrawMode drawmode, Mesh::Usage usage); Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, Mesh::DrawMode drawmode, Mesh::Usage usage);
Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, Mesh::Usage usage); Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, Mesh::Usage usage);
Text *newText(Font *font, const std::string &text = ""); Text *newText(Font *font, const std::vector<Font::ColoredString> &text = {});
bool isGammaCorrect() const; bool isGammaCorrect() const;
@@ -328,7 +328,7 @@ public:
* @param kx Shear along the x-axis. * @param kx Shear along the x-axis.
* @param ky Shear along the y-axis. * @param ky Shear along the y-axis.
**/ **/
void print(const std::string &str, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); void print(const std::vector<Font::ColoredString> &str, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
/** /**
* Draw formatted text on screen at the specified coordinates. * Draw formatted text on screen at the specified coordinates.
@@ -346,7 +346,7 @@ public:
* @param kx Shear along the x-axis. * @param kx Shear along the x-axis.
* @param ky Shear along the y-axis. * @param ky Shear along the y-axis.
**/ **/
void printf(const std::string &str, float x, float y, float wrap, Font::AlignMode align, float angle, float sx, float sy, float ox, float oy, float kx, float ky); void printf(const std::vector<Font::ColoredString> &str, float x, float y, float wrap, Font::AlignMode align, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
/** /**
* Draws a point at (x,y). * Draws a point at (x,y).
+47 -36
View File
@@ -30,7 +30,7 @@ namespace graphics
namespace opengl namespace opengl
{ {
Text::Text(Font *font, const std::string &text) Text::Text(Font *font, const std::vector<Font::ColoredString> &text)
: font(font) : font(font)
, vbo(nullptr) , vbo(nullptr)
, text_info() , text_info()
@@ -111,13 +111,13 @@ void Text::regenerateVertices()
void Text::addTextData(const TextData &t) void Text::addTextData(const TextData &t)
{ {
std::vector<Font::GlyphVertex> vertices; std::vector<Font::GlyphVertex> vertices;
std::vector<Font::DrawCommand> new_commands; Font::DrawCommands new_commands;
// We only have formatted text if the align mode is valid. // We only have formatted text if the align mode is valid.
if (t.align == Font::ALIGN_MAX_ENUM) if (t.align == Font::ALIGN_MAX_ENUM)
new_commands = font->generateVertices(t.text, vertices, 0.0f, Vector(0.0f, 0.0f), &text_info); new_commands = font->generateVertices(t.codepoints, vertices, 0.0f, Vector(0.0f, 0.0f), &text_info);
else else
new_commands = font->generateVerticesFormatted(t.text, t.wrap, t.align, vertices, &text_info); new_commands = font->generateVerticesFormatted(t.codepoints, t.wrap, t.align, vertices, &text_info);
if (t.use_matrix) if (t.use_matrix)
t.matrix.transform(&vertices[0], &vertices[0], (int) vertices.size()); t.matrix.transform(&vertices[0], &vertices[0], (int) vertices.size());
@@ -127,34 +127,37 @@ void Text::addTextData(const TextData &t)
if (!t.append_vertices) if (!t.append_vertices)
{ {
voffset = 0; voffset = 0;
draw_commands.clear(); draw_commands.commands.clear();
draw_commands.usecolors = false;
} }
uploadVertices(vertices, voffset); uploadVertices(vertices, voffset);
if (!new_commands.empty()) if (!new_commands.commands.empty())
{ {
// The start vertex should be adjusted to account for the vertex offset. // The start vertex should be adjusted to account for the vertex offset.
for (Font::DrawCommand &cmd : new_commands) for (Font::DrawCommand &cmd : new_commands.commands)
cmd.startvertex += (int) voffset; cmd.startvertex += (int) voffset;
auto firstcmd = new_commands.begin(); auto firstcmd = new_commands.commands.begin();
// If the first draw command in the new list has the same texture as the // If the first draw command in the new list has the same texture as the
// last one in the existing list we're building and its vertices are // last one in the existing list we're building and its vertices are
// in-order, we can combine them (saving a draw call.) // in-order, we can combine them (saving a draw call.)
if (!draw_commands.empty()) if (!draw_commands.commands.empty())
{ {
auto prevcmd = draw_commands.back(); auto prevcmd = draw_commands.commands.back();
if (prevcmd.texture == firstcmd->texture && (prevcmd.startvertex + prevcmd.vertexcount) == firstcmd->startvertex) if (prevcmd.texture == firstcmd->texture && (prevcmd.startvertex + prevcmd.vertexcount) == firstcmd->startvertex)
{ {
draw_commands.back().vertexcount += firstcmd->vertexcount; draw_commands.commands.back().vertexcount += firstcmd->vertexcount;
++firstcmd; ++firstcmd;
} }
} }
// Append the new draw commands to the list we're building. // Append the new draw commands to the list we're building.
draw_commands.insert(draw_commands.end(), firstcmd, new_commands.end()); draw_commands.commands.insert(draw_commands.commands.end(), firstcmd, new_commands.commands.end());
draw_commands.usecolors = draw_commands.usecolors || new_commands.usecolors;
} }
vert_offset = voffset + vertices.size(); vert_offset = voffset + vertices.size();
@@ -165,20 +168,20 @@ void Text::addTextData(const TextData &t)
regenerateVertices(); regenerateVertices();
} }
void Text::set(const std::string &text) void Text::set(const std::vector<Font::ColoredString> &text)
{ {
if (text.empty()) return set(text, -1.0f, Font::ALIGN_MAX_ENUM);
return set();
addTextData({text, -1.0f, Font::ALIGN_MAX_ENUM, false, false, Matrix3()});
} }
void Text::set(const std::string &text, float wrap, Font::AlignMode align) void Text::set(const std::vector<Font::ColoredString> &text, float wrap, Font::AlignMode align)
{ {
if (text.empty()) if (text.empty() || (text.size() == 1 && text[0].str.empty()))
return set(); return set();
addTextData({text, wrap, align, false, false, Matrix3()}); Font::ColoredCodepoints codepoints;
Font::getCodepointsFromString(text, codepoints);
addTextData({codepoints, wrap, align, false, false, Matrix3()});
} }
void Text::set() void Text::set()
@@ -186,30 +189,29 @@ void Text::set()
clear(); clear();
} }
void Text::add(const std::string &text, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) void Text::add(const std::vector<Font::ColoredString> &text, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
if (text.empty()) return addf(text, -1.0f, Font::ALIGN_MAX_ENUM, x, y, angle, sx, sy, ox, oy, kx, ky);
return;
Matrix3 m(x, y, angle, sx, sy, ox, oy, kx, ky);
addTextData({text, -1.0f, Font::ALIGN_MAX_ENUM, true, true, m});
} }
void Text::addf(const std::string &text, float wrap, Font::AlignMode align, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) void Text::addf(const std::vector<Font::ColoredString> &text, float wrap, Font::AlignMode align, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
if (text.empty()) if (text.empty() || (text.size() == 1 && text[0].str.empty()))
return; return;
Font::ColoredCodepoints codepoints;
Font::getCodepointsFromString(text, codepoints);
Matrix3 m(x, y, angle, sx, sy, ox, oy, kx, ky); Matrix3 m(x, y, angle, sx, sy, ox, oy, kx, ky);
addTextData({text, wrap, align, true, true, m}); addTextData({codepoints, wrap, align, true, true, m});
} }
void Text::clear() void Text::clear()
{ {
text_data.clear(); text_data.clear();
draw_commands.clear(); draw_commands.commands.clear();
draw_commands.usecolors = false;
texture_cache_id = font->getTextureCacheID(); texture_cache_id = font->getTextureCacheID();
text_info = {}; text_info = {};
vert_offset = 0; vert_offset = 0;
@@ -217,7 +219,7 @@ void Text::clear()
void Text::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) void Text::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
if (vbo == nullptr || draw_commands.empty()) if (vbo == nullptr || draw_commands.commands.empty())
return; return;
OpenGL::TempDebugGroup debuggroup("Text object draw"); OpenGL::TempDebugGroup debuggroup("Text object draw");
@@ -226,8 +228,9 @@ void Text::draw(float x, float y, float angle, float sx, float sy, float ox, flo
if (font->getTextureCacheID() != texture_cache_id) if (font->getTextureCacheID() != texture_cache_id)
regenerateVertices(); regenerateVertices();
const size_t pos_offset = offsetof(Font::GlyphVertex, x); const size_t pos_offset = offsetof(Font::GlyphVertex, x);
const size_t tex_offset = offsetof(Font::GlyphVertex, s); const size_t tex_offset = offsetof(Font::GlyphVertex, s);
const size_t color_offset = offsetof(Font::GlyphVertex, color.r);
const size_t stride = sizeof(Font::GlyphVertex); const size_t stride = sizeof(Font::GlyphVertex);
OpenGL::TempTransform transform(gl); OpenGL::TempTransform transform(gl);
@@ -239,10 +242,18 @@ void Text::draw(float x, float y, float angle, float sx, float sy, float ox, flo
// Font::drawVertices expects AttribPointer calls to be done already. // Font::drawVertices expects AttribPointer calls to be done already.
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, vbo->getPointer(pos_offset)); glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, vbo->getPointer(pos_offset));
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, vbo->getPointer(tex_offset)); glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, vbo->getPointer(tex_offset));
if (draw_commands.usecolors)
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, vbo->getPointer(color_offset));
} }
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD); uint32 enabledattribs = ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD;
if (draw_commands.usecolors)
enabledattribs |= ATTRIBFLAG_COLOR;
gl.useVertexAttribArrays(enabledattribs);
font->drawVertices(draw_commands); font->drawVertices(draw_commands);
} }
+7 -7
View File
@@ -38,15 +38,15 @@ class Text : public Drawable
{ {
public: public:
Text(Font *font, const std::string &text = ""); Text(Font *font, const std::vector<Font::ColoredString> &text = {});
virtual ~Text(); virtual ~Text();
void set(const std::string &text); void set(const std::vector<Font::ColoredString> &text);
void set(const std::string &text, float wrap, Font::AlignMode align); void set(const std::vector<Font::ColoredString> &text, float wrap, Font::AlignMode align);
void set(); void set();
void add(const std::string &text, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); void add(const std::vector<Font::ColoredString> &text, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
void addf(const std::string &text, float wrap, Font::AlignMode align, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); void addf(const std::vector<Font::ColoredString> &text, float wrap, Font::AlignMode align, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
void clear(); void clear();
// Implements Drawable. // Implements Drawable.
@@ -69,7 +69,7 @@ private:
struct TextData struct TextData
{ {
std::string text; Font::ColoredCodepoints codepoints;
float wrap; float wrap;
Font::AlignMode align; Font::AlignMode align;
bool use_matrix; bool use_matrix;
@@ -84,7 +84,7 @@ private:
StrongRef<Font> font; StrongRef<Font> font;
GLBuffer *vbo; GLBuffer *vbo;
std::vector<Font::DrawCommand> draw_commands; Font::DrawCommands draw_commands;
std::vector<TextData> text_data; std::vector<TextData> text_data;
Font::TextInfo text_info; Font::TextInfo text_info;
@@ -851,7 +851,9 @@ int w_newText(lua_State *L)
luax_catchexcept(L, [&](){ t = instance()->newText(font); }); luax_catchexcept(L, [&](){ t = instance()->newText(font); });
else else
{ {
std::string text = luax_checkstring(L, 2); std::vector<Font::ColoredString> text;
luax_checkcoloredstring(L, 2, text);
luax_catchexcept(L, [&](){ t = instance()->newText(font, text); }); luax_catchexcept(L, [&](){ t = instance()->newText(font, text); });
} }
@@ -1466,7 +1468,9 @@ int w_draw(lua_State *L)
int w_print(lua_State *L) int w_print(lua_State *L)
{ {
std::string str = luax_checkstring(L, 1); std::vector<Font::ColoredString> str;
luax_checkcoloredstring(L, 1, str);
float x = (float)luaL_optnumber(L, 2, 0.0); float x = (float)luaL_optnumber(L, 2, 0.0);
float y = (float)luaL_optnumber(L, 3, 0.0); float y = (float)luaL_optnumber(L, 3, 0.0);
float angle = (float)luaL_optnumber(L, 4, 0.0f); float angle = (float)luaL_optnumber(L, 4, 0.0f);
@@ -1485,7 +1489,9 @@ int w_print(lua_State *L)
int w_printf(lua_State *L) int w_printf(lua_State *L)
{ {
std::string str = luax_checkstring(L, 1); std::vector<Font::ColoredString> str;
luax_checkcoloredstring(L, 1, str);
float x = (float)luaL_checknumber(L, 2); float x = (float)luaL_checknumber(L, 2);
float y = (float)luaL_checknumber(L, 3); float y = (float)luaL_checknumber(L, 3);
float wrap = (float)luaL_checknumber(L, 4); float wrap = (float)luaL_checknumber(L, 4);
+54 -5
View File
@@ -32,6 +32,47 @@ Text *luax_checktext(lua_State *L, int idx)
return luax_checktype<Text>(L, idx, GRAPHICS_TEXT_ID); return luax_checktype<Text>(L, idx, GRAPHICS_TEXT_ID);
} }
void luax_checkcoloredstring(lua_State *L, int idx, std::vector<Font::ColoredString> &strings)
{
Font::ColoredString coloredstr;
coloredstr.color = Color(255, 255, 255, 255);
if (lua_istable(L, idx))
{
int len = luax_objlen(L, idx);
for (int i = 1; i <= len; i++)
{
lua_rawgeti(L, idx, i);
if (lua_istable(L, -1))
{
for (int j = 1; j <= 4; j++)
lua_rawgeti(L, -j, j);
coloredstr.color.r = (unsigned char) luaL_checknumber(L, -4);
coloredstr.color.g = (unsigned char) luaL_checknumber(L, -3);
coloredstr.color.b = (unsigned char) luaL_checknumber(L, -2);
coloredstr.color.a = (unsigned char) luaL_optnumber(L, -1, 255);
lua_pop(L, 4);
}
else
{
coloredstr.str = luaL_checkstring(L, -1);
strings.push_back(coloredstr);
}
lua_pop(L, 1);
}
}
else
{
coloredstr.str = luaL_checkstring(L, idx);
strings.push_back(coloredstr);
}
}
int w_Text_set(lua_State *L) int w_Text_set(lua_State *L)
{ {
Text *t = luax_checktext(L, 1); Text *t = luax_checktext(L, 1);
@@ -44,7 +85,8 @@ int w_Text_set(lua_State *L)
else if (lua_isnoneornil(L, 3)) else if (lua_isnoneornil(L, 3))
{ {
// Single argument: unformatted text. // Single argument: unformatted text.
std::string newtext = luax_checkstring(L, 2); std::vector<Font::ColoredString> newtext;
luax_checkcoloredstring(L, 2, newtext);
luax_catchexcept(L, [&](){ t->set(newtext); }); luax_catchexcept(L, [&](){ t->set(newtext); });
} }
else else
@@ -57,7 +99,8 @@ int w_Text_set(lua_State *L)
if (!Font::getConstant(alignstr, align)) if (!Font::getConstant(alignstr, align))
return luaL_error(L, "Invalid align mode: %s", alignstr); return luaL_error(L, "Invalid align mode: %s", alignstr);
std::string newtext = luax_checkstring(L, 2); std::vector<Font::ColoredString> newtext;
luax_checkcoloredstring(L, 2, newtext);
luax_catchexcept(L, [&](){ t->set(newtext, wraplimit, align); }); luax_catchexcept(L, [&](){ t->set(newtext, wraplimit, align); });
} }
@@ -76,7 +119,8 @@ int w_Text_setf(lua_State *L)
if (!Font::getConstant(alignstr, align)) if (!Font::getConstant(alignstr, align))
return luaL_error(L, "Invalid align mode: %s", alignstr); return luaL_error(L, "Invalid align mode: %s", alignstr);
std::string newtext = luax_checkstring(L, 2); std::vector<Font::ColoredString> newtext;
luax_checkcoloredstring(L, 2, newtext);
luax_catchexcept(L, [&](){ t->set(newtext, wraplimit, align); }); luax_catchexcept(L, [&](){ t->set(newtext, wraplimit, align); });
@@ -86,7 +130,9 @@ int w_Text_setf(lua_State *L)
int w_Text_add(lua_State *L) int w_Text_add(lua_State *L)
{ {
Text *t = luax_checktext(L, 1); Text *t = luax_checktext(L, 1);
std::string text = luax_checkstring(L, 2);
std::vector<Font::ColoredString> text;
luax_checkcoloredstring(L, 2, text);
float x = (float) luaL_optnumber(L, 3, 0.0); float x = (float) luaL_optnumber(L, 3, 0.0);
float y = (float) luaL_optnumber(L, 4, 0.0); float y = (float) luaL_optnumber(L, 4, 0.0);
@@ -105,7 +151,10 @@ int w_Text_add(lua_State *L)
int w_Text_addf(lua_State *L) int w_Text_addf(lua_State *L)
{ {
Text *t = luax_checktext(L, 1); Text *t = luax_checktext(L, 1);
std::string text = luax_checkstring(L, 2);
std::vector<Font::ColoredString> text;
luax_checkcoloredstring(L, 2, text);
float wrap = (float) luaL_checknumber(L, 3); float wrap = (float) luaL_checknumber(L, 3);
Font::AlignMode align = Font::ALIGN_MAX_ENUM; Font::AlignMode align = Font::ALIGN_MAX_ENUM;
+1
View File
@@ -32,6 +32,7 @@ namespace opengl
{ {
Text *luax_checktext(lua_State *L, int idx); Text *luax_checktext(lua_State *L, int idx);
void luax_checkcoloredstring(lua_State *L, int idx, std::vector<Font::ColoredString> &strings);
int w_Text_set(lua_State *L); int w_Text_set(lua_State *L);
int w_Text_setf(lua_State *L); int w_Text_setf(lua_State *L);
int w_Text_add(lua_State *L); int w_Text_add(lua_State *L);