Skip to content

Commit

Permalink
Add optimized method to render text.
Browse files Browse the repository at this point in the history
Retains results of text rendering in a texture, and ignores
(caches) identical strings being set.

Initial uses gives approx 10% better FPS on opening view on Rush.
  • Loading branch information
perim committed Mar 29, 2017
1 parent 486dd8e commit a709209
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 11 deletions.
67 changes: 65 additions & 2 deletions lib/ivis_opengl/textdraw.cpp
Expand Up @@ -186,6 +186,8 @@ struct FTFace
return m_face;
}

FT_Face &face() { return m_face; }

hb_font_t *m_font;

private:
Expand Down Expand Up @@ -422,8 +424,8 @@ static FTFace &getFTFace(iV_fonts FontID)
}
}

static GLuint textureID;
static GLuint pbo;
static GLuint textureID = 0;
static GLuint pbo = 0;

void iV_TextInit()
{
Expand Down Expand Up @@ -723,3 +725,64 @@ void iV_DrawTextF(float x, float y, const char *format, ...)
va_end(ap);
}
#endif

void WzText::setText(const std::string &string, iV_fonts fontID)
{
if (mText == string && fontID == mFontID)
{
return; // cached
}
mFontID = fontID;
mText = string;
if (texture == 0)
{
pie_SetTexturePage(TEXPAGE_EXTERN);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
TextRun tr(string, "en", HB_SCRIPT_COMMON, HB_DIRECTION_LTR);
std::unique_ptr<unsigned char[]> data;
FTFace &face = getFTFace(fontID);
FT_Face &type = face.face();
std::tie(data, dimensions.x, dimensions.y, offsets.x, offsets.y) = getShaper().drawText(tr, face);
if (dimensions.x > 0 && dimensions.y > 0)
{
pie_SetTexturePage(TEXPAGE_EXTERN);
glBindTexture(GL_TEXTURE_2D, texture);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, 4 * dimensions.x * dimensions.y, data.get(), GL_STREAM_DRAW);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dimensions.x, dimensions.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);

mAboveBase = -(type->size->metrics.ascender >> 6);
mLineSize = (type->size->metrics.ascender - type->size->metrics.descender) >> 6;
mBelowBase = type->size->metrics.descender >> 6;
}
glBindTexture(GL_TEXTURE_2D, 0);
}

WzText::WzText(const std::string &string, iV_fonts fontID)
{
setText(string, fontID);
}

WzText::~WzText()
{
glDeleteTextures(1, &texture); // ok to call with texture ID zero
}

void WzText::render(Vector2i position, PIELIGHT colour, float rotation)
{
ASSERT(texture != 0, "Text not initialized before rendering");
if (rotation != 0.f)
{
rotation = 180. - rotation;
}
glDisable(GL_CULL_FACE);
iV_DrawImage(texture, position, offsets, dimensions, rotation, REND_TEXT, colour);
glEnable(GL_CULL_FACE);
}
26 changes: 26 additions & 0 deletions lib/ivis_opengl/textdraw.h
Expand Up @@ -34,6 +34,32 @@ enum iV_fonts
font_count
};

class WzText
{
public:
WzText() {}
WzText(const std::string &text, iV_fonts fontID);
void setText(const std::string &text, iV_fonts fontID);
~WzText();
int width() { return dimensions.x; }
int height() { return dimensions.y; }
void render(Vector2i position, PIELIGHT colour, float rotation = 0.0f);
void render(int x, int y, PIELIGHT colour, float rotation = 0.0f) { render(Vector2i{x,y}, colour, rotation); }
int aboveBase() { return mAboveBase; }
int belowBase() { return mBelowBase; }
int lineSize() { return mLineSize; }

private:
iV_fonts mFontID = font_count;
std::string mText;
GLuint texture = 0;
int mAboveBase = 0;
int mBelowBase = 0;
int mLineSize = 0;
Vector2i offsets;
Vector2i dimensions;
};

void iV_TextInit();
void iV_TextShutdown();
void iV_font(const char *fontName, const char *fontFace, const char *fontFaceBold);
Expand Down
25 changes: 16 additions & 9 deletions src/display3d.cpp
Expand Up @@ -132,6 +132,11 @@ static void NetworkDisplayPlainForm(WIDGET *psWidget, UDWORD xOffset, UDWORD yOf
static void NetworkDisplayImage(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset);
extern bool writeGameInfo(const char *pFileName); // Used to help debug issues when we have fatal errors & crash handler testing.

static WzText txtLevelName;
static WzText txtDebugStatus;
static WzText txtCurrentTime;
static WzText txtShowFPS;

/******************** Variables ********************/
// Should be cleaned up properly and be put in structures.

Expand Down Expand Up @@ -803,13 +808,12 @@ void draw3DScene(void)
}
if (showFPS)
{
unsigned int width, height;
const char *fps;
sasprintf((char **)&fps, "FPS: %d", frameRate());
width = iV_GetTextWidth(fps, font_regular) + 10;
height = iV_GetTextHeight(fps, font_regular);

iV_DrawText(fps, pie_GetVideoBufferWidth() - width, pie_GetVideoBufferHeight() - height, font_regular);
txtShowFPS.setText(fps, font_regular);
const unsigned width = txtShowFPS.width() + 10;
const unsigned height = txtShowFPS.height();
txtShowFPS.render(pie_GetVideoBufferWidth() - width, pie_GetVideoBufferHeight() - height, WZCOL_TEXT_BRIGHT);
}
if (showORDERS)
{
Expand All @@ -823,14 +827,14 @@ void draw3DScene(void)
if (getWidgetsStatus() && !gamePaused())
{
char buildInfo[255];
iV_SetTextColour(WZCOL_TEXT_MEDIUM);
iV_DrawText(getLevelName(), RET_X + 134, 410 + E_H, font_small);
getAsciiTime(buildInfo, graphicsTime);
iV_DrawText(buildInfo, RET_X + 134, 422 + E_H, font_small);
txtLevelName.render(RET_X + 134, 410 + E_H, WZCOL_TEXT_MEDIUM);
if (getDebugMappingStatus())
{
iV_DrawText("DEBUG ", RET_X + 134, 436 + E_H, font_small);
txtDebugStatus.render(RET_X + 134, 436 + E_H, WZCOL_TEXT_MEDIUM);
}
txtCurrentTime.setText(buildInfo, font_small);
txtCurrentTime.render(RET_X + 134, 422 + E_H, WZCOL_TEXT_MEDIUM);
}

while (player.r.y > DEG(360))
Expand Down Expand Up @@ -1124,6 +1128,9 @@ bool init3DView(void)
return false;
}

txtLevelName.setText(getLevelName(), font_small);
txtDebugStatus.setText("DEBUG ", font_small);

return true;
}

Expand Down

0 comments on commit a709209

Please sign in to comment.