Loading libs/hwui/Matrix.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,11 @@ bool Matrix4::changesBounds() { ALMOST_EQUAL(data[10], 1.0f)); } bool Matrix4::isPureTranslate() { return mSimpleMatrix && ALMOST_EQUAL(data[kScaleX], 1.0f) && ALMOST_EQUAL(data[kScaleY], 1.0f); } void Matrix4::load(const float* v) { memcpy(data, v, sizeof(data)); mSimpleMatrix = false; Loading libs/hwui/Matrix.h +2 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,8 @@ public: multiply(u); } bool isPureTranslate(); bool changesBounds(); void copyTo(float* v) const; Loading libs/hwui/OpenGLRenderer.cpp +88 −25 Original line number Diff line number Diff line Loading @@ -909,9 +909,19 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); if (mSnapshot->transform->isPureTranslate()) { const float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f); const float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f); drawTextureMesh(x, y, x + (dstRight - dstLeft), y + (dstBottom - dstTop), texture->id, alpha / 255.0f, mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, false, true); } else { drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, texture->id, alpha / 255.0f, mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount); } resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); } Loading @@ -937,6 +947,7 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors); if (mesh && mesh->verticesCount > 0) { const bool pureTranslate = mSnapshot->transform->isPureTranslate(); #if RENDER_LAYERS_AS_REGIONS // Mark the current layer dirty where we are going to draw the patch if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && Loading @@ -944,18 +955,35 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int const size_t count = mesh->quads.size(); for (size_t i = 0; i < count; i++) { Rect bounds = mesh->quads.itemAt(i); if (pureTranslate) { const float x = (int) floorf(bounds.left + 0.5f); const float y = (int) floorf(bounds.top + 0.5f); dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getBottom(), *mSnapshot->transform); } else { dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *mSnapshot->transform); } } } #endif if (pureTranslate) { const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); drawTextureMesh(x, y, x + right - left, y + bottom - top, texture->id, alpha / 255.0f, mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, GL_TRIANGLES, mesh->verticesCount, false, true, mesh->meshBuffer, true, !mesh->hasEmptyQuads); } else { drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer, true, !mesh->hasEmptyQuads); } } } void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { // TODO: Should do quickReject for each line Loading Loading @@ -1087,6 +1115,13 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, break; } // TODO: Handle paint->getTextScaleX() const bool pureTranslate = mSnapshot->transform->isPureTranslate(); if (pureTranslate) { x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); } int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); Loading @@ -1110,7 +1145,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, count, mShadowRadius); const AutoTexture autoCleanup(shadow); setupShadow(shadow, x, y, mode, a); setupShadow(shadow, x, y, mode, a, pureTranslate); // Draw the mesh glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); Loading @@ -1120,14 +1155,17 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, GLuint textureUnit = 0; glActiveTexture(gTextureUnits[textureUnit]); // Assume that the modelView matrix does not force scales, rotates, etc. const bool linearFilter = mSnapshot->transform->changesBounds(); // Pick the appropriate texture filtering bool linearFilter = mSnapshot->transform->changesBounds(); if (pureTranslate && !linearFilter) { linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f; } // Dimensions are set to (0,0), the layer (if any) won't be dirtied setupTextureAlpha8(fontRenderer.getTexture(linearFilter), 0, 0, textureUnit, x, y, r, g, b, a, mode, false, true, NULL, NULL); x, y, r, g, b, a, mode, false, true, NULL, NULL, 0, pureTranslate); const Rect& clip = mSnapshot->getLocalClip(); const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip(); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); #if RENDER_LAYERS_AS_REGIONS Loading @@ -1137,11 +1175,13 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, #endif mCaches.unbindMeshBuffer(); if (fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y, if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y, hasLayer ? &bounds : NULL)) { #if RENDER_LAYERS_AS_REGIONS if (hasLayer) { if (!pureTranslate) { mSnapshot->transform->mapRect(bounds); } bounds.intersect(*mSnapshot->clipRect); bounds.snapToPixelBoundaries(); Loading Loading @@ -1241,7 +1281,7 @@ void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) { /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y, SkXfermode::Mode mode, float alpha) { SkXfermode::Mode mode, float alpha, bool ignoreTransforms) { const float sx = x - texture->left + mShadowDx; const float sy = y - texture->top + mShadowDy; Loading @@ -1252,7 +1292,9 @@ void OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y, const GLfloat b = a * ((mShadowColor ) & 0xFF) / 255.0f; GLuint textureUnit = 0; setupTextureAlpha8(texture, textureUnit, sx, sy, r, g, b, a, mode, true, false); setupTextureAlpha8(texture->id, texture->width, texture->height, textureUnit, sx, sy, r, g, b, a, mode, true, false, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, 0, ignoreTransforms); } void OpenGLRenderer::setupTextureAlpha8(const Texture* texture, GLuint& textureUnit, Loading @@ -1273,7 +1315,7 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, GLuint& textureUnit, float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode, bool transforms, bool applyFilters, GLvoid* vertices, GLvoid* texCoords, GLuint vbo) { GLvoid* vertices, GLvoid* texCoords, GLuint vbo, bool ignoreTransform) { // Describe the required shaders ProgramDescription description; description.hasTexture = true; Loading Loading @@ -1321,9 +1363,14 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t mModelView.loadIdentity(); } mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); mat4 t; if (!ignoreTransform) { t.load(*mSnapshot->transform); } mCaches.currentProgram->set(mOrthoMatrix, mModelView, t); if (width > 0 && height > 0) { dirtyLayer(x, y, x + width, y + height, *mSnapshot->transform); dirtyLayer(x, y, x + width, y + height, t); } if (setColor) { Loading @@ -1334,6 +1381,9 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t if (applyFilters) { // Setup attributes and uniforms required by the shaders if (mShader) { if (ignoreTransform) { mModelView.loadInverse(*mSnapshot->transform); } mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); } if (mColorFilter) { Loading Loading @@ -1473,7 +1523,11 @@ void OpenGLRenderer::setupColorRect(float left, float top, float right, float bo // Setup attributes and uniforms required by the shaders if (mShader) { if (ignoreMatrix) mModelView.loadIdentity(); if (ignoreMatrix) { mModelView.loadIdentity(); } else if (ignoreTransform) { mModelView.loadInverse(*mSnapshot->transform); } mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); } if (mColorFilter) { Loading @@ -1489,10 +1543,19 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); if (mSnapshot->transform->isPureTranslate()) { const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id, alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, false, true); } else { drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount); } } void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) { Loading libs/hwui/OpenGLRenderer.h +3 −2 Original line number Diff line number Diff line Loading @@ -294,9 +294,10 @@ private: * @param y The y coordinate of the shadow * @param mode The blending mode * @param alpha The alpha value * @param ignoreTransforms True if the coordinates are already in screen space */ void setupShadow(const ShadowTexture* texture, float x, float y, SkXfermode::Mode mode, float alpha); float alpha, bool ignoreTransforms = false); /** * Prepares the renderer to draw the specified Alpha8 texture as a rectangle. Loading Loading @@ -349,7 +350,7 @@ private: void setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, GLuint& textureUnit, float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode, bool transforms, bool applyFilters, GLvoid* vertices, GLvoid* texCoords, GLuint vbo = 0); GLvoid* vertices, GLvoid* texCoords, GLuint vbo = 0, bool ignoreTransform = false); /** * Draws text underline and strike-through if needed. Loading Loading
libs/hwui/Matrix.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,11 @@ bool Matrix4::changesBounds() { ALMOST_EQUAL(data[10], 1.0f)); } bool Matrix4::isPureTranslate() { return mSimpleMatrix && ALMOST_EQUAL(data[kScaleX], 1.0f) && ALMOST_EQUAL(data[kScaleY], 1.0f); } void Matrix4::load(const float* v) { memcpy(data, v, sizeof(data)); mSimpleMatrix = false; Loading
libs/hwui/Matrix.h +2 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,8 @@ public: multiply(u); } bool isPureTranslate(); bool changesBounds(); void copyTo(float* v) const; Loading
libs/hwui/OpenGLRenderer.cpp +88 −25 Original line number Diff line number Diff line Loading @@ -909,9 +909,19 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); if (mSnapshot->transform->isPureTranslate()) { const float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f); const float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f); drawTextureMesh(x, y, x + (dstRight - dstLeft), y + (dstBottom - dstTop), texture->id, alpha / 255.0f, mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, false, true); } else { drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, texture->id, alpha / 255.0f, mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount); } resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); } Loading @@ -937,6 +947,7 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors); if (mesh && mesh->verticesCount > 0) { const bool pureTranslate = mSnapshot->transform->isPureTranslate(); #if RENDER_LAYERS_AS_REGIONS // Mark the current layer dirty where we are going to draw the patch if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && Loading @@ -944,18 +955,35 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int const size_t count = mesh->quads.size(); for (size_t i = 0; i < count; i++) { Rect bounds = mesh->quads.itemAt(i); if (pureTranslate) { const float x = (int) floorf(bounds.left + 0.5f); const float y = (int) floorf(bounds.top + 0.5f); dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getBottom(), *mSnapshot->transform); } else { dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *mSnapshot->transform); } } } #endif if (pureTranslate) { const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); drawTextureMesh(x, y, x + right - left, y + bottom - top, texture->id, alpha / 255.0f, mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, GL_TRIANGLES, mesh->verticesCount, false, true, mesh->meshBuffer, true, !mesh->hasEmptyQuads); } else { drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer, true, !mesh->hasEmptyQuads); } } } void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { // TODO: Should do quickReject for each line Loading Loading @@ -1087,6 +1115,13 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, break; } // TODO: Handle paint->getTextScaleX() const bool pureTranslate = mSnapshot->transform->isPureTranslate(); if (pureTranslate) { x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); } int alpha; SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); Loading @@ -1110,7 +1145,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, count, mShadowRadius); const AutoTexture autoCleanup(shadow); setupShadow(shadow, x, y, mode, a); setupShadow(shadow, x, y, mode, a, pureTranslate); // Draw the mesh glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); Loading @@ -1120,14 +1155,17 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, GLuint textureUnit = 0; glActiveTexture(gTextureUnits[textureUnit]); // Assume that the modelView matrix does not force scales, rotates, etc. const bool linearFilter = mSnapshot->transform->changesBounds(); // Pick the appropriate texture filtering bool linearFilter = mSnapshot->transform->changesBounds(); if (pureTranslate && !linearFilter) { linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f; } // Dimensions are set to (0,0), the layer (if any) won't be dirtied setupTextureAlpha8(fontRenderer.getTexture(linearFilter), 0, 0, textureUnit, x, y, r, g, b, a, mode, false, true, NULL, NULL); x, y, r, g, b, a, mode, false, true, NULL, NULL, 0, pureTranslate); const Rect& clip = mSnapshot->getLocalClip(); const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip(); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); #if RENDER_LAYERS_AS_REGIONS Loading @@ -1137,11 +1175,13 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, #endif mCaches.unbindMeshBuffer(); if (fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y, if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y, hasLayer ? &bounds : NULL)) { #if RENDER_LAYERS_AS_REGIONS if (hasLayer) { if (!pureTranslate) { mSnapshot->transform->mapRect(bounds); } bounds.intersect(*mSnapshot->clipRect); bounds.snapToPixelBoundaries(); Loading Loading @@ -1241,7 +1281,7 @@ void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) { /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y, SkXfermode::Mode mode, float alpha) { SkXfermode::Mode mode, float alpha, bool ignoreTransforms) { const float sx = x - texture->left + mShadowDx; const float sy = y - texture->top + mShadowDy; Loading @@ -1252,7 +1292,9 @@ void OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y, const GLfloat b = a * ((mShadowColor ) & 0xFF) / 255.0f; GLuint textureUnit = 0; setupTextureAlpha8(texture, textureUnit, sx, sy, r, g, b, a, mode, true, false); setupTextureAlpha8(texture->id, texture->width, texture->height, textureUnit, sx, sy, r, g, b, a, mode, true, false, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, 0, ignoreTransforms); } void OpenGLRenderer::setupTextureAlpha8(const Texture* texture, GLuint& textureUnit, Loading @@ -1273,7 +1315,7 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, GLuint& textureUnit, float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode, bool transforms, bool applyFilters, GLvoid* vertices, GLvoid* texCoords, GLuint vbo) { GLvoid* vertices, GLvoid* texCoords, GLuint vbo, bool ignoreTransform) { // Describe the required shaders ProgramDescription description; description.hasTexture = true; Loading Loading @@ -1321,9 +1363,14 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t mModelView.loadIdentity(); } mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); mat4 t; if (!ignoreTransform) { t.load(*mSnapshot->transform); } mCaches.currentProgram->set(mOrthoMatrix, mModelView, t); if (width > 0 && height > 0) { dirtyLayer(x, y, x + width, y + height, *mSnapshot->transform); dirtyLayer(x, y, x + width, y + height, t); } if (setColor) { Loading @@ -1334,6 +1381,9 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t if (applyFilters) { // Setup attributes and uniforms required by the shaders if (mShader) { if (ignoreTransform) { mModelView.loadInverse(*mSnapshot->transform); } mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); } if (mColorFilter) { Loading Loading @@ -1473,7 +1523,11 @@ void OpenGLRenderer::setupColorRect(float left, float top, float right, float bo // Setup attributes and uniforms required by the shaders if (mShader) { if (ignoreMatrix) mModelView.loadIdentity(); if (ignoreMatrix) { mModelView.loadIdentity(); } else if (ignoreTransform) { mModelView.loadInverse(*mSnapshot->transform); } mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); } if (mColorFilter) { Loading @@ -1489,10 +1543,19 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); if (mSnapshot->transform->isPureTranslate()) { const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id, alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, false, true); } else { drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount); } } void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) { Loading
libs/hwui/OpenGLRenderer.h +3 −2 Original line number Diff line number Diff line Loading @@ -294,9 +294,10 @@ private: * @param y The y coordinate of the shadow * @param mode The blending mode * @param alpha The alpha value * @param ignoreTransforms True if the coordinates are already in screen space */ void setupShadow(const ShadowTexture* texture, float x, float y, SkXfermode::Mode mode, float alpha); float alpha, bool ignoreTransforms = false); /** * Prepares the renderer to draw the specified Alpha8 texture as a rectangle. Loading Loading @@ -349,7 +350,7 @@ private: void setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, GLuint& textureUnit, float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode, bool transforms, bool applyFilters, GLvoid* vertices, GLvoid* texCoords, GLuint vbo = 0); GLvoid* vertices, GLvoid* texCoords, GLuint vbo = 0, bool ignoreTransform = false); /** * Draws text underline and strike-through if needed. Loading