From 0d1e452bc901d50b8629d2514c5347aff274a41d Mon Sep 17 00:00:00 2001 From: danij Date: Wed, 13 Nov 2013 15:06:40 +0000 Subject: [PATCH] Refactor|Fonts|Resources|Client: Continued revising bitmap font representation --- doomsday/client/include/gl/gl_draw.h | 8 +- .../client/include/resource/abstractfont.h | 9 +- doomsday/client/include/resource/bitmapfont.h | 9 +- .../include/resource/compositebitmapfont.h | 10 +- doomsday/client/src/gl/dgl_draw.cpp | 82 +++++++----- doomsday/client/src/gl/gl_draw.cpp | 40 ++---- doomsday/client/src/render/rend_font.cpp | 79 +++++------- doomsday/client/src/resource/abstractfont.cpp | 5 - doomsday/client/src/resource/bitmapfont.cpp | 66 ++++------ .../src/resource/compositebitmapfont.cpp | 120 ++++++++---------- doomsday/libdeng2/include/de/core/rectangle.h | 6 + 11 files changed, 191 insertions(+), 243 deletions(-) diff --git a/doomsday/client/include/gl/gl_draw.h b/doomsday/client/include/gl/gl_draw.h index 42dd37ea67..65a1f5af88 100644 --- a/doomsday/client/include/gl/gl_draw.h +++ b/doomsday/client/include/gl/gl_draw.h @@ -25,6 +25,7 @@ #ifndef LIBDENG_GRAPHICS_DRAW_H #define LIBDENG_GRAPHICS_DRAW_H +#include #include #include @@ -34,10 +35,13 @@ extern "C" { void GL_DrawLine(float x1, float y1, float x2, float y2, float r, float g, float b, float a); -void GL_DrawRect(RectRaw const *rect); +void GL_DrawRect(de::Rectanglei const &rect); void GL_DrawRect2(int x, int y, int w, int h); -void GL_DrawRectWithCoords(RectRaw const *rect, de::Vector2i coords[4]); +/** + * @param coords [topLeft, topRight, bottomRight, bottomLeft] + */ +void GL_DrawRectWithCoords(de::Rectanglei const &rect, de::Vector2i const coords[4]); void GL_DrawRectf(const RectRawf* rect); void GL_DrawRectf2(double x, double y, double w, double h); diff --git a/doomsday/client/include/resource/abstractfont.h b/doomsday/client/include/resource/abstractfont.h index 8018272e88..6fcc0d475c 100644 --- a/doomsday/client/include/resource/abstractfont.h +++ b/doomsday/client/include/resource/abstractfont.h @@ -54,8 +54,6 @@ class AbstractFont int _ascent; int _descent; - de::Vector2ui _noCharSize; - /// Do fonts have margins? Is this a pixel border in the composited character /// map texture (perhaps per-glyph)? de::Vector2ui _margin; @@ -79,11 +77,8 @@ class AbstractFont virtual void glInit(); virtual void glDeinit(); - virtual de::Rectanglei const &charGeometry(uchar ch) = 0; - virtual int charWidth(uchar ch) = 0; - virtual int charHeight(uchar ch) = 0; - - de::Vector2i charSize(uchar ch); + virtual de::Rectanglei const &charPosCoords(uchar ch) = 0; + virtual de::Rectanglei const &charTexCoords(uchar ch) = 0; }; #endif // CLIENT_RESOURCE_ABSTRACTFONT_H diff --git a/doomsday/client/include/resource/bitmapfont.h b/doomsday/client/include/resource/bitmapfont.h index 362e2a8fe3..57f29713f5 100644 --- a/doomsday/client/include/resource/bitmapfont.h +++ b/doomsday/client/include/resource/bitmapfont.h @@ -38,7 +38,7 @@ class BitmapFont : public AbstractFont struct bitmapfont_char_t { de::Rectanglei geometry; - de::Vector2i coords[4]; + de::Rectanglei coords; }; public: @@ -53,14 +53,11 @@ class BitmapFont : public AbstractFont GLuint textureGLName() const; de::Vector2i const &textureDimensions() const; - void charCoords(unsigned char ch, de::Vector2i coords[4]); - void glInit(); void glDeinit(); - de::Rectanglei const &charGeometry(unsigned char ch); - int charWidth(unsigned char ch); - int charHeight(unsigned char ch); + de::Rectanglei const &charPosCoords(uchar ch); + de::Rectanglei const &charTexCoords(uchar ch); private: DENG2_PRIVATE(d) diff --git a/doomsday/client/include/resource/compositebitmapfont.h b/doomsday/client/include/resource/compositebitmapfont.h index 59488f5f13..6d20e8bafa 100644 --- a/doomsday/client/include/resource/compositebitmapfont.h +++ b/doomsday/client/include/resource/compositebitmapfont.h @@ -41,6 +41,7 @@ class CompositeBitmapFont : public AbstractFont patchid_t patch; de::Texture::Variant *tex; uint8_t border; + bool haveSourceImage; }; public: @@ -66,16 +67,13 @@ class CompositeBitmapFont : public AbstractFont de::Texture::Variant *charTexture(uchar ch); - uint8_t charBorder(uchar chr); - - void charCoords(uchar chr, de::Vector2i coords[4]); + uint charBorder(uchar ch); void glInit(); void glDeinit(); - de::Rectanglei const &charGeometry(uchar ch); - int charWidth(uchar ch); - int charHeight(uchar ch); + de::Rectanglei const &charPosCoords(uchar ch); + de::Rectanglei const &charTexCoords(uchar ch); private: DENG2_PRIVATE(d) diff --git a/doomsday/client/src/gl/dgl_draw.cpp b/doomsday/client/src/gl/dgl_draw.cpp index c233ea86ff..ebbbcaf682 100644 --- a/doomsday/client/src/gl/dgl_draw.cpp +++ b/doomsday/client/src/gl/dgl_draw.cpp @@ -1,4 +1,4 @@ -/** @file dgl_draw.cpp +/** @file dgl_draw.cpp Drawing Operations and Vertex Arrays. * * @authors Copyright © 2003-2013 Jaakko Keränen * @authors Copyright © 2007-2013 Daniel Swanson @@ -17,15 +17,6 @@ * http://www.gnu.org/licenses */ -/** - * Drawing Operations and Vertex Arrays. - * - * Get OpenGL header files from: - * http://oss.sgi.com/projects/ogl-sample/ - */ - -// HEADER FILES ------------------------------------------------------------ - #define DENG_NO_API_MACROS_GL #include @@ -38,17 +29,7 @@ #include "gl/sys_opengl.h" -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -// FUNCTION PROTOTYPES ----------------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ +using namespace de; static int primLevel = 0; static DGLuint inList = 0; @@ -56,8 +37,6 @@ static DGLuint inList = 0; static boolean inPrim = false; #endif -// CODE -------------------------------------------------------------------- - boolean GL_NewList(DGLuint list, int mode) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -125,6 +104,7 @@ void GL_DeleteLists(DGLuint list, int range) glDeleteLists(list, range); } +#undef DGL_Color3ub DENG_EXTERN_C void DGL_Color3ub(DGLubyte r, DGLubyte g, DGLubyte b) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -133,6 +113,7 @@ DENG_EXTERN_C void DGL_Color3ub(DGLubyte r, DGLubyte g, DGLubyte b) glColor3ub(r, g, b); } +#undef DGL_Color3ubv DENG_EXTERN_C void DGL_Color3ubv(const DGLubyte* vec) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -141,6 +122,7 @@ DENG_EXTERN_C void DGL_Color3ubv(const DGLubyte* vec) glColor3ubv(vec); } +#undef DGL_Color4ub DENG_EXTERN_C void DGL_Color4ub(DGLubyte r, DGLubyte g, DGLubyte b, DGLubyte a) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -149,6 +131,7 @@ DENG_EXTERN_C void DGL_Color4ub(DGLubyte r, DGLubyte g, DGLubyte b, DGLubyte a) glColor4ub(r, g, b, a); } +#undef DGL_Color4ubv DENG_EXTERN_C void DGL_Color4ubv(const DGLubyte* vec) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -157,6 +140,7 @@ DENG_EXTERN_C void DGL_Color4ubv(const DGLubyte* vec) glColor4ubv(vec); } +#undef DGL_Color3f DENG_EXTERN_C void DGL_Color3f(float r, float g, float b) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -165,6 +149,7 @@ DENG_EXTERN_C void DGL_Color3f(float r, float g, float b) glColor3f(r, g, b); } +#undef DGL_Color3fv DENG_EXTERN_C void DGL_Color3fv(const float* vec) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -173,6 +158,7 @@ DENG_EXTERN_C void DGL_Color3fv(const float* vec) glColor3fv(vec); } +#undef DGL_Color4f DENG_EXTERN_C void DGL_Color4f(float r, float g, float b, float a) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -181,6 +167,7 @@ DENG_EXTERN_C void DGL_Color4f(float r, float g, float b, float a) glColor4f(r, g, b, a); } +#undef DGL_Color4fv DENG_EXTERN_C void DGL_Color4fv(const float* vec) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -189,6 +176,7 @@ DENG_EXTERN_C void DGL_Color4fv(const float* vec) glColor4fv(vec); } +#undef DGL_TexCoord2f DENG_EXTERN_C void DGL_TexCoord2f(byte target, float s, float t) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -197,6 +185,7 @@ DENG_EXTERN_C void DGL_TexCoord2f(byte target, float s, float t) glMultiTexCoord2f(GL_TEXTURE0 + target, s, t); } +#undef DGL_TexCoord2fv DENG_EXTERN_C void DGL_TexCoord2fv(byte target, float* vec) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -205,6 +194,7 @@ DENG_EXTERN_C void DGL_TexCoord2fv(byte target, float* vec) glMultiTexCoord2fv(GL_TEXTURE0 + target, vec); } +#undef DGL_Vertex2f DENG_EXTERN_C void DGL_Vertex2f(float x, float y) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -213,6 +203,7 @@ DENG_EXTERN_C void DGL_Vertex2f(float x, float y) glVertex2f(x, y); } +#undef DGL_Vertex2fv DENG_EXTERN_C void DGL_Vertex2fv(const float* vec) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -221,6 +212,7 @@ DENG_EXTERN_C void DGL_Vertex2fv(const float* vec) glVertex2fv(vec); } +#undef DGL_Vertex3f DENG_EXTERN_C void DGL_Vertex3f(float x, float y, float z) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -229,6 +221,7 @@ DENG_EXTERN_C void DGL_Vertex3f(float x, float y, float z) glVertex3f(x, y, z); } +#undef DGL_Vertex3fv DENG_EXTERN_C void DGL_Vertex3fv(const float* vec) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -237,6 +230,7 @@ DENG_EXTERN_C void DGL_Vertex3fv(const float* vec) glVertex3fv(vec); } +#undef DGL_Vertices2ftv DENG_EXTERN_C void DGL_Vertices2ftv(int num, const dgl_ft2vertex_t* vec) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -249,6 +243,7 @@ DENG_EXTERN_C void DGL_Vertices2ftv(int num, const dgl_ft2vertex_t* vec) } } +#undef DGL_Vertices3ftv DENG_EXTERN_C void DGL_Vertices3ftv(int num, const dgl_ft3vertex_t* vec) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -261,6 +256,7 @@ DENG_EXTERN_C void DGL_Vertices3ftv(int num, const dgl_ft3vertex_t* vec) } } +#undef DGL_Vertices3fctv DENG_EXTERN_C void DGL_Vertices3fctv(int num, const dgl_fct3vertex_t* vec) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -274,6 +270,7 @@ DENG_EXTERN_C void DGL_Vertices3fctv(int num, const dgl_fct3vertex_t* vec) } } +#undef DGL_Begin DENG_EXTERN_C void DGL_Begin(dglprimtype_t mode) { if(novideo) @@ -300,6 +297,7 @@ DENG_EXTERN_C void DGL_Begin(dglprimtype_t mode) DGL_QUAD_STRIP ? GL_QUAD_STRIP : GL_QUADS); } +#undef DGL_End DENG_EXTERN_C void DGL_End(void) { if(novideo) @@ -320,51 +318,64 @@ DENG_EXTERN_C void DGL_End(void) #endif } +#undef DGL_NewList DENG_EXTERN_C boolean DGL_NewList(DGLuint list, int mode) { return GL_NewList(list, mode); } +#undef DGL_EndList DENG_EXTERN_C DGLuint DGL_EndList(void) { return GL_EndList(); } +#undef DGL_CallList DENG_EXTERN_C void DGL_CallList(DGLuint list) { GL_CallList(list); } +#undef DGL_DeleteLists DENG_EXTERN_C void DGL_DeleteLists(DGLuint list, int range) { GL_DeleteLists(list, range); } -DENG_EXTERN_C void DGL_DrawLine(float x1, float y1, float x2, float y2, float r, float g, float b, float a) +#undef DGL_DrawLine +DENG_EXTERN_C void DGL_DrawLine(float x1, float y1, float x2, float y2, float r, + float g, float b, float a) { GL_DrawLine(x1, y1, x2, y2, r, g, b, a); } -DENG_EXTERN_C void DGL_DrawRect(const RectRaw* rect) +#undef DGL_DrawRect +DENG_EXTERN_C void DGL_DrawRect(RectRaw const *rect) { - GL_DrawRect(rect); + if(!rect) return; + GL_DrawRect(Rectanglei::fromSize(Vector2i(rect->origin.xy), + Vector2ui(rect->size.width, rect->size.height))); } +#undef DGL_DrawRect2 DENG_EXTERN_C void DGL_DrawRect2(int x, int y, int w, int h) { GL_DrawRect2(x, y, w, h); } -DENG_EXTERN_C void DGL_DrawRectf(const RectRawf* rect) +#undef DGL_DrawRectf +DENG_EXTERN_C void DGL_DrawRectf(RectRawf const *rect) { GL_DrawRectf(rect); } +#undef DGL_DrawRectf2 DENG_EXTERN_C void DGL_DrawRectf2(double x, double y, double w, double h) { GL_DrawRectf2(x, y, w, h); } +#undef DGL_DrawRectf2Color DENG_EXTERN_C void DGL_DrawRectf2Color(double x, double y, double w, double h, float r, float g, float b, float a) { DENG_ASSERT_IN_MAIN_THREAD(); @@ -374,25 +385,29 @@ DENG_EXTERN_C void DGL_DrawRectf2Color(double x, double y, double w, double h, f GL_DrawRectf2(x, y, w, h); } +#undef DGL_DrawRectf2Tiled DENG_EXTERN_C void DGL_DrawRectf2Tiled(double x, double y, double w, double h, int tw, int th) { GL_DrawRectf2Tiled(x, y, w, h, tw, th); } -DENG_EXTERN_C void DGL_DrawCutRectfTiled(const RectRawf* rect, int tw, int th, int txoff, int tyoff, - const RectRawf* cutRect) +#undef DGL_DrawCutRectfTiled +DENG_EXTERN_C void DGL_DrawCutRectfTiled(RectRawf const *rect, int tw, int th, int txoff, int tyoff, + RectRawf const *cutRect) { GL_DrawCutRectfTiled(rect, tw, th, txoff, tyoff, cutRect); } +#undef DGL_DrawCutRectf2Tiled DENG_EXTERN_C void DGL_DrawCutRectf2Tiled(double x, double y, double w, double h, int tw, int th, int txoff, int tyoff, double cx, double cy, double cw, double ch) { GL_DrawCutRectf2Tiled(x, y, w, h, tw, th, txoff, tyoff, cx, cy, cw, ch); } -DENG_EXTERN_C void DGL_DrawQuadOutline(const Point2Raw* tl, const Point2Raw* tr, const Point2Raw* br, - const Point2Raw* bl, const float color[4]) +#undef DGL_DrawQuadOutline +DENG_EXTERN_C void DGL_DrawQuadOutline(Point2Raw const *tl, Point2Raw const *tr, + Point2Raw const *br, Point2Raw const *bl, float const color[4]) { if(!tl || !tr || !br || !bl || (color && !(color[CA] > 0))) return; @@ -408,8 +423,9 @@ DENG_EXTERN_C void DGL_DrawQuadOutline(const Point2Raw* tl, const Point2Raw* tr, glEnd(); } -DENG_EXTERN_C void DGL_DrawQuad2Outline(int tlX, int tlY, int trX, int trY, int brX, int brY, int blX, - int blY, const float color[4]) +#undef DGL_DrawQuad2Outline +DENG_EXTERN_C void DGL_DrawQuad2Outline(int tlX, int tlY, int trX, int trY, + int brX, int brY, int blX, int blY, const float color[4]) { Point2Raw tl, tr, bl, br; tl.x = tlX; diff --git a/doomsday/client/src/gl/gl_draw.cpp b/doomsday/client/src/gl/gl_draw.cpp index 1ede56b70b..b641ed5ee5 100644 --- a/doomsday/client/src/gl/gl_draw.cpp +++ b/doomsday/client/src/gl/gl_draw.cpp @@ -40,54 +40,40 @@ using namespace de; static bool drawFilter = false; static Vector4f filterColor; -void GL_DrawRectWithCoords(RectRaw const *rect, Vector2i coords[4]) +void GL_DrawRectWithCoords(Rectanglei const &rect, Vector2i const coords[4]) { - if(!rect) return; - DENG_ASSERT_IN_MAIN_THREAD(); DENG_ASSERT_GL_CONTEXT_ACTIVE(); glBegin(GL_QUADS); - // Upper left. + // Top left. if(coords) glTexCoord2i(coords[0].x, coords[0].y); - glVertex2f(rect->origin.x, rect->origin.y); + glVertex2f(rect.topLeft.x, rect.topLeft.y); - // Upper Right. + // Top Right. if(coords) glTexCoord2i(coords[1].x, coords[1].y); - glVertex2f(rect->origin.x + rect->size.width, rect->origin.y); + glVertex2f(rect.topRight().x, rect.topRight().y); - // Lower right. + // Bottom right. if(coords) glTexCoord2i(coords[2].x, coords[2].y); - glVertex2f(rect->origin.x + rect->size.width, rect->origin.y + rect->size.height); + glVertex2f(rect.bottomRight.x, rect.bottomRight.y); - // Lower left. + // Bottom left. if(coords) glTexCoord2i(coords[3].x, coords[3].y); - glVertex2f(rect->origin.x, rect->origin.y + rect->size.height); + glVertex2f(rect.bottomLeft().x, rect.bottomLeft().y); glEnd(); } -void GL_DrawRect(RectRaw const *rect) +void GL_DrawRect(Rectanglei const &rect) { - Vector2i coords[4]; - coords[0].x = 0; - coords[0].y = 0; - coords[1].x = 1; - coords[1].y = 0; - coords[2].x = 1; - coords[2].y = 1; - coords[3].x = 0; - coords[3].y = 1; + Vector2i coords[4] = { Vector2i(0, 0), Vector2i(1, 0), + Vector2i(1, 1), Vector2i(0, 1) }; GL_DrawRectWithCoords(rect, coords); } void GL_DrawRect2(int x, int y, int w, int h) { - RectRaw rect; - rect.origin.x = x; - rect.origin.y = y; - rect.size.width = w; - rect.size.height = h; - GL_DrawRect(&rect); + GL_DrawRect(Rectanglei::fromSize(Vector2i(x, y), Vector2ui(w, h))); } void GL_DrawRectfWithCoords(const RectRawf* rect, Point2Rawf coords[4]) diff --git a/doomsday/client/src/render/rend_font.cpp b/doomsday/client/src/render/rend_font.cpp index b3a8ac422e..bdb6f259e0 100644 --- a/doomsday/client/src/render/rend_font.cpp +++ b/doomsday/client/src/render/rend_font.cpp @@ -96,13 +96,13 @@ typedef struct { } caseMod[2]; // 1=upper, 0=lower } drawtextstate_t; -static void drawChar(unsigned char ch, int posX, int posY, AbstractFont *font, int alignFlags, short textFlags); +static void drawChar(uchar ch, float posX, float posY, AbstractFont *font, int alignFlags, short textFlags); static void drawFlash(Point2Raw const *origin, Size2Raw const *size, bool bright); static int inited = false; static char smallTextBuffer[FR_SMALL_TEXT_BUFFER_SIZE+1]; -static char* largeTextBuffer = NULL; +static char *largeTextBuffer = NULL; static size_t largeTextBufferSize = 0; static int typeInTime; @@ -123,14 +123,6 @@ static int topToAscent(AbstractFont *font) return lineHeight - font->ascent(); } -static int lineHeight(AbstractFont *font, unsigned char ch) -{ - int ascent = font->ascent(); - if(ascent != 0) - return ascent; - return font->charHeight(ch); -} - static inline fr_state_attributes_t *currentAttribs(void) { return fr.attribStack + fr.attribStackDepth; @@ -419,32 +411,32 @@ void FR_SetCaseScale(boolean value) } #undef FR_CharSize -void FR_CharSize(Size2Raw *size, unsigned char ch) +void FR_CharSize(Size2Raw *size, uchar ch) { errorIfNotInited("FR_CharSize"); if(size) { - Vector2i dimensions = App_Fonts().toFont(fr.fontNum)->charSize(ch); + Vector2ui dimensions = App_Fonts().toFont(fr.fontNum)->charPosCoords(ch).size(); size->width = dimensions.x; size->height = dimensions.y; } } #undef FR_CharWidth -int FR_CharWidth(unsigned char ch) +int FR_CharWidth(uchar ch) { errorIfNotInited("FR_CharWidth"); if(fr.fontNum != 0) - return App_Fonts().toFont(fr.fontNum)->charWidth(ch); + return App_Fonts().toFont(fr.fontNum)->charPosCoords(ch).width(); return 0; } #undef FR_CharHeight -int FR_CharHeight(unsigned char ch) +int FR_CharHeight(uchar ch) { errorIfNotInited("FR_CharHeight"); if(fr.fontNum != 0) - return App_Fonts().toFont(fr.fontNum)->charHeight(ch); + return App_Fonts().toFont(fr.fontNum)->charPosCoords(ch).height(); return 0; } @@ -456,7 +448,7 @@ int FR_SingleLineHeight(char const *text) int ascent = App_Fonts().toFont(fr.fontNum)->ascent(); if(ascent != 0) return ascent; - return App_Fonts().toFont(fr.fontNum)->charHeight((unsigned char)text[0]); + return App_Fonts().toFont(fr.fontNum)->charPosCoords((uchar)text[0]).height(); } int FR_GlyphTopToAscent(char const *text) @@ -750,78 +742,67 @@ static void textFragmentDrawer(const char* fragment, int x, int y, int alignFlag } } -static void drawChar(unsigned char ch, int posX, int posY, AbstractFont *font, +static void drawChar(uchar ch, float x, float y, AbstractFont *font, int alignFlags, short /*textFlags*/) { - float x = (float) posX, y = (float) posY; - Vector2i coords[4]; - RectRaw geometry; - if(alignFlags & ALIGN_RIGHT) { - x -= font->charWidth(ch); + x -= font->charPosCoords(ch).width(); } else if(!(alignFlags & ALIGN_LEFT)) { - x -= font->charWidth(ch) / 2; + x -= font->charPosCoords(ch).width() / 2; } + int const ascent = font->ascent(); + int const lineHeight = ascent? ascent : font->charPosCoords(ch).height(); if(alignFlags & ALIGN_BOTTOM) { - y -= topToAscent(font) + lineHeight(font, ch); + y -= topToAscent(font) + lineHeight; } else if(!(alignFlags & ALIGN_TOP)) { - y -= (topToAscent(font) + lineHeight(font, ch))/2; + y -= (topToAscent(font) + lineHeight) / 2; } glMatrixMode(GL_MODELVIEW); glTranslatef(x, y, 0); + Rectanglei geometry = font->charPosCoords(ch); + if(BitmapFont *bmapFont = font->maybeAs()) { /// @todo Filtering should be determined at a higher level. /// @todo We should not need to re-bind this texture here. GL_BindTextureUnmanaged(bmapFont->textureGLName(), gl::ClampToEdge, gl::ClampToEdge, filterUI? gl::Linear : gl::Nearest); - - std::memcpy(&geometry, bmapFont->charGeometry(ch), sizeof(geometry)); - bmapFont->charCoords(ch, coords); } else if(CompositeBitmapFont *compFont = font->maybeAs()) { - uint8_t const border = compFont->charBorder(ch); - GL_BindTexture(compFont->charTexture(ch)); - - std::memcpy(&geometry, compFont->charGeometry(ch), sizeof(geometry)); - if(border) + if(uint border = compFont->charBorder(ch)) { - geometry.origin.x -= border; - geometry.origin.y -= border; - geometry.size.width += border*2; - geometry.size.height += border*2; + geometry = geometry.expanded(border); } - compFont->charCoords(ch, coords); - } - else - { - // Unknown font type!? - DENG2_ASSERT(false); } if(font->_margin.x) { - geometry.origin.x -= font->_margin.x; - geometry.size.width += font->_margin.x * 2; + geometry.topLeft.x -= font->_margin.x; + geometry.setWidth(geometry.width() + font->_margin.x * 2); } if(font->_margin.y) { - geometry.origin.y -= font->_margin.y; - geometry.size.height += font->_margin.y * 2; + geometry.topLeft.y -= font->_margin.y; + geometry.setHeight(geometry.height() + font->_margin.y * 2); } - GL_DrawRectWithCoords(&geometry, coords); + Vector2i coords[4] = { font->charTexCoords(ch).topLeft, + font->charTexCoords(ch).topRight(), + font->charTexCoords(ch).bottomRight, + font->charTexCoords(ch).bottomLeft() }; + + GL_DrawRectWithCoords(geometry, coords); if(font->is()) { diff --git a/doomsday/client/src/resource/abstractfont.cpp b/doomsday/client/src/resource/abstractfont.cpp index 85d270cbfb..b3963ce6b9 100644 --- a/doomsday/client/src/resource/abstractfont.cpp +++ b/doomsday/client/src/resource/abstractfont.cpp @@ -36,11 +36,6 @@ void AbstractFont::glInit() void AbstractFont::glDeinit() {} -Vector2i AbstractFont::charSize(unsigned char ch) -{ - return Vector2i(charWidth(ch), charHeight(ch)); -} - fontid_t AbstractFont::primaryBind() const { return _primaryBind; diff --git a/doomsday/client/src/resource/bitmapfont.cpp b/doomsday/client/src/resource/bitmapfont.cpp index 01c812e131..0481581dc9 100644 --- a/doomsday/client/src/resource/bitmapfont.cpp +++ b/doomsday/client/src/resource/bitmapfont.cpp @@ -51,8 +51,8 @@ DENG2_PIMPL(BitmapFont) Vector2i texDimensions; ///< Texture dimensions in pixels. bool needGLInit; - /// Character map. - bitmapfont_char_t chars[MAX_CHARS]; + bitmapfont_char_t glyphs[MAX_CHARS]; + bitmapfont_char_t missingGlyph; Instance(Public *i) : Base(i) @@ -60,7 +60,8 @@ DENG2_PIMPL(BitmapFont) , needGLInit(true) { Str_Init(&filePath); - zap(chars); + zap(glyphs); + zap(missingGlyph); } ~Instance() @@ -68,6 +69,12 @@ DENG2_PIMPL(BitmapFont) self.glDeinit(); } + bitmapfont_char_t &glyph(uchar ch) + { + if(ch >= MAX_CHARS) return missingGlyph; + return glyphs[ch]; + } + void *readFormat0(de::FileHandle *file) { DENG2_ASSERT(file != 0); @@ -84,31 +91,26 @@ DENG2_PIMPL(BitmapFont) Vector2ui avgSize; for(int i = 0; i < glyphCount; ++i) { - bitmapfont_char_t *ch = &chars[i < MAX_CHARS ? i : MAX_CHARS - 1]; + bitmapfont_char_t *ch = &glyphs[i < MAX_CHARS ? i : MAX_CHARS - 1]; ushort x = inShort(file); ushort y = inShort(file); ushort w = inByte(file); ushort h = inByte(file); - ch->geometry.topLeft = Vector2i(0, 0); - ch->geometry.setSize(Vector2ui(w, h) - self._margin * 2); - - ch->coords[0] = Vector2i(x, y); // Top left. - ch->coords[2] = Vector2i(x + w, y + h); // Bottom right. - ch->coords[1] = Vector2i(ch->coords[2].x, ch->coords[0].y); // Top right. - ch->coords[3] = Vector2i(ch->coords[0].x, ch->coords[2].y); // Bottom left. + ch->geometry = Rectanglei::fromSize(Vector2i(0, 0), Vector2ui(w, h) - self._margin * 2); + ch->coords = Rectanglei::fromSize(Vector2i(x, y), Vector2ui(w, h)); avgSize += ch->geometry.size(); } - self._noCharSize = avgSize / glyphCount; + missingGlyph.geometry.setSize(avgSize / glyphCount); // Load the bitmap. int bitmapFormat = inByte(file); if(bitmapFormat > 0) { de::Uri uri = App_Fonts().composeUri(App_Fonts().id(thisPublic)); - throw Error("BitmapFont::readFormat0", QString("Font \"%1\" uses unknown bitmap bitmapFormat %2").arg(uri).arg(bitmapFormat)); + throw Error("BitmapFont::readFormat0", QString("Font \"%1\" uses unknown format '%2'").arg(uri).arg(bitmapFormat)); } int numPels = texDimensions.x * texDimensions.y; @@ -139,7 +141,7 @@ DENG2_PIMPL(BitmapFont) if(bitmapFormat != 1 && bitmapFormat != 0) // Luminance + Alpha. { de::Uri uri = App_Fonts().composeUri(App_Fonts().id(thisPublic)); - throw Error("BitmapFont::readFormat2", QString("Font \"%1\" uses unknown bitmap bitmapFormat %2").arg(uri).arg(bitmapFormat)); + throw Error("BitmapFont::readFormat2", QString("Font \"%1\" uses unknown format '%2'").arg(uri).arg(bitmapFormat)); } self._flags |= FF_COLORIZE|FF_SHADOWED; @@ -163,20 +165,15 @@ DENG2_PIMPL(BitmapFont) ushort y = inShort(file); ushort w = inShort(file); ushort h = inShort(file); - bitmapfont_char_t *ch = &chars[code]; + bitmapfont_char_t *ch = &glyphs[code]; - ch->geometry.topLeft = Vector2i(0, 0); - ch->geometry.setSize(self._margin * 2 - Vector2ui(w, h)); - - ch->coords[0] = Vector2i(x, y); // Top left. - ch->coords[2] = Vector2i(x + w, y + h); // Bottom right. - ch->coords[1] = Vector2i(ch->coords[2].x, ch->coords[0].y); // Top right. - ch->coords[3] = Vector2i(ch->coords[0].x, ch->coords[2].y); // Bottom left. + ch->geometry = Rectanglei::fromSize(Vector2i(0, 0), self._margin * 2 - Vector2ui(w, h)); + ch->coords = Rectanglei::fromSize(Vector2i(x, y), Vector2ui(w, h)); avgSize += ch->geometry.size(); } - self._noCharSize = avgSize / glyphCount; + missingGlyph.geometry.setSize(avgSize / glyphCount); // Read the bitmap. int numPels = texDimensions.x * texDimensions.y; @@ -232,24 +229,16 @@ BitmapFont *BitmapFont::fromFile(fontid_t bindId, char const *resourcePath) // s return font; } -de::Rectanglei const &BitmapFont::charGeometry(unsigned char chr) +Rectanglei const &BitmapFont::charPosCoords(uchar ch) { glInit(); - return d->chars[chr].geometry; + return d->glyph(ch).geometry; } -int BitmapFont::charWidth(unsigned char ch) +Rectanglei const &BitmapFont::charTexCoords(uchar ch) { glInit(); - if(d->chars[ch].geometry.width() == 0) return _noCharSize.x; - return d->chars[ch].geometry.width(); -} - -int BitmapFont::charHeight(unsigned char ch) -{ - glInit(); - if(d->chars[ch].geometry.height() == 0) return _noCharSize.y; - return d->chars[ch].geometry.height(); + return d->glyph(ch).coords; } void BitmapFont::glInit() @@ -338,10 +327,3 @@ Vector2i const &BitmapFont::textureDimensions() const { return d->texDimensions; } - -void BitmapFont::charCoords(unsigned char chr, Vector2i coords[4]) -{ - if(!coords) return; - glInit(); - std::memcpy(coords, d->chars[chr].coords, sizeof(*coords) * 4); -} diff --git a/doomsday/client/src/resource/compositebitmapfont.cpp b/doomsday/client/src/resource/compositebitmapfont.cpp index ed509703eb..4afec3b75c 100644 --- a/doomsday/client/src/resource/compositebitmapfont.cpp +++ b/doomsday/client/src/resource/compositebitmapfont.cpp @@ -33,15 +33,16 @@ DENG2_PIMPL(CompositeBitmapFont) ded_compositefont_t *def; /// Definition on which "this" font is derived (if any). bool needGLInit; - /// Character map. - bitmapcompositefont_char_t chars[MAX_CHARS]; + bitmapcompositefont_char_t glyphs[MAX_CHARS]; + bitmapcompositefont_char_t missingGlyph; Instance(Public *i) : Base(i) , def(0) , needGLInit(true) { - zap(chars); + zap(glyphs); + zap(missingGlyph); self._flags |= FF_COLORIZE; } @@ -49,6 +50,13 @@ DENG2_PIMPL(CompositeBitmapFont) { self.glDeinit(); } + + bitmapcompositefont_char_t &glyph(uchar ch) + { + if(ch >= MAX_CHARS) return missingGlyph; + if(!glyphs[ch].haveSourceImage) return missingGlyph; + return glyphs[ch]; + } }; CompositeBitmapFont::CompositeBitmapFont(fontid_t bindId) @@ -57,27 +65,47 @@ CompositeBitmapFont::CompositeBitmapFont(fontid_t bindId) setPrimaryBind(bindId); } -Rectanglei const &CompositeBitmapFont::charGeometry(uchar chr) +Rectanglei const &CompositeBitmapFont::charPosCoords(uchar ch) +{ + glInit(); + return d->glyph(ch).geometry; +} + +Rectanglei const &CompositeBitmapFont::charTexCoords(uchar /*ch*/) { + static Rectanglei coords(Vector2i(0, 0), Vector2i(1, 1)); glInit(); - return d->chars[chr].geometry; + return coords; } -int CompositeBitmapFont::charWidth(uchar ch) +uint CompositeBitmapFont::charBorder(uchar ch) { glInit(); - if(d->chars[ch].geometry.width() == 0) return _noCharSize.x; - return d->chars[ch].geometry.width(); + return d->glyph(ch).border; } -int CompositeBitmapFont::charHeight(uchar ch) +TextureVariant *CompositeBitmapFont::charTexture(uchar ch) +{ + glInit(); + return d->glyph(ch).tex; +} + +patchid_t CompositeBitmapFont::charPatch(uchar ch) { glInit(); - if(d->chars[ch].geometry.height() == 0) return _noCharSize.y; - return d->chars[ch].geometry.height(); + return d->glyph(ch).patch; } -static texturevariantspecification_t &charTextureSpec() +void CompositeBitmapFont::charSetPatch(uchar ch, char const *encodedPatchName) +{ + if(ch >= MAX_CHARS) return; + d->glyphs[ch].patch = App_ResourceSystem().declarePatch(encodedPatchName); + + // We'll need to rebuild the prepared GL resources. + d->needGLInit = true; +} + +static texturevariantspecification_t &glyphTextureSpec() { return GL_TextureVariantSpec(TC_UI, TSF_MONOCHROME | TSF_UPSCALE_AND_SHARPEN, 0, 0, 0, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, @@ -91,39 +119,37 @@ void CompositeBitmapFont::glInit() glDeinit(); - int numPatches = 0; + int foundGlyphs = 0; Vector2ui avgSize; for(int i = 0; i < MAX_CHARS; ++i) { - bitmapcompositefont_char_t *ch = &d->chars[i]; + bitmapcompositefont_char_t *ch = &d->glyphs[i]; patchid_t patch = ch->patch; - patchinfo_t info; - if(0 == patch) continue; + ch->haveSourceImage = patch != 0; + if(!ch->haveSourceImage) continue; + patchinfo_t info; R_GetPatchInfo(patch, &info); - ch->geometry.topLeft = Vector2i(info.geometry.origin.xy) - Vector2i(_margin.x, _margin.y); - ch->geometry.setSize(_margin * 2 + - Vector2ui(info.geometry.size.width, info.geometry.size.height)); - ch->border = 0; ch->tex = App_ResourceSystem().textures() .scheme("Patches").findByUniqueId(patch) - .texture().prepareVariant(charTextureSpec()); + .texture().prepareVariant(glyphTextureSpec()); + ch->border = 0; if(ch->tex && ch->tex->source() == TEXS_ORIGINAL) { // Upscale & Sharpen will have been applied. ch->border = 1; } + ch->geometry = Rectanglei::fromSize(Vector2i(info.geometry.origin.xy), + Vector2ui(info.geometry.size.width, info.geometry.size.height)) + .expanded(_margin.toVector2i()); + avgSize += ch->geometry.size(); - ++numPatches; + ++foundGlyphs; } - if(numPatches) - { - avgSize /= numPatches; - } - _noCharSize = avgSize; + d->missingGlyph.geometry.setSize(avgSize / (foundGlyphs? foundGlyphs : 1)); // We have prepared all patches. d->needGLInit = false; @@ -138,7 +164,7 @@ void CompositeBitmapFont::glDeinit() for(int i = 0; i < 256; ++i) { - bitmapcompositefont_char_t *ch = &d->chars[i]; + bitmapcompositefont_char_t *ch = &d->glyphs[i]; if(!ch->tex) continue; GL_ReleaseVariantTexture(*ch->tex); ch->tex = 0; @@ -205,41 +231,3 @@ void CompositeBitmapFont::rebuildFromDef(ded_compositefont_t *newDef) } } } - -TextureVariant *CompositeBitmapFont::charTexture(uchar ch) -{ - glInit(); - return d->chars[ch].tex; -} - -patchid_t CompositeBitmapFont::charPatch(uchar ch) -{ - glInit(); - return d->chars[ch].patch; -} - -void CompositeBitmapFont::charSetPatch(uchar chr, char const *encodedPatchName) -{ - bitmapcompositefont_char_t *ch = &d->chars[chr]; - ch->patch = App_ResourceSystem().declarePatch(encodedPatchName); - d->needGLInit = true; -} - -uint8_t CompositeBitmapFont::charBorder(uchar chr) -{ - bitmapcompositefont_char_t *ch = &d->chars[chr]; - glInit(); - return ch->border; -} - -void CompositeBitmapFont::charCoords(uchar /*chr*/, Vector2i coords[4]) -{ - if(!coords) return; - - glInit(); - - coords[0] = Vector2i(0, 0); // Top left. - coords[2] = Vector2i(1, 1); // Bottom right. - coords[1] = Vector2i(1, 0); // Top right. - coords[3] = Vector2i(0, 1); // Bottom left. -} diff --git a/doomsday/libdeng2/include/de/core/rectangle.h b/doomsday/libdeng2/include/de/core/rectangle.h index 5fa24a0846..3cd3f7265a 100644 --- a/doomsday/libdeng2/include/de/core/rectangle.h +++ b/doomsday/libdeng2/include/de/core/rectangle.h @@ -103,9 +103,15 @@ class Rectangle RectangleType expanded(Type n) const { return RectangleType(topLeft - Corner(n, n), bottomRight + Corner(n, n)); } + RectangleType expanded(Corner delta) const { + return RectangleType(topLeft - delta, bottomRight + delta); + } RectangleType shrunk(Type n) const { return RectangleType(topLeft + Corner(n, n), bottomRight - Corner(n, n)); } + RectangleType shrunk(Corner delta) const { + return RectangleType(topLeft + delta, bottomRight - delta); + } RectangleType adjusted(CornerVectorType const &tl, CornerVectorType const &br) const { return RectangleType(topLeft + tl, bottomRight + br); }