diff --git a/examples/10-font/font.cpp b/examples/10-font/font.cpp index 0309defb..d8c1d7ea 100644 --- a/examples/10-font/font.cpp +++ b/examples/10-font/font.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include "../common/entry.h" #include "../common/dbg.h" #include "../common/math.h" @@ -19,12 +19,12 @@ int _main_(int /*_argc*/, char** /*_argv*/) { - uint32_t width = 1280; + uint32_t width = 1280; uint32_t height = 720; uint32_t debug = BGFX_DEBUG_TEXT; uint32_t reset = 0; - bgfx::init(); + bgfx::init(); bgfx::reset(width, height); @@ -33,20 +33,21 @@ int _main_(int /*_argc*/, char** /*_argv*/) // Set view 0 clear state. bgfx::setViewClear(0 - , BGFX_CLEAR_COLOR_BIT|BGFX_CLEAR_DEPTH_BIT - , 0x303030ff - , 1.0f - , 0 - ); - + , BGFX_CLEAR_COLOR_BIT | BGFX_CLEAR_DEPTH_BIT + , 0x303030ff + , 1.0f + , 0 + ); + //init the text rendering system FontManager* fontManager = new FontManager(512); TextBufferManager* textBufferManager = new TextBufferManager(fontManager); //load some truetype files - const char* fontNames[7] = { + const char* fontNames[7] = + { "font/droidsans.ttf", - "font/chp-fire.ttf", + "font/chp-fire.ttf", "font/bleeding_cowboys.ttf", "font/mias_scribblings.ttf", "font/ruritania.ttf", @@ -54,11 +55,11 @@ int _main_(int /*_argc*/, char** /*_argv*/) "font/five_minutes.otf" }; - const uint32_t fontCount = sizeof(fontNames)/sizeof(const char*); - + const uint32_t fontCount = sizeof(fontNames) / sizeof(const char*); + TrueTypeHandle fontFiles[fontCount]; FontHandle fonts[fontCount]; - for(int32_t ii = 0; iiloadTrueTypeFromFile(fontNames[ii]); @@ -68,43 +69,43 @@ int _main_(int /*_argc*/, char** /*_argv*/) //You can unload the truetype files at this stage, but in that case, the set of glyph's will be limited to the set of preloaded glyph fontManager->unloadTrueType(fontFiles[ii]); } - + TrueTypeHandle console_tt = fontManager->loadTrueTypeFromFile("font/visitor1.ttf"); //this font doesn't have any preloaded glyph's but the truetype file is loaded //so glyph will be generated as needed FontHandle consola_16 = fontManager->createFontByPixelSize(console_tt, 0, 10); - + //create a static text buffer compatible with alpha font //a static text buffer content cannot be modified after its first submit. TextBufferHandle staticText = textBufferManager->createTextBuffer(FONT_TYPE_ALPHA, STATIC); - + //the pen position represent the top left of the box of the first line of text textBufferManager->setPenPosition(staticText, 24.0f, 100.0f); - for(int32_t ii = 0; iiappendText(staticText, fonts[ii], L"The quick brown fox jumps over the lazy dog\n"); //the position of the pen is adjusted when there is an endline } - // Now write some styled text - - //setup style colors + // Now write some styled text + + //setup style colors textBufferManager->setBackgroundColor(staticText, 0x551111FF); textBufferManager->setUnderlineColor(staticText, 0xFF2222FF); textBufferManager->setOverlineColor(staticText, 0x2222FFFF); - textBufferManager->setStrikeThroughColor(staticText, 0x22FF22FF); + textBufferManager->setStrikeThroughColor(staticText, 0x22FF22FF); //text + bkg textBufferManager->setStyle(staticText, STYLE_BACKGROUND); textBufferManager->appendText(staticText, fonts[0], L"The quick "); - + //text + strike-through textBufferManager->setStyle(staticText, STYLE_STRIKE_THROUGH); textBufferManager->appendText(staticText, fonts[0], L"brown fox "); - + //text + overline textBufferManager->setStyle(staticText, STYLE_OVERLINE); textBufferManager->appendText(staticText, fonts[0], L"jumps over "); @@ -112,25 +113,25 @@ int _main_(int /*_argc*/, char** /*_argv*/) //text + underline textBufferManager->setStyle(staticText, STYLE_UNDERLINE); textBufferManager->appendText(staticText, fonts[0], L"the lazy "); - + //text + bkg + strike-through - textBufferManager->setStyle(staticText, STYLE_BACKGROUND|STYLE_STRIKE_THROUGH); + textBufferManager->setStyle(staticText, STYLE_BACKGROUND | STYLE_STRIKE_THROUGH); textBufferManager->appendText(staticText, fonts[0], L"dog\n"); - - - //create a transient buffer for realtime data - TextBufferHandle transientText = textBufferManager->createTextBuffer(FONT_TYPE_ALPHA, TRANSIENT); - - uint32_t w = 0,h = 0; - while (!processEvents(width, height, debug, reset) ) + + //create a transient buffer for realtime data + TextBufferHandle transientText = textBufferManager->createTextBuffer(FONT_TYPE_ALPHA, TRANSIENT); + + uint32_t w = 0, h = 0; + while (!processEvents(width, height, debug, reset) ) { - - if(w!=width|| h!=height) + if (w != width + || h != height) { - w=width; - h= height; - printf("ri: %d,%d\n",width,height); + w = width; + h = height; + printf("ri: %d,%d\n", width, height); } + // Set view 0 default viewport. bgfx::setViewRect(0, 0, 0, width, height); @@ -143,35 +144,35 @@ int _main_(int /*_argc*/, char** /*_argv*/) const int64_t frameTime = now - last; last = now; const double freq = double(bx::getHPFrequency() ); - const double toMs = 1000.0/freq; + const double toMs = 1000.0 / freq; // Use debug font to print information about this example. //bgfx::dbgTextClear(); //bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/10-font"); //bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Use the font system to display text and styled text."); //bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); - + //Use transient text to display debug information //Code below is similar to commented code above wchar_t fpsText[64]; //swprintf(fpsText,L"Frame: % 7.3f[ms]", double(frameTime)*toMs); - swprintf(fpsText, countof(fpsText), L"Frame: % 7.3f[ms]", double(frameTime)*toMs); - + swprintf(fpsText, countof(fpsText), L"Frame: % 7.3f[ms]", double(frameTime) * toMs); + textBufferManager->clearTextBuffer(transientText); - textBufferManager->setPenPosition(transientText, 20.0, 4.0f); - textBufferManager->appendText(transientText, consola_16, L"bgfx/examples/10-font\n"); + textBufferManager->setPenPosition(transientText, 20.0, 4.0f); + textBufferManager->appendText(transientText, consola_16, L"bgfx/examples/10-font\n"); textBufferManager->appendText(transientText, consola_16, L"Description: Use the font system to display text and styled text.\n"); textBufferManager->appendText(transientText, consola_16, fpsText); float at[3] = { 0, 0, 0.0f }; float eye[3] = {0, 0, -1.0f }; - + float view[16]; float proj[16]; mtxLookAt(view, eye, at); - //setup a top-left ortho matrix for screen space drawing + //setup a top-left ortho matrix for screen space drawing float centering = 0.5f; - mtxOrtho(proj, centering, width+centering,height+centering, centering,-1.0f, 1.0f); + mtxOrtho(proj, centering, width + centering, height + centering, centering, -1.0f, 1.0f); // Set view and projection matrix for view 0. bgfx::setViewTransform(0, view, proj); @@ -180,30 +181,29 @@ int _main_(int /*_argc*/, char** /*_argv*/) textBufferManager->submitTextBuffer(transientText, 0); //submit the static text - textBufferManager->submitTextBuffer(staticText, 0); - - // Advance to next frame. Rendering thread will be kicked to + textBufferManager->submitTextBuffer(staticText, 0); + + // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. bgfx::frame(); } - - + fontManager->unloadTrueType(console_tt); //destroy the fonts - fontManager->destroyFont(consola_16); - for(int32_t ii = 0; iidestroyFont(consola_16); + for (int32_t ii = 0; ii < fontCount; ++ii) { fontManager->destroyFont(fonts[ii]); } textBufferManager->destroyTextBuffer(staticText); - textBufferManager->destroyTextBuffer(transientText); + textBufferManager->destroyTextBuffer(transientText); delete textBufferManager; - delete fontManager; - + delete fontManager; + // Shutdown bgfx. - bgfx::shutdown(); + bgfx::shutdown(); return 0; } diff --git a/examples/11-fontsdf/fontsdf.cpp b/examples/11-fontsdf/fontsdf.cpp index c1f9d860..8fd4daef 100644 --- a/examples/11-fontsdf/fontsdf.cpp +++ b/examples/11-fontsdf/fontsdf.cpp @@ -16,7 +16,7 @@ inline void mtxTranslate(float* _result, float x, float y, float z) { - memset(_result, 0, sizeof(float)*16); + memset(_result, 0, sizeof(float) * 16); _result[0] = _result[5] = _result[10] = _result[15] = 1.0f; _result[12] = x; _result[13] = y; @@ -25,7 +25,7 @@ inline void mtxTranslate(float* _result, float x, float y, float z) inline void mtxScale(float* _result, float x, float y, float z) { - memset(_result, 0, sizeof(float)*16); + memset(_result, 0, sizeof(float) * 16); _result[0] = x; _result[5] = y; _result[10] = z; @@ -34,7 +34,7 @@ inline void mtxScale(float* _result, float x, float y, float z) int _main_(int /*_argc*/, char** /*_argv*/) { - uint32_t width = 1280; + uint32_t width = 1280; uint32_t height = 720; uint32_t debug = BGFX_DEBUG_TEXT; uint32_t reset = 0; @@ -48,14 +48,14 @@ int _main_(int /*_argc*/, char** /*_argv*/) // Set view 0 clear state. bgfx::setViewClear(0 - , BGFX_CLEAR_COLOR_BIT|BGFX_CLEAR_DEPTH_BIT - //, 0x303030ff - //, 0xffffffff - , 0x000000FF - , 1.0f - , 0 - ); - + , BGFX_CLEAR_COLOR_BIT | BGFX_CLEAR_DEPTH_BIT + //, 0x303030ff + //, 0xffffffff + , 0x000000FF + , 1.0f + , 0 + ); + //init the text rendering system FontManager* fontManager = new FontManager(512); TextBufferManager* textBufferManager = new TextBufferManager(fontManager); @@ -63,7 +63,7 @@ int _main_(int /*_argc*/, char** /*_argv*/) //load a truetype files /* "font/droidsans.ttf", - "font/chp-fire.ttf", + "font/chp-fire.ttf", "font/bleeding_cowboys.ttf", "font/mias_scribblings.ttf", "font/ruritania.ttf", @@ -71,29 +71,28 @@ int _main_(int /*_argc*/, char** /*_argv*/) "font/five_minutes.otf" */ TrueTypeHandle times_tt = fontManager->loadTrueTypeFromFile("font/bleeding_cowboys.ttf"); - + //create a distance field font FontHandle distance_font = fontManager->createFontByPixelSize(times_tt, 0, 48, FONT_TYPE_DISTANCE); //create a scalled down version of the same font (without adding anything to the atlas) FontHandle smaller_font = fontManager->createScaledFontToPixelSize(distance_font, 32); - + //preload glyph and generate (generate bitmap's) fontManager->preloadGlyph(distance_font, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,\" \n"); //You can unload the truetype files at this stage, but in that case, the set of glyph's will be limited to the set of preloaded glyph fontManager->unloadTrueType(times_tt); - - TextBufferHandle staticText = textBufferManager->createTextBuffer(FONT_TYPE_DISTANCE, STATIC); + + TextBufferHandle staticText = textBufferManager->createTextBuffer(FONT_TYPE_DISTANCE, STATIC); textBufferManager->setTextColor(staticText, 0xDD0000FF); - - //textBufferManager->appendText(staticText, distance_font, L"The quick brown fox jumps over the lazy dog\n"); + + //textBufferManager->appendText(staticText, distance_font, L"The quick brown fox jumps over the lazy dog\n"); //textBufferManager->appendText(staticText, distance_font, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n"); textBufferManager->appendText(staticText, distance_font, L"BGFX "); textBufferManager->appendText(staticText, smaller_font, L"bgfx"); - int64_t timeOffset = bx::getHPCounter(); - while (!processEvents(width, height, debug, reset) ) + while (!processEvents(width, height, debug, reset) ) { // Set view 0 default viewport. bgfx::setViewRect(0, 0, 0, width, height); @@ -107,14 +106,14 @@ int _main_(int /*_argc*/, char** /*_argv*/) const int64_t frameTime = now - last; last = now; const double freq = double(bx::getHPFrequency() ); - const double toMs = 1000.0/freq; - float time = (float)( (now - timeOffset)/double(bx::getHPFrequency() ) ); + const double toMs = 1000.0 / freq; + float time = (float)( (now - timeOffset) / double(bx::getHPFrequency() ) ); // Use debug font to print information about this example. bgfx::dbgTextClear(); bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/11-fontsdf"); bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Use a single distance field font to render text of various size."); - bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); + bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime) * toMs); float at[3] = { 0, 0, 0.0f }; float eye[3] = {0, 0, -1.0f }; @@ -124,48 +123,48 @@ int _main_(int /*_argc*/, char** /*_argv*/) mtxLookAt(view, eye, at); float centering = 0.5f; //setup a top-left ortho matrix for screen space drawing - mtxOrtho(proj, centering, width+centering,height+centering, centering,-1.0f, 1.0f); + mtxOrtho(proj, centering, width + centering, height + centering, centering, -1.0f, 1.0f); // Set view and projection matrix for view 0. - bgfx::setViewTransform(0, view, proj); + bgfx::setViewTransform(0, view, proj); TextRectangle rect = textBufferManager->getRectangle(staticText); float mtxA[16]; float mtxB[16]; float mtxC[16]; - mtxRotateZ(mtxA, time*0.37f); - mtxTranslate(mtxB, -(rect.width*0.5f), -(rect.height*0.5f), 0); - + mtxRotateZ(mtxA, time * 0.37f); + mtxTranslate(mtxB, -(rect.width * 0.5f), -(rect.height * 0.5f), 0); + mtxMul(mtxC, mtxB, mtxA); - - float scale=4.1f+4.0f*sinf(time); + + float scale = 4.1f + 4.0f * sinf(time); mtxScale(mtxA, scale, scale, 1.0f); mtxMul(mtxB, mtxC, mtxA); - - mtxTranslate(mtxC, ((width)*0.5f), ((height)*0.5f), 0); + + mtxTranslate(mtxC, ( (width) * 0.5f), ( (height) * 0.5f), 0); mtxMul(mtxA, mtxB, mtxC); - + // Set model matrix for rendering. bgfx::setTransform(mtxA); //draw your text - textBufferManager->submitTextBuffer(staticText, 0); + textBufferManager->submitTextBuffer(staticText, 0); - // Advance to next frame. Rendering thread will be kicked to + // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. bgfx::frame(); } - //destroy the fonts + //destroy the fonts fontManager->destroyFont(distance_font); - fontManager->destroyFont(smaller_font); - - textBufferManager->destroyTextBuffer(staticText); + fontManager->destroyFont(smaller_font); + + textBufferManager->destroyTextBuffer(staticText); delete textBufferManager; - delete fontManager; + delete fontManager; // Shutdown bgfx. - bgfx::shutdown(); + bgfx::shutdown(); return 0; } diff --git a/examples/common/cube_atlas.cpp b/examples/common/cube_atlas.cpp index f68f93ba..4dd552f7 100644 --- a/examples/common/cube_atlas.cpp +++ b/examples/common/cube_atlas.cpp @@ -5,67 +5,74 @@ #include "cube_atlas.h" #include -#include +#include #include - //********** Rectangle packer implementation ************ class RectanglePacker -{ +{ public: - RectanglePacker(); - RectanglePacker(uint32_t _width, uint32_t _height); - - /// non constructor initialization - void init(uint32_t _width, uint32_t _height); - /// find a suitable position for the given rectangle - /// @return true if the rectangle can be added, false otherwise - bool addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX, uint16_t& _outY ); - /// return the used surface in squared unit - uint32_t getUsedSurface() { return m_usedSpace; } - /// return the total available surface in squared unit - uint32_t getTotalSurface() { return m_width*m_height; } - /// return the usage ratio of the available surface [0:1] - float getUsageRatio(); - /// reset to initial state - void clear(); +RectanglePacker(); +RectanglePacker(uint32_t _width, uint32_t _height); + +/// non constructor initialization +void init(uint32_t _width, uint32_t _height); +/// find a suitable position for the given rectangle +/// @return true if the rectangle can be added, false otherwise +bool addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX, uint16_t& _outY); +/// return the used surface in squared unit +uint32_t getUsedSurface() +{ + return m_usedSpace; +} +/// return the total available surface in squared unit +uint32_t getTotalSurface() +{ + return m_width * m_height; +} +/// return the usage ratio of the available surface [0:1] +float getUsageRatio(); +/// reset to initial state +void clear(); private: - int32_t fit(uint32_t _skylineNodeIndex, uint16_t _width, uint16_t _height); - /// Merges all skyline nodes that are at the same level. - void merge(); +int32_t fit(uint32_t _skylineNodeIndex, uint16_t _width, uint16_t _height); +/// Merges all skyline nodes that are at the same level. +void merge(); - struct Node +struct Node +{ + Node(int16_t _x, int16_t _y, int16_t _width) : m_x(_x), m_y(_y), m_width(_width) { - Node(int16_t _x, int16_t _y, int16_t _width):m_x(_x), m_y(_y), m_width(_width) {} - - /// The starting x-coordinate (leftmost). - int16_t m_x; - /// The y-coordinate of the skyline level line. - int16_t m_y; - /// The line _width. The ending coordinate (inclusive) will be x+width-1. - int32_t m_width; //32bit to avoid padding - }; + } - /// width (in pixels) of the underlying texture - uint32_t m_width; - /// height (in pixels) of the underlying texture - uint32_t m_height; - /// Surface used in squared pixel - uint32_t m_usedSpace; - /// node of the skyline algorithm - std::vector m_skyline; + /// The starting x-coordinate (leftmost). + int16_t m_x; + /// The y-coordinate of the skyline level line. + int16_t m_y; + /// The line _width. The ending coordinate (inclusive) will be x+width-1. + int32_t m_width; //32bit to avoid padding }; -RectanglePacker::RectanglePacker(): m_width(0), m_height(0), m_usedSpace(0) -{ +/// width (in pixels) of the underlying texture +uint32_t m_width; +/// height (in pixels) of the underlying texture +uint32_t m_height; +/// Surface used in squared pixel +uint32_t m_usedSpace; +/// node of the skyline algorithm +std::vector m_skyline; +}; + +RectanglePacker::RectanglePacker() : m_width(0), m_height(0), m_usedSpace(0) +{ } -RectanglePacker::RectanglePacker(uint32_t _width, uint32_t _height):m_width(_width), m_height(_height), m_usedSpace(0) -{ - // We want a one pixel border around the whole atlas to avoid any artefact when - // sampling texture - m_skyline.push_back(Node(1,1, _width-2)); +RectanglePacker::RectanglePacker(uint32_t _width, uint32_t _height) : m_width(_width), m_height(_height), m_usedSpace(0) +{ + // We want a one pixel border around the whole atlas to avoid any artefact when + // sampling texture + m_skyline.push_back(Node(1, 1, _width - 2) ); } void RectanglePacker::init(uint32_t _width, uint32_t _height) @@ -78,32 +85,33 @@ void RectanglePacker::init(uint32_t _width, uint32_t _height) m_skyline.clear(); // We want a one pixel border around the whole atlas to avoid any artifact when - // sampling texture - m_skyline.push_back(Node(1,1, _width-2)); + // sampling texture + m_skyline.push_back(Node(1, 1, _width - 2) ); } bool RectanglePacker::addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX, uint16_t& _outY) { int y, best_height, best_index; - int32_t best_width; - Node* node; - Node* prev; - _outX = 0; + int32_t best_width; + Node* node; + Node* prev; + _outX = 0; _outY = 0; - + uint32_t ii; - best_height = INT_MAX; - best_index = -1; - best_width = INT_MAX; - for( ii = 0; ii < m_skyline.size(); ++ii ) + best_height = INT_MAX; + best_index = -1; + best_width = INT_MAX; + for (ii = 0; ii < m_skyline.size(); ++ii) { - y = fit( ii, _width, _height ); - if( y >= 0 ) + y = fit(ii, _width, _height); + if (y >= 0) { - node = &m_skyline[ii]; - if( ( (y + _height) < best_height ) || - ( ((y + _height) == best_height) && (node->m_width < best_width)) ) + node = &m_skyline[ii]; + if ( ( (y + _height) < best_height) + || ( ( (y + _height) == best_height) + && (node->m_width < best_width) ) ) { best_height = y + _height; best_index = ii; @@ -111,116 +119,124 @@ bool RectanglePacker::addRectangle(uint16_t _width, uint16_t _height, uint16_t& _outX = node->m_x; _outY = y; } - } - } + } + } - if( best_index == -1 ) - { + if (best_index == -1) + { return false; - } - - Node newNode(_outX, _outY + _height, _width); - m_skyline.insert(m_skyline.begin() + best_index, newNode); + } - for(ii = best_index+1; ii < m_skyline.size(); ++ii) - { - node = &m_skyline[ii]; - prev = &m_skyline[ii-1]; - if (node->m_x < (prev->m_x + prev->m_width) ) - { - int shrink = prev->m_x + prev->m_width - node->m_x; - node->m_x += shrink; - node->m_width -= shrink; - if (node->m_width <= 0) - { - m_skyline.erase(m_skyline.begin() + ii); - --ii; - } - else - { - break; - } - } - else - { - break; - } - } + Node newNode(_outX, _outY + _height, _width); + m_skyline.insert(m_skyline.begin() + best_index, newNode); - merge(); - m_usedSpace += _width * _height; - return true; + for (ii = best_index + 1; ii < m_skyline.size(); ++ii) + { + node = &m_skyline[ii]; + prev = &m_skyline[ii - 1]; + if (node->m_x < (prev->m_x + prev->m_width) ) + { + int shrink = prev->m_x + prev->m_width - node->m_x; + node->m_x += shrink; + node->m_width -= shrink; + if (node->m_width <= 0) + { + m_skyline.erase(m_skyline.begin() + ii); + --ii; + } + else + { + break; + } + } + else + { + break; + } + } + + merge(); + m_usedSpace += _width * _height; + return true; } - + float RectanglePacker::getUsageRatio() -{ - uint32_t total = m_width*m_height; - if(total > 0) +{ + uint32_t total = m_width * m_height; + if (total > 0) + { return (float) m_usedSpace / (float) total; + } else + { return 0.0f; + } } void RectanglePacker::clear() { m_skyline.clear(); - m_usedSpace = 0; - - // We want a one pixel border around the whole atlas to avoid any artefact when - // sampling texture - m_skyline.push_back(Node(1,1, m_width-2)); + m_usedSpace = 0; + + // We want a one pixel border around the whole atlas to avoid any artefact when + // sampling texture + m_skyline.push_back(Node(1, 1, m_width - 2) ); } int32_t RectanglePacker::fit(uint32_t _skylineNodeIndex, uint16_t _width, uint16_t _height) { int32_t width = _width; - int32_t height = _height; - - const Node& baseNode = m_skyline[_skylineNodeIndex]; - - int32_t x = baseNode.m_x, y; + int32_t height = _height; + + const Node& baseNode = m_skyline[_skylineNodeIndex]; + + int32_t x = baseNode.m_x, y; int32_t _width_left = width; int32_t i = _skylineNodeIndex; - if ( (x + width) > (int32_t)(m_width-1) ) - { - return -1; - } - y = baseNode.m_y; - while( _width_left > 0 ) + if ( (x + width) > (int32_t)(m_width - 1) ) { - const Node& node = m_skyline[i]; - if( node.m_y > y ) - { - y = node.m_y; - } - if( (y + height) > (int32_t)(m_height-1) ) - { + return -1; + } + + y = baseNode.m_y; + while (_width_left > 0) + { + const Node& node = m_skyline[i]; + if (node.m_y > y) + { + y = node.m_y; + } + + if ( (y + height) > (int32_t)(m_height - 1) ) + { return -1; - } - _width_left -= node.m_width; + } + + _width_left -= node.m_width; ++i; } + return y; } - + void RectanglePacker::merge() { Node* node; - Node* next; - uint32_t ii; + Node* next; + uint32_t ii; - for( ii=0; ii < m_skyline.size()-1; ++ii ) - { - node = (Node *) &m_skyline[ii]; - next = (Node *) &m_skyline[ii+1]; - if( node->m_y == next->m_y ) + for (ii = 0; ii < m_skyline.size() - 1; ++ii) + { + node = (Node*) &m_skyline[ii]; + next = (Node*) &m_skyline[ii + 1]; + if (node->m_y == next->m_y) { node->m_width += next->m_width; - m_skyline.erase(m_skyline.begin() + ii + 1); + m_skyline.erase(m_skyline.begin() + ii + 1); --ii; } - } + } } //********** Cube Atlas implementation ************ @@ -231,15 +247,18 @@ struct Atlas::PackedLayer AtlasRegion faceRegion; }; -Atlas::Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount ) +Atlas::Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount) { - BX_CHECK(_textureSize >= 64 && _textureSize <= 4096, "suspicious texture size" ); - BX_CHECK(_maxRegionsCount >= 64 && _maxRegionsCount <= 32000, "suspicious _regions count" ); + BX_CHECK(_textureSize >= 64 + && _textureSize <= 4096, "suspicious texture size"); + BX_CHECK(_maxRegionsCount >= 64 + && _maxRegionsCount <= 32000, "suspicious _regions count"); m_layers = new PackedLayer[24]; - for(int ii=0; ii<24;++ii) + for (int ii = 0; ii < 24; ++ii) { - m_layers[ii].packer.init(_textureSize, _textureSize); + m_layers[ii].packer.init(_textureSize, _textureSize); } + m_usedLayers = 0; m_usedFaces = 0; @@ -248,28 +267,29 @@ Atlas::Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount ) m_maxRegionCount = _maxRegionsCount; m_regions = new AtlasRegion[_maxRegionsCount]; m_textureBuffer = new uint8_t[ _textureSize * _textureSize * 6 * 4 ]; - memset(m_textureBuffer, 0, _textureSize * _textureSize * 6 * 4); + memset(m_textureBuffer, 0, _textureSize * _textureSize * 6 * 4); //BGFX_TEXTURE_MIN_POINT|BGFX_TEXTURE_MAG_POINT|BGFX_TEXTURE_MIP_POINT; //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT //BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP - uint32_t flags = 0;// BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT; + uint32_t flags = 0; // BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT; //Uncomment this to debug atlas //const bgfx::Memory* mem = bgfx::alloc(textureSize*textureSize * 6 * 4); - //memset(mem->data, 255, mem->size); - const bgfx::Memory* mem = NULL; + //memset(mem->data, 255, mem->size); + const bgfx::Memory* mem = NULL; m_textureHandle = bgfx::createTextureCube(6 - , _textureSize - , 1 - , bgfx::TextureFormat::BGRA8 - , flags - ,mem - ); + , _textureSize + , 1 + , bgfx::TextureFormat::BGRA8 + , flags + , mem + ); } -Atlas::Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer , uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount) +Atlas::Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer, uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount) { - BX_CHECK(_regionCount <= 64 && _maxRegionsCount <= 4096, "suspicious initialization"); + BX_CHECK(_regionCount <= 64 + && _maxRegionsCount <= 4096, "suspicious initialization"); //layers are frozen m_usedLayers = 24; m_usedFaces = 6; @@ -277,27 +297,32 @@ Atlas::Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer , uint16_t _re m_textureSize = _textureSize; m_regionCount = _regionCount; //regions are frozen - if(_regionCount < _maxRegionsCount) + if (_regionCount < _maxRegionsCount) + { m_maxRegionCount = _regionCount; + } else + { m_maxRegionCount = _maxRegionsCount; + } + m_regions = new AtlasRegion[_regionCount]; m_textureBuffer = new uint8_t[getTextureBufferSize()]; - + //BGFX_TEXTURE_MIN_POINT|BGFX_TEXTURE_MAG_POINT|BGFX_TEXTURE_MIP_POINT; //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT //BGFX_TEXTURE_U_CLAMP|BGFX_TEXTURE_V_CLAMP - uint32_t flags = 0;//BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT; - memcpy(m_regions, _regionBuffer, _regionCount * sizeof(AtlasRegion)); - memcpy(m_textureBuffer, _textureBuffer, getTextureBufferSize()); + uint32_t flags = 0; //BGFX_TEXTURE_MIN_ANISOTROPIC|BGFX_TEXTURE_MAG_ANISOTROPIC|BGFX_TEXTURE_MIP_POINT; + memcpy(m_regions, _regionBuffer, _regionCount * sizeof(AtlasRegion) ); + memcpy(m_textureBuffer, _textureBuffer, getTextureBufferSize() ); m_textureHandle = bgfx::createTextureCube(6 - , _textureSize - , 1 - , bgfx::TextureFormat::BGRA8 - , flags - , bgfx::makeRef(m_textureBuffer, getTextureBufferSize()) - ); + , _textureSize + , 1 + , bgfx::TextureFormat::BGRA8 + , flags + , bgfx::makeRef(m_textureBuffer, getTextureBufferSize() ) + ); } Atlas::~Atlas() @@ -307,183 +332,198 @@ Atlas::~Atlas() delete[] m_textureBuffer; } -uint16_t Atlas::addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type, uint16_t outline) +uint16_t Atlas::addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type, uint16_t outline) { if (m_regionCount >= m_maxRegionCount) { return UINT16_MAX; } - - uint16_t x=0,y=0; + + uint16_t x = 0, y = 0; // We want each bitmap to be separated by at least one black pixel // TODO manage mipmaps uint32_t idx = 0; - while(idx= m_usedLayers) + if (idx >= m_usedLayers) { //do we have still room to add layers ? - if( (idx + _type) > 24 || m_usedFaces>=6) + if ( (idx + _type) > 24 + || m_usedFaces >= 6) { - return UINT16_MAX; - } - //create new layers - for(int ii=0; ii < _type; ++ii) - { - m_layers[idx+ii].faceRegion.setMask(_type, m_usedFaces, ii); + return UINT16_MAX; } + + //create new layers + for (int ii = 0; ii < _type; ++ii) + { + m_layers[idx + ii].faceRegion.setMask(_type, m_usedFaces, ii); + } + m_usedLayers += _type; m_usedFaces++; - //add it to the created layer - if(!m_layers[idx].packer.addRectangle(_width+1, _height+1, x, y)) + if (!m_layers[idx].packer.addRectangle(_width + 1, _height + 1, x, y) ) { return UINT16_MAX; } } - + AtlasRegion& region = m_regions[m_regionCount]; - region.m_x = x ; - region.m_y = y ; + region.m_x = x; + region.m_y = y; region.m_width = _width; region.m_height = _height; region.m_mask = m_layers[idx].faceRegion.m_mask; updateRegion(region, _bitmapBuffer); - + region.m_x += outline; region.m_y += outline; - region.m_width -= (outline*2); - region.m_height -= (outline*2); + region.m_width -= (outline * 2); + region.m_height -= (outline * 2); return m_regionCount++; } void Atlas::updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffer) -{ +{ const bgfx::Memory* mem = bgfx::alloc(_region.m_width * _region.m_height * 4); //BAD! - memset(mem->data,0, mem->size); - if(_region.getType() == AtlasRegion::TYPE_BGRA8) - { + memset(mem->data, 0, mem->size); + if (_region.getType() == AtlasRegion::TYPE_BGRA8) + { const uint8_t* inLineBuffer = _bitmapBuffer; - uint8_t* outLineBuffer = m_textureBuffer + _region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((_region.m_y *m_textureSize)+_region.m_x)*4); + uint8_t* outLineBuffer = m_textureBuffer + _region.getFaceIndex() * (m_textureSize * m_textureSize * 4) + ( ( (_region.m_y * m_textureSize) + _region.m_x) * 4); //update the cpu buffer - for(int yy = 0; yy < _region.m_height; ++yy) + for (int yy = 0; yy < _region.m_height; ++yy) { memcpy(outLineBuffer, inLineBuffer, _region.m_width * 4); - inLineBuffer += _region.m_width*4; - outLineBuffer += m_textureSize*4; + inLineBuffer += _region.m_width * 4; + outLineBuffer += m_textureSize * 4; } + //update the GPU buffer memcpy(mem->data, _bitmapBuffer, mem->size); - }else + } + else { uint32_t layer = _region.getComponentIndex(); //uint32_t face = _region.getFaceIndex(); const uint8_t* inLineBuffer = _bitmapBuffer; - uint8_t* outLineBuffer = (m_textureBuffer + _region.getFaceIndex() * (m_textureSize*m_textureSize*4) + (((_region.m_y *m_textureSize)+_region.m_x)*4)); - + uint8_t* outLineBuffer = (m_textureBuffer + _region.getFaceIndex() * (m_textureSize * m_textureSize * 4) + ( ( (_region.m_y * m_textureSize) + _region.m_x) * 4) ); + //update the cpu buffer - for(int yy = 0; yy<_region.m_height; ++yy) + for (int yy = 0; yy < _region.m_height; ++yy) { - for(int xx = 0; xx<_region.m_width; ++xx) + for (int xx = 0; xx < _region.m_width; ++xx) { - outLineBuffer[(xx*4) + layer] = inLineBuffer[xx]; + outLineBuffer[(xx * 4) + layer] = inLineBuffer[xx]; } + //update the GPU buffer - memcpy(mem->data + yy*_region.m_width*4, outLineBuffer, _region.m_width*4); + memcpy(mem->data + yy * _region.m_width * 4, outLineBuffer, _region.m_width * 4); inLineBuffer += _region.m_width; - outLineBuffer += m_textureSize*4; + outLineBuffer += m_textureSize * 4; } } - bgfx::updateTextureCube(m_textureHandle, (uint8_t)_region.getFaceIndex(), 0, _region.m_x, _region.m_y, _region.m_width, _region.m_height, mem); + + bgfx::updateTextureCube(m_textureHandle, (uint8_t)_region.getFaceIndex(), 0, _region.m_x, _region.m_y, _region.m_width, _region.m_height, mem); } -void Atlas::packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ) +void Atlas::packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride) { packUV(m_layers[_idx].faceRegion, _vertexBuffer, _offset, _stride); } -void Atlas::packUV( uint16_t handle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ) +void Atlas::packUV(uint16_t handle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride) { const AtlasRegion& region = m_regions[handle]; packUV(region, _vertexBuffer, _offset, _stride); } -void Atlas::packUV( const AtlasRegion& _region, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ) +void Atlas::packUV(const AtlasRegion& _region, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride) { - float texMult = 65535.0f / ((float)(m_textureSize)); + float texMult = 65535.0f / ( (float)(m_textureSize) ); static const int16_t minVal = -32768; static const int16_t maxVal = 32767; - - int16_t x0 = (int16_t)(_region.m_x * texMult)-32768; - int16_t y0 = (int16_t)(_region.m_y * texMult)-32768; - int16_t x1 = (int16_t)((_region.m_x + _region.m_width)* texMult)-32768; - int16_t y1 = (int16_t)((_region.m_y + _region.m_height)* texMult)-32768; - int16_t w = (int16_t) ((32767.0f/4.0f) * _region.getComponentIndex()); - _vertexBuffer+=_offset; - switch(_region.getFaceIndex()) + int16_t x0 = (int16_t)(_region.m_x * texMult) - 32768; + int16_t y0 = (int16_t)(_region.m_y * texMult) - 32768; + int16_t x1 = (int16_t)( (_region.m_x + _region.m_width) * texMult) - 32768; + int16_t y1 = (int16_t)( (_region.m_y + _region.m_height) * texMult) - 32768; + int16_t w = (int16_t) ( (32767.0f / 4.0f) * _region.getComponentIndex() ); + + _vertexBuffer += _offset; + switch (_region.getFaceIndex() ) { case 0: // +X - x0= -x0; - x1= -x1; - y0= -y0; - y1= -y1; - writeUV(_vertexBuffer, maxVal, y0, x0, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, maxVal, y1, x0, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, maxVal, y1, x1, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, maxVal, y0, x1, w); _vertexBuffer+=_stride; + x0 = -x0; + x1 = -x1; + y0 = -y0; + y1 = -y1; + writeUV(_vertexBuffer, maxVal, y0, x0, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, maxVal, y1, x0, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, maxVal, y1, x1, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, maxVal, y0, x1, w); _vertexBuffer += _stride; break; - case 1: // -X - y0= -y0; - y1= -y1; - writeUV(_vertexBuffer, minVal, y0, x0, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, minVal, y1, x0, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, minVal, y1, x1, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, minVal, y0, x1, w); _vertexBuffer+=_stride; + + case 1: // -X + y0 = -y0; + y1 = -y1; + writeUV(_vertexBuffer, minVal, y0, x0, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, minVal, y1, x0, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, minVal, y1, x1, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, minVal, y0, x1, w); _vertexBuffer += _stride; break; - case 2: // +Y - writeUV(_vertexBuffer, x0, maxVal, y0, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x0, maxVal, y1, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, maxVal, y1, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, maxVal, y0, w); _vertexBuffer+=_stride; + + case 2: // +Y + writeUV(_vertexBuffer, x0, maxVal, y0, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x0, maxVal, y1, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, maxVal, y1, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, maxVal, y0, w); _vertexBuffer += _stride; break; + case 3: // -Y - y0= -y0; - y1= -y1; - writeUV(_vertexBuffer, x0, minVal, y0, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x0, minVal, y1, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, minVal, y1, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, minVal, y0, w); _vertexBuffer+=_stride; + y0 = -y0; + y1 = -y1; + writeUV(_vertexBuffer, x0, minVal, y0, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x0, minVal, y1, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, minVal, y1, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, minVal, y0, w); _vertexBuffer += _stride; break; + case 4: // +Z - y0= -y0; - y1= -y1; - writeUV(_vertexBuffer, x0, y0, maxVal, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x0, y1, maxVal, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, y1, maxVal, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, y0, maxVal, w); _vertexBuffer+=_stride; + y0 = -y0; + y1 = -y1; + writeUV(_vertexBuffer, x0, y0, maxVal, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x0, y1, maxVal, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, y1, maxVal, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, y0, maxVal, w); _vertexBuffer += _stride; break; + case 5: // -Z - x0= -x0; - x1= -x1; - y0= -y0; - y1= -y1; - writeUV(_vertexBuffer, x0, y0, minVal, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x0, y1, minVal, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, y1, minVal, w); _vertexBuffer+=_stride; - writeUV(_vertexBuffer, x1, y0, minVal, w); _vertexBuffer+=_stride; + x0 = -x0; + x1 = -x1; + y0 = -y0; + y1 = -y1; + writeUV(_vertexBuffer, x0, y0, minVal, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x0, y1, minVal, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, y1, minVal, w); _vertexBuffer += _stride; + writeUV(_vertexBuffer, x1, y0, minVal, w); _vertexBuffer += _stride; break; } } diff --git a/examples/common/cube_atlas.h b/examples/common/cube_atlas.h index 9ac55826..e44d022c 100644 --- a/examples/common/cube_atlas.h +++ b/examples/common/cube_atlas.h @@ -15,7 +15,7 @@ /// algorithm based on C++ sources provided by Jukka Jylänki at: /// http://clb.demon.fi/files/RectangleBinPack/ -#include +#include struct AtlasRegion { @@ -23,115 +23,147 @@ struct AtlasRegion { TYPE_GRAY = 1, // 1 component TYPE_BGRA8 = 4 // 4 components - }; + }; uint16_t m_x, m_y; uint16_t m_width, m_height; uint32_t m_mask; //encode the region type, the face index and the component index in case of a gray region - Type getType()const { return (Type) ((m_mask >> 0) & 0x0000000F); } - uint32_t getFaceIndex()const { return (m_mask >> 4) & 0x0000000F; } - uint32_t getComponentIndex()const { return (m_mask >> 8) & 0x0000000F; } - void setMask(Type _type, uint32_t _faceIndex, uint32_t _componentIndex) { m_mask = (_componentIndex << 8) + (_faceIndex << 4) + (uint32_t)_type; } + Type getType() const + { + return (Type) ( (m_mask >> 0) & 0x0000000F); + } + uint32_t getFaceIndex() const + { + return (m_mask >> 4) & 0x0000000F; + } + uint32_t getComponentIndex() const + { + return (m_mask >> 8) & 0x0000000F; + } + void setMask(Type _type, uint32_t _faceIndex, uint32_t _componentIndex) + { + m_mask = (_componentIndex << 8) + (_faceIndex << 4) + (uint32_t)_type; + } }; class Atlas { public: - /// create an empty dynamic atlas (region can be updated and added) - /// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA)) - /// @param maxRegionCount maximum number of region allowed in the atlas - Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount = 4096); - - /// initialize a static atlas with serialized data (region can be updated but not added) - /// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA)) - /// @param textureBuffer buffer of size 6*textureSize*textureSize*sizeof(uint32_t) (will be copied) - /// @param regionCount number of region in the Atlas - /// @param regionBuffer buffer containing the region (will be copied) - /// @param maxRegionCount maximum number of region allowed in the atlas - Atlas(uint16_t _textureSize, const uint8_t * _textureBuffer, uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount = 4096); - ~Atlas(); - - /// add a region to the atlas, and copy the content of mem to the underlying texture - uint16_t addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type = AtlasRegion::TYPE_BGRA8, uint16_t outline = 0); +/// create an empty dynamic atlas (region can be updated and added) +/// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA)) +/// @param maxRegionCount maximum number of region allowed in the atlas +Atlas(uint16_t _textureSize, uint16_t _maxRegionsCount = 4096); - /// update a preallocated region - void updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffer); +/// initialize a static atlas with serialized data (region can be updated but not added) +/// @param textureSize an atlas creates a texture cube of 6 faces with size equal to (textureSize*textureSize * sizeof(RGBA)) +/// @param textureBuffer buffer of size 6*textureSize*textureSize*sizeof(uint32_t) (will be copied) +/// @param regionCount number of region in the Atlas +/// @param regionBuffer buffer containing the region (will be copied) +/// @param maxRegionCount maximum number of region allowed in the atlas +Atlas(uint16_t _textureSize, const uint8_t* _textureBuffer, uint16_t _regionCount, const uint8_t* _regionBuffer, uint16_t _maxRegionsCount = 4096); +~Atlas(); - /// Pack the UV coordinates of the four corners of a region to a vertex buffer using the supplied vertex format. - /// v0 -- v3 - /// | | encoded in that order: v0,v1,v2,v3 - /// v1 -- v2 - /// @remark the UV are four signed short normalized components. - /// @remark the x,y,z components encode cube uv coordinates. The w component encode the color channel if any. - /// @param handle handle to the region we are interested in - /// @param vertexBuffer address of the first vertex we want to update. Must be valid up to vertexBuffer + offset + 3*stride + 4*sizeof(int16_t), which means the buffer must contains at least 4 vertex includind the first. - /// @param offset byte offset to the first uv coordinate of the vertex in the buffer - /// @param stride stride between tho UV coordinates, usually size of a Vertex. - void packUV( uint16_t _regionHandle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ); - void packUV( const AtlasRegion& _region, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ); - - /// Same as packUV but pack a whole face of the atlas cube, mostly used for debugging and visualizing atlas - void packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride ); +/// add a region to the atlas, and copy the content of mem to the underlying texture +uint16_t addRegion(uint16_t _width, uint16_t _height, const uint8_t* _bitmapBuffer, AtlasRegion::Type _type = AtlasRegion::TYPE_BGRA8, uint16_t outline = 0); - /// Pack the vertex index of the region as 2 quad into an index buffer - void packIndex(uint16_t* _indexBuffer, uint32_t _startIndex, uint32_t _startVertex ) - { - _indexBuffer[_startIndex+0] = _startVertex+0; - _indexBuffer[_startIndex+1] = _startVertex+1; - _indexBuffer[_startIndex+2] = _startVertex+2; - _indexBuffer[_startIndex+3] = _startVertex+0; - _indexBuffer[_startIndex+4] = _startVertex+2; - _indexBuffer[_startIndex+5] = _startVertex+3; - } +/// update a preallocated region +void updateRegion(const AtlasRegion& _region, const uint8_t* _bitmapBuffer); - /// return the TextureHandle (cube) of the atlas - bgfx::TextureHandle getTextureHandle() const { return m_textureHandle; } +/// Pack the UV coordinates of the four corners of a region to a vertex buffer using the supplied vertex format. +/// v0 -- v3 +/// | | encoded in that order: v0,v1,v2,v3 +/// v1 -- v2 +/// @remark the UV are four signed short normalized components. +/// @remark the x,y,z components encode cube uv coordinates. The w component encode the color channel if any. +/// @param handle handle to the region we are interested in +/// @param vertexBuffer address of the first vertex we want to update. Must be valid up to vertexBuffer + offset + 3*stride + 4*sizeof(int16_t), which means the buffer must contains at least 4 vertex includind the first. +/// @param offset byte offset to the first uv coordinate of the vertex in the buffer +/// @param stride stride between tho UV coordinates, usually size of a Vertex. +void packUV(uint16_t _regionHandle, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride); +void packUV(const AtlasRegion& _region, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride); - //retrieve a region info - const AtlasRegion& getRegion(uint16_t _handle) const { return m_regions[_handle]; } - - /// retrieve the size of side of a texture in pixels - uint16_t getTextureSize(){ return m_textureSize; } +/// Same as packUV but pack a whole face of the atlas cube, mostly used for debugging and visualizing atlas +void packFaceLayerUV(uint32_t _idx, uint8_t* _vertexBuffer, uint32_t _offset, uint32_t _stride); - /// retrieve the usage ratio of the atlas - //float getUsageRatio() const { return 0.0f; } +/// Pack the vertex index of the region as 2 quad into an index buffer +void packIndex(uint16_t* _indexBuffer, uint32_t _startIndex, uint32_t _startVertex) +{ + _indexBuffer[_startIndex + 0] = _startVertex + 0; + _indexBuffer[_startIndex + 1] = _startVertex + 1; + _indexBuffer[_startIndex + 2] = _startVertex + 2; + _indexBuffer[_startIndex + 3] = _startVertex + 0; + _indexBuffer[_startIndex + 4] = _startVertex + 2; + _indexBuffer[_startIndex + 5] = _startVertex + 3; +} - /// retrieve the numbers of region in the atlas - uint16_t getRegionCount() const { return m_regionCount; } +/// return the TextureHandle (cube) of the atlas +bgfx::TextureHandle getTextureHandle() const +{ + return m_textureHandle; +} - /// retrieve a pointer to the region buffer (in order to serialize it) - const AtlasRegion* getRegionBuffer() const { return m_regions; } - - /// retrieve the byte size of the texture - uint32_t getTextureBufferSize() const { return 6*m_textureSize*m_textureSize*4; } +//retrieve a region info +const AtlasRegion& getRegion(uint16_t _handle) const +{ + return m_regions[_handle]; +} - /// retrieve the mirrored texture buffer (to serialize it) - const uint8_t* getTextureBuffer() const { return m_textureBuffer; } +/// retrieve the size of side of a texture in pixels +uint16_t getTextureSize() +{ + return m_textureSize; +} + +/// retrieve the usage ratio of the atlas +//float getUsageRatio() const { return 0.0f; } + +/// retrieve the numbers of region in the atlas +uint16_t getRegionCount() const +{ + return m_regionCount; +} + +/// retrieve a pointer to the region buffer (in order to serialize it) +const AtlasRegion* getRegionBuffer() const +{ + return m_regions; +} + +/// retrieve the byte size of the texture +uint32_t getTextureBufferSize() const +{ + return 6 * m_textureSize * m_textureSize * 4; +} + +/// retrieve the mirrored texture buffer (to serialize it) +const uint8_t* getTextureBuffer() const +{ + return m_textureBuffer; +} private: - void writeUV( uint8_t* _vertexBuffer, int16_t _x, int16_t _y, int16_t _z, int16_t _w) - { - ((uint16_t*) _vertexBuffer)[0] = _x; - ((uint16_t*) _vertexBuffer)[1] = _y; - ((uint16_t*) _vertexBuffer)[2] = _z; - ((uint16_t*) _vertexBuffer)[3] = _w; - } - struct PackedLayer; - PackedLayer* m_layers; +void writeUV(uint8_t* _vertexBuffer, int16_t _x, int16_t _y, int16_t _z, int16_t _w) +{ + ( (uint16_t*) _vertexBuffer)[0] = _x; + ( (uint16_t*) _vertexBuffer)[1] = _y; + ( (uint16_t*) _vertexBuffer)[2] = _z; + ( (uint16_t*) _vertexBuffer)[3] = _w; +} +struct PackedLayer; +PackedLayer* m_layers; - uint32_t m_usedLayers; - uint32_t m_usedFaces; +uint32_t m_usedLayers; +uint32_t m_usedFaces; - bgfx::TextureHandle m_textureHandle; - uint16_t m_textureSize; +bgfx::TextureHandle m_textureHandle; +uint16_t m_textureSize; - uint16_t m_regionCount; - uint16_t m_maxRegionCount; - - AtlasRegion* m_regions; - uint8_t* m_textureBuffer; +uint16_t m_regionCount; +uint16_t m_maxRegionCount; +AtlasRegion* m_regions; +uint8_t* m_textureBuffer; }; #endif // __CUBE_ATLAS_H__ diff --git a/examples/common/font/font_manager.cpp b/examples/common/font/font_manager.cpp index 782bd89c..582356d1 100644 --- a/examples/common/font/font_manager.cpp +++ b/examples/common/font/font_manager.cpp @@ -7,40 +7,42 @@ #include "../cube_atlas.h" #if BX_COMPILER_MSVC -# pragma warning(push) -# pragma warning(disable: 4100) // DISABLE warning C4100: '' : unreferenced formal parameter -# pragma warning(disable: 4146) // DISABLE warning C4146: unary minus operator applied to unsigned type, result still unsigned -# pragma warning(disable: 4700) // DISABLE warning C4700: uninitialized local variable 'temp' used -# pragma warning(disable: 4701) // DISABLE warning C4701: potentially uninitialized local variable '' used -# include -# pragma warning(pop) +# pragma warning(push) +# pragma warning(disable: 4100) // DISABLE warning C4100: '' : unreferenced formal parameter +# pragma warning(disable: 4146) // DISABLE warning C4146: unary minus operator applied to unsigned type, result still unsigned +# pragma warning(disable: 4700) // DISABLE warning C4700: uninitialized local variable 'temp' used +# pragma warning(disable: 4701) // DISABLE warning C4701: potentially uninitialized local variable '' used +# include +# pragma warning(pop) #else -# include +# include #endif // BX_COMPILER_MSVC - #include #include #include - #if BGFX_CONFIG_USE_TINYSTL namespace tinystl { //struct bgfx_allocator //{ - //static void* static_allocate(size_t _bytes); - //static void static_deallocate(void* _ptr, size_t /*_bytes*/); + //static void* static_allocate(size_t _bytes); + //static void static_deallocate(void* _ptr, size_t /*_bytes*/); //}; } // namespace tinystl //# define TINYSTL_ALLOCATOR tinystl::bgfx_allocator -# include +# include //# include namespace stl = tinystl; #else -# include -namespace std { namespace tr1 {} } -namespace stl { +# include +namespace std +{ namespace tr1 + {} +} +namespace stl +{ using namespace std; using namespace std::tr1; } @@ -48,53 +50,52 @@ namespace stl { class FontManager::TrueTypeFont { -public: - TrueTypeFont(); - ~TrueTypeFont(); +public: +TrueTypeFont(); +~TrueTypeFont(); - /// Initialize from an external buffer - /// @remark The ownership of the buffer is external, and you must ensure it stays valid up to this object lifetime - /// @return true if the initialization succeed - bool init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight ); - - /// return the font descriptor of the current font - FontInfo getFontInfo(); - - /// raster a glyph as 8bit alpha to a memory buffer - /// update the GlyphInfo according to the raster strategy - /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char) - bool bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); +/// Initialize from an external buffer +/// @remark The ownership of the buffer is external, and you must ensure it stays valid up to this object lifetime +/// @return true if the initialization succeed +bool init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight); - /// raster a glyph as 32bit subpixel rgba to a memory buffer - /// update the GlyphInfo according to the raster strategy - /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(uint32_t) - bool bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); +/// return the font descriptor of the current font +FontInfo getFontInfo(); - /// raster a glyph as 8bit signed distance to a memory buffer - /// update the GlyphInfo according to the raster strategy - /// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char) - bool bakeGlyphDistance(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); +/// raster a glyph as 8bit alpha to a memory buffer +/// update the GlyphInfo according to the raster strategy +/// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char) +bool bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); + +/// raster a glyph as 32bit subpixel rgba to a memory buffer +/// update the GlyphInfo according to the raster strategy +/// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(uint32_t) +bool bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); + +/// raster a glyph as 8bit signed distance to a memory buffer +/// update the GlyphInfo according to the raster strategy +/// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char) +bool bakeGlyphDistance(CodePoint_t _codePoint, GlyphInfo& _outGlyphInfo, uint8_t* _outBuffer); private: - void* m_font; +void* m_font; }; - struct FTHolder { FT_Library library; FT_Face face; }; -FontManager::TrueTypeFont::TrueTypeFont(): m_font(NULL) -{ +FontManager::TrueTypeFont::TrueTypeFont() : m_font(NULL) +{ } FontManager::TrueTypeFont::~TrueTypeFont() { - if(m_font!=NULL) + if (m_font != NULL) { FTHolder* holder = (FTHolder*) m_font; - FT_Done_Face( holder->face ); - FT_Done_FreeType( holder->library ); + FT_Done_Face(holder->face); + FT_Done_FreeType(holder->library); delete m_font; m_font = NULL; } @@ -102,55 +103,58 @@ FontManager::TrueTypeFont::~TrueTypeFont() bool FontManager::TrueTypeFont::init(const uint8_t* _buffer, uint32_t _bufferSize, int32_t _fontIndex, uint32_t _pixelHeight) { - BX_CHECK((_bufferSize > 256 && _bufferSize < 100000000), "TrueType buffer size is suspicious"); - BX_CHECK((_pixelHeight > 4 && _pixelHeight < 128), "TrueType buffer size is suspicious"); - - BX_CHECK(m_font == NULL, "TrueTypeFont already initialized" ); - - FTHolder* holder = new FTHolder(); + BX_CHECK( (_bufferSize > 256 + && _bufferSize < 100000000), "TrueType buffer size is suspicious"); + BX_CHECK( (_pixelHeight > 4 + && _pixelHeight < 128), "TrueType buffer size is suspicious"); + + BX_CHECK(m_font == NULL, "TrueTypeFont already initialized"); + + FTHolder* holder = new FTHolder(); // Initialize Freetype library - FT_Error error = FT_Init_FreeType( &holder->library ); - if( error) + FT_Error error = FT_Init_FreeType(&holder->library); + if (error) { delete holder; return false; } - error = FT_New_Memory_Face( holder->library, _buffer, _bufferSize, _fontIndex, &holder->face ); - if ( error == FT_Err_Unknown_File_Format ) - { + error = FT_New_Memory_Face(holder->library, _buffer, _bufferSize, _fontIndex, &holder->face); + if (error == FT_Err_Unknown_File_Format) + { // the font file could be opened and read, but it appears //that its font format is unsupported - FT_Done_FreeType( holder->library ); + FT_Done_FreeType(holder->library); delete holder; return false; } - else if ( error ) + else if (error) { // another error code means that the font file could not // be opened or read, or simply that it is broken... - FT_Done_FreeType( holder->library ); + FT_Done_FreeType(holder->library); delete holder; return false; } - // Select unicode charmap - error = FT_Select_Charmap( holder->face, FT_ENCODING_UNICODE ); - if( error ) - { - FT_Done_Face( holder->face ); - FT_Done_FreeType( holder->library ); - return false; - } + // Select unicode charmap + error = FT_Select_Charmap(holder->face, FT_ENCODING_UNICODE); + if (error) + { + FT_Done_Face(holder->face); + FT_Done_FreeType(holder->library); + return false; + } + //set size in pixels - error = FT_Set_Pixel_Sizes( holder->face, 0, _pixelHeight ); - if( error ) - { - FT_Done_Face( holder->face ); - FT_Done_FreeType( holder->library ); - return false; - } + error = FT_Set_Pixel_Sizes(holder->face, 0, _pixelHeight); + if (error) + { + FT_Done_Face(holder->face); + FT_Done_FreeType(holder->library); + return false; + } m_font = holder; return true; @@ -158,88 +162,106 @@ bool FontManager::TrueTypeFont::init(const uint8_t* _buffer, uint32_t _bufferSiz FontInfo FontManager::TrueTypeFont::getFontInfo() { - BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); + BX_CHECK(m_font != NULL, "TrueTypeFont not initialized"); FTHolder* holder = (FTHolder*) m_font; - + //todo manage unscalable font - BX_CHECK(FT_IS_SCALABLE (holder->face), "Font is unscalable"); + BX_CHECK(FT_IS_SCALABLE(holder->face), "Font is unscalable"); FT_Size_Metrics metrics = holder->face->size->metrics; - FontInfo outFontInfo; outFontInfo.scale = 1.0f; - outFontInfo.ascender = metrics.ascender /64.0f; - outFontInfo.descender = metrics.descender /64.0f; - outFontInfo.lineGap = (metrics.height - metrics.ascender + metrics.descender) /64.0f; - - outFontInfo.underline_position = FT_MulFix(holder->face->underline_position, metrics.y_scale) /64.0f; - outFontInfo.underline_thickness= FT_MulFix(holder->face->underline_thickness,metrics.y_scale) /64.0f; + outFontInfo.ascender = metrics.ascender / 64.0f; + outFontInfo.descender = metrics.descender / 64.0f; + outFontInfo.lineGap = (metrics.height - metrics.ascender + metrics.descender) / 64.0f; + + outFontInfo.underline_position = FT_MulFix(holder->face->underline_position, metrics.y_scale) / 64.0f; + outFontInfo.underline_thickness = FT_MulFix(holder->face->underline_thickness, metrics.y_scale) / 64.0f; return outFontInfo; } bool FontManager::TrueTypeFont::bakeGlyphAlpha(CodePoint_t _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer) -{ - BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); +{ + BX_CHECK(m_font != NULL, "TrueTypeFont not initialized"); FTHolder* holder = (FTHolder*) m_font; - - _glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, _codePoint ); - + + _glyphInfo.glyphIndex = FT_Get_Char_Index(holder->face, _codePoint); + FT_GlyphSlot slot = holder->face->glyph; - FT_Error error = FT_Load_Glyph( holder->face, _glyphInfo.glyphIndex, FT_LOAD_DEFAULT ); - if(error) { return false; } - + FT_Error error = FT_Load_Glyph(holder->face, _glyphInfo.glyphIndex, FT_LOAD_DEFAULT); + if (error) + { + return false; + } + FT_Glyph glyph; - error = FT_Get_Glyph( slot, &glyph ); - if ( error ) { return false; } - - error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 ); - if(error){ return false; } - + error = FT_Get_Glyph(slot, &glyph); + if (error) + { + return false; + } + + error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1); + if (error) + { + return false; + } + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; - + int32_t x = bitmap->left; int32_t y = -bitmap->top; int32_t w = bitmap->bitmap.width; int32_t h = bitmap->bitmap.rows; _glyphInfo.offset_x = (float) x; - _glyphInfo.offset_y = (float) y; - _glyphInfo.width = (float) w; - _glyphInfo.height = (float) h; - _glyphInfo.advance_x = (float)slot->advance.x /64.0f; - _glyphInfo.advance_y = (float)slot->advance.y /64.0f; + _glyphInfo.offset_y = (float) y; + _glyphInfo.width = (float) w; + _glyphInfo.height = (float) h; + _glyphInfo.advance_x = (float)slot->advance.x / 64.0f; + _glyphInfo.advance_y = (float)slot->advance.y / 64.0f; int32_t charsize = 1; - int32_t depth=1; + int32_t depth = 1; int32_t stride = bitmap->bitmap.pitch; - for( int32_t ii=0; iibitmap.buffer + (ii*stride) * charsize, w * charsize * depth ); - } + for (int32_t ii = 0; ii < h; ++ii) + { + memcpy(_outBuffer + (ii * w) * charsize * depth, + bitmap->bitmap.buffer + (ii * stride) * charsize, w * charsize * depth); + } + FT_Done_Glyph(glyph); return true; } bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer) { - BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); + BX_CHECK(m_font != NULL, "TrueTypeFont not initialized"); FTHolder* holder = (FTHolder*) m_font; - - _glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, _codePoint ); - + + _glyphInfo.glyphIndex = FT_Get_Char_Index(holder->face, _codePoint); + FT_GlyphSlot slot = holder->face->glyph; - FT_Error error = FT_Load_Glyph( holder->face, _glyphInfo.glyphIndex, FT_LOAD_DEFAULT ); - if(error) { return false; } - + FT_Error error = FT_Load_Glyph(holder->face, _glyphInfo.glyphIndex, FT_LOAD_DEFAULT); + if (error) + { + return false; + } + FT_Glyph glyph; - error = FT_Get_Glyph( slot, &glyph ); - if ( error ) { return false; } - - error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_LCD, 0, 1 ); - if(error){ return false; } - + error = FT_Get_Glyph(slot, &glyph); + if (error) + { + return false; + } + + error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_LCD, 0, 1); + if (error) + { + return false; + } + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; int32_t x = bitmap->left; int32_t y = -bitmap->top; @@ -247,216 +269,257 @@ bool FontManager::TrueTypeFont::bakeGlyphSubpixel(CodePoint_t _codePoint, GlyphI int32_t h = bitmap->bitmap.rows; _glyphInfo.offset_x = (float) x; - _glyphInfo.offset_y = (float) y; - _glyphInfo.width = (float) w; - _glyphInfo.height = (float) h; - _glyphInfo.advance_x = (float)slot->advance.x /64.0f; - _glyphInfo.advance_y = (float)slot->advance.y /64.0f; + _glyphInfo.offset_y = (float) y; + _glyphInfo.width = (float) w; + _glyphInfo.height = (float) h; + _glyphInfo.advance_x = (float)slot->advance.x / 64.0f; + _glyphInfo.advance_y = (float)slot->advance.y / 64.0f; int32_t charsize = 1; - int32_t depth=3; + int32_t depth = 3; int32_t stride = bitmap->bitmap.pitch; - for( int32_t ii=0; iibitmap.buffer + (ii*stride) * charsize, w * charsize * depth ); - } + for (int32_t ii = 0; ii < h; ++ii) + { + memcpy(_outBuffer + (ii * w) * charsize * depth, + bitmap->bitmap.buffer + (ii * stride) * charsize, w * charsize * depth); + } + FT_Done_Glyph(glyph); return true; } //TODO optimize: remove dynamic allocation and convert double to float -void make_distance_map( unsigned char *img, unsigned char *outImg, unsigned int width, unsigned int height ) +void make_distance_map(unsigned char* img, unsigned char* outImg, unsigned int width, unsigned int height) { - short * xdist = (short *) malloc( width * height * sizeof(short) ); - short * ydist = (short *) malloc( width * height * sizeof(short) ); - double * gx = (double *) calloc( width * height, sizeof(double) ); - double * gy = (double *) calloc( width * height, sizeof(double) ); - double * data = (double *) calloc( width * height, sizeof(double) ); - double * outside = (double *) calloc( width * height, sizeof(double) ); - double * inside = (double *) calloc( width * height, sizeof(double) ); - uint32_t ii; + short* xdist = (short*) malloc(width * height * sizeof(short) ); + short* ydist = (short*) malloc(width * height * sizeof(short) ); + double* gx = (double*) calloc(width * height, sizeof(double) ); + double* gy = (double*) calloc(width * height, sizeof(double) ); + double* data = (double*) calloc(width * height, sizeof(double) ); + double* outside = (double*) calloc(width * height, sizeof(double) ); + double* inside = (double*) calloc(width * height, sizeof(double) ); + uint32_t ii; - // Convert img into double (data) - double img_min = 255, img_max = -255; - for( ii=0; ii img_max) img_max = v; - if (v < img_min) img_min = v; - } - // Rescale image levels between 0 and 1 - for( ii=0; ii img_max) + { + img_max = v; + } - // Compute outside = edtaa3(bitmap); % Transform background (0's) - computegradient( data, width, height, gx, gy); - edtaa3(data, gx, gy, width, height, xdist, ydist, outside); - for( ii=0; ii255) out[i] = 255; outside[ii] -= inside[ii]; - outside[ii] = 128 + outside[ii]*16; + outside[ii] = 128 + outside[ii] * 16; //if(outside[i] > 8) outside[i] = 8; //if(inside[i] > 8) outside[i] = 8; //outside[i] = 128 - inside[i]*8 + outside[i]*8; - - if( outside[ii] < 0 ) outside[ii] = 0; - if( outside[ii] > 255 ) outside[ii] = 255; - out[ii] = 255 - (unsigned char) outside[ii]; - //out[i] = (unsigned char) outside[i]; - } - free( xdist ); - free( ydist ); - free( gx ); - free( gy ); - free( data ); - free( outside ); - free( inside ); + if (outside[ii] < 0) + { + outside[ii] = 0; + } + + if (outside[ii] > 255) + { + outside[ii] = 255; + } + + out[ii] = 255 - (unsigned char) outside[ii]; + //out[i] = (unsigned char) outside[i]; + } + + free(xdist); + free(ydist); + free(gx); + free(gy); + free(data); + free(outside); + free(inside); } - bool FontManager::TrueTypeFont::bakeGlyphDistance(CodePoint_t _codePoint, GlyphInfo& _glyphInfo, uint8_t* _outBuffer) -{ - BX_CHECK(m_font != NULL, "TrueTypeFont not initialized" ); +{ + BX_CHECK(m_font != NULL, "TrueTypeFont not initialized"); FTHolder* holder = (FTHolder*) m_font; - - _glyphInfo.glyphIndex = FT_Get_Char_Index( holder->face, _codePoint ); - - FT_Int32 loadMode = FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING; + + _glyphInfo.glyphIndex = FT_Get_Char_Index(holder->face, _codePoint); + + FT_Int32 loadMode = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; FT_Render_Mode renderMode = FT_RENDER_MODE_NORMAL; FT_GlyphSlot slot = holder->face->glyph; - FT_Error error = FT_Load_Glyph( holder->face, _glyphInfo.glyphIndex, loadMode ); - if(error) { return false; } - + FT_Error error = FT_Load_Glyph(holder->face, _glyphInfo.glyphIndex, loadMode); + if (error) + { + return false; + } + FT_Glyph glyph; - error = FT_Get_Glyph( slot, &glyph ); - if ( error ) { return false; } - - error = FT_Glyph_To_Bitmap( &glyph, renderMode, 0, 1 ); - if(error){ return false; } - + error = FT_Get_Glyph(slot, &glyph); + if (error) + { + return false; + } + + error = FT_Glyph_To_Bitmap(&glyph, renderMode, 0, 1); + if (error) + { + return false; + } + FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; - + int32_t x = bitmap->left; int32_t y = -bitmap->top; int32_t w = bitmap->bitmap.width; int32_t h = bitmap->bitmap.rows; _glyphInfo.offset_x = (float) x; - _glyphInfo.offset_y = (float) y; - _glyphInfo.width = (float) w; - _glyphInfo.height = (float) h; - _glyphInfo.advance_x = (float)slot->advance.x /64.0f; - _glyphInfo.advance_y = (float)slot->advance.y /64.0f; - - int32_t charsize = 1; - int32_t depth=1; - int32_t stride = bitmap->bitmap.pitch; - - for(int32_t ii=0; iiadvance.x / 64.0f; + _glyphInfo.advance_y = (float)slot->advance.y / 64.0f; + + int32_t charsize = 1; + int32_t depth = 1; + int32_t stride = bitmap->bitmap.pitch; + + for (int32_t ii = 0; ii < h; ++ii) + { + memcpy(_outBuffer + (ii * w) * charsize * depth, + bitmap->bitmap.buffer + (ii * stride) * charsize, w * charsize * depth); + } - memcpy(_outBuffer+(ii*w) * charsize * depth, - bitmap->bitmap.buffer + (ii*stride) * charsize, w * charsize * depth ); - } FT_Done_Glyph(glyph); - - if(w*h >0) + + if (w * h > 0) { uint32_t dw = 6; - uint32_t dh = 6; - if(dw<2) dw = 2; - if(dh<2) dh = 2; - - uint32_t nw = w + dw*2; - uint32_t nh = h + dh*2; - BX_CHECK(nw*nh < 128*128, "buffer overflow"); - uint32_t buffSize = nw*nh*sizeof(uint8_t); - - uint8_t * alphaImg = (uint8_t *) malloc( buffSize ); - memset(alphaImg, 0, nw*nh*sizeof(uint8_t)); + uint32_t dh = 6; + if (dw < 2) + { + dw = 2; + } + + if (dh < 2) + { + dh = 2; + } + + uint32_t nw = w + dw * 2; + uint32_t nh = h + dh * 2; + BX_CHECK(nw * nh < 128 * 128, "buffer overflow"); + uint32_t buffSize = nw * nh * sizeof(uint8_t); + + uint8_t* alphaImg = (uint8_t*) malloc(buffSize); + memset(alphaImg, 0, nw * nh * sizeof(uint8_t) ); //copy the original buffer to the temp one - for(uint32_t ii= dh; ii< nh-dh; ++ii) + for (uint32_t ii = dh; ii < nh - dh; ++ii) { - memcpy(alphaImg+ii*nw+dw, _outBuffer+(ii-dh)*w, w); + memcpy(alphaImg + ii * nw + dw, _outBuffer + (ii - dh) * w, w); } - + make_distance_map(alphaImg, _outBuffer, nw, nh); - free(alphaImg); - + free(alphaImg); + _glyphInfo.offset_x -= (float) dw; _glyphInfo.offset_y -= (float) dh; - _glyphInfo.width = (float) nw ; + _glyphInfo.width = (float) nw; _glyphInfo.height = (float) nh; } - - return true; + + return true; } - - //************************************************************* -typedef stl::unordered_map GlyphHash_t; +typedef stl::unordered_map GlyphHash_t; // cache font data struct FontManager::CachedFont { - CachedFont(){ trueTypeFont = NULL; masterFontHandle.idx = -1; } + CachedFont() + { + trueTypeFont = NULL; masterFontHandle.idx = -1; + } FontInfo fontInfo; GlyphHash_t cachedGlyphs; FontManager::TrueTypeFont* trueTypeFont; // an handle to a master font in case of sub distance field font - FontHandle masterFontHandle; + FontHandle masterFontHandle; int16_t padding; }; - - - const uint16_t MAX_OPENED_FILES = 64; const uint16_t MAX_OPENED_FONT = 64; -const uint32_t MAX_FONT_BUFFER_SIZE = 512*512*4; +const uint32_t MAX_FONT_BUFFER_SIZE = 512 * 512 * 4; -FontManager::FontManager(Atlas* _atlas):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) +FontManager::FontManager(Atlas* _atlas) : m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) { m_atlas = _atlas; - m_ownAtlas = false; - init(); + m_ownAtlas = false; + init(); } -FontManager::FontManager(uint32_t _textureSideWidth):m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) +FontManager::FontManager(uint32_t _textureSideWidth) : m_filesHandles(MAX_OPENED_FILES), m_fontHandles(MAX_OPENED_FONT) { m_atlas = new Atlas(_textureSideWidth); - m_ownAtlas = true; + m_ownAtlas = true; init(); } @@ -465,73 +528,72 @@ void FontManager::init() m_cachedFiles = new CachedFile[MAX_OPENED_FILES]; m_cachedFonts = new CachedFont[MAX_OPENED_FONT]; m_buffer = new uint8_t[MAX_FONT_BUFFER_SIZE]; - + const uint32_t W = 3; // Create filler rectangle - uint8_t buffer[W*W*4]; - memset( buffer, 255, W * W * 4); + uint8_t buffer[W * W * 4]; + memset(buffer, 255, W * W * 4); m_blackGlyph.width = W; m_blackGlyph.height = W; ///make sure the black glyph doesn't bleed by using a one pixel inner outline - m_blackGlyph.regionIndex = m_atlas->addRegion(W, W, buffer, AtlasRegion::TYPE_GRAY, 1 ); + m_blackGlyph.regionIndex = m_atlas->addRegion(W, W, buffer, AtlasRegion::TYPE_GRAY, 1); } FontManager::~FontManager() { BX_CHECK(m_fontHandles.getNumHandles() == 0, "All the fonts must be destroyed before destroying the manager"); - delete [] m_cachedFonts; + delete[] m_cachedFonts; BX_CHECK(m_filesHandles.getNumHandles() == 0, "All the font files must be destroyed before destroying the manager"); - delete [] m_cachedFiles; - - delete [] m_buffer; - - if(m_ownAtlas) - { + delete[] m_cachedFiles; + + delete[] m_buffer; + + if (m_ownAtlas) + { delete m_atlas; } } - - TrueTypeHandle FontManager::loadTrueTypeFromFile(const char* _fontPath) { - FILE * pFile; - pFile = fopen (_fontPath, "rb"); - if (pFile==NULL) + FILE* pFile; + pFile = fopen(_fontPath, "rb"); + if (pFile == NULL) { TrueTypeHandle invalid = BGFX_INVALID_HANDLE; return invalid; } - + // Go to the end of the file. if (fseek(pFile, 0L, SEEK_END) == 0) { // Get the size of the file. long bufsize = ftell(pFile); - if (bufsize == -1) + if (bufsize == -1) { fclose(pFile); TrueTypeHandle invalid = BGFX_INVALID_HANDLE; return invalid; } - + uint8_t* buffer = new uint8_t[bufsize]; // Go back to the start of the file. fseek(pFile, 0L, SEEK_SET); // Read the entire file into memory. - uint32_t newLen = fread((void*)buffer, sizeof(char), bufsize, pFile); - if (newLen == 0) + uint32_t newLen = fread( (void*)buffer, sizeof(char), bufsize, pFile); + if (newLen == 0) { fclose(pFile); - delete [] buffer; + delete[] buffer; TrueTypeHandle invalid = BGFX_INVALID_HANDLE; return invalid; } + fclose(pFile); uint16_t id = m_filesHandles.alloc(); @@ -541,20 +603,21 @@ TrueTypeHandle FontManager::loadTrueTypeFromFile(const char* _fontPath) TrueTypeHandle ret = {id}; return ret; } + //TODO validate font TrueTypeHandle invalid = BGFX_INVALID_HANDLE; return invalid; } TrueTypeHandle FontManager::loadTrueTypeFromMemory(const uint8_t* _buffer, uint32_t _size) -{ - uint16_t id = m_filesHandles.alloc(); +{ + uint16_t id = m_filesHandles.alloc(); BX_CHECK(id != bx::HandleAlloc::invalid, "Invalid handle used"); m_cachedFiles[id].buffer = new uint8_t[_size]; m_cachedFiles[id].bufferSize = _size; memcpy(m_cachedFiles[id].buffer, _buffer, _size); - - //TODO validate font + + //TODO validate font TrueTypeHandle ret = {id}; return ret; } @@ -573,19 +636,19 @@ FontHandle FontManager::createFontByPixelSize(TrueTypeHandle _tt_handle, uint32_ BX_CHECK(bgfx::invalidHandle != _tt_handle.idx, "Invalid handle used"); TrueTypeFont* ttf = new TrueTypeFont(); - if(!ttf->init( m_cachedFiles[_tt_handle.idx].buffer, m_cachedFiles[_tt_handle.idx].bufferSize, _typefaceIndex, _pixelSize)) + if (!ttf->init(m_cachedFiles[_tt_handle.idx].buffer, m_cachedFiles[_tt_handle.idx].bufferSize, _typefaceIndex, _pixelSize) ) { delete ttf; FontHandle invalid = BGFX_INVALID_HANDLE; return invalid; } - + uint16_t fontIdx = m_fontHandles.alloc(); - BX_CHECK(fontIdx != bx::HandleAlloc::invalid, "Invalid handle used"); - + BX_CHECK(fontIdx != bx::HandleAlloc::invalid, "Invalid handle used"); + m_cachedFonts[fontIdx].trueTypeFont = ttf; m_cachedFonts[fontIdx].fontInfo = ttf->getFontInfo(); - m_cachedFonts[fontIdx].fontInfo.fontType = _fontType; + m_cachedFonts[fontIdx].fontInfo.fontType = _fontType; m_cachedFonts[fontIdx].fontInfo.pixelSize = _pixelSize; m_cachedFonts[fontIdx].cachedGlyphs.clear(); m_cachedFonts[fontIdx].masterFontHandle.idx = -1; @@ -608,7 +671,6 @@ FontHandle FontManager::createScaledFontToPixelSize(FontHandle _baseFontHandle, newFontInfo.underline_thickness = (newFontInfo.underline_thickness * newFontInfo.scale); newFontInfo.underline_position = (newFontInfo.underline_position * newFontInfo.scale); - uint16_t fontIdx = m_fontHandles.alloc(); BX_CHECK(fontIdx != bx::HandleAlloc::invalid, "Invalid handle used"); m_cachedFonts[fontIdx].cachedGlyphs.clear(); @@ -619,7 +681,7 @@ FontHandle FontManager::createScaledFontToPixelSize(FontHandle _baseFontHandle, return ret; } -FontHandle FontManager::loadBakedFontFromFile(const char* /*fontPath*/, const char* /*descriptorPath*/) +FontHandle FontManager::loadBakedFontFromFile(const char* /*fontPath*/, const char* /*descriptorPath*/) { //assert(false); //TODO implement FontHandle invalid = BGFX_INVALID_HANDLE; @@ -637,33 +699,35 @@ void FontManager::destroyFont(FontHandle _handle) { BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - if(m_cachedFonts[_handle.idx].trueTypeFont != NULL) + if (m_cachedFonts[_handle.idx].trueTypeFont != NULL) { delete m_cachedFonts[_handle.idx].trueTypeFont; m_cachedFonts[_handle.idx].trueTypeFont = NULL; } - m_cachedFonts[_handle.idx].cachedGlyphs.clear(); + + m_cachedFonts[_handle.idx].cachedGlyphs.clear(); m_fontHandles.free(_handle.idx); } bool FontManager::preloadGlyph(FontHandle _handle, const wchar_t* _string) -{ +{ BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); CachedFont& font = m_cachedFonts[_handle.idx]; //if truetype present - if(font.trueTypeFont != NULL) - { + if (font.trueTypeFont != NULL) + { //parse string - for( uint32_t ii=0, end = wcslen(_string) ; ii < end; ++ii ) + for (uint32_t ii = 0, end = wcslen(_string); ii < end; ++ii) { //if glyph cached, continue CodePoint_t codePoint = _string[ii]; - if(!preloadGlyph(_handle, codePoint)) + if (!preloadGlyph(_handle, codePoint) ) { return false; } } + return true; } @@ -677,37 +741,40 @@ bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) FontInfo& fontInfo = font.fontInfo; //check if glyph not already present GlyphHash_t::iterator iter = font.cachedGlyphs.find(_codePoint); - if(iter != font.cachedGlyphs.end()) + if (iter != font.cachedGlyphs.end() ) { return true; } //if truetype present - if(font.trueTypeFont != NULL) + if (font.trueTypeFont != NULL) { GlyphInfo glyphInfo; - + //bake glyph as bitmap to buffer - switch(font.fontInfo.fontType) + switch (font.fontInfo.fontType) { case FONT_TYPE_ALPHA: font.trueTypeFont->bakeGlyphAlpha(_codePoint, glyphInfo, m_buffer); break; + //case FONT_TYPE_LCD: - //font.m_trueTypeFont->bakeGlyphSubpixel(codePoint, glyphInfo, m_buffer); - //break; + //font.m_trueTypeFont->bakeGlyphSubpixel(codePoint, glyphInfo, m_buffer); + //break; case FONT_TYPE_DISTANCE: font.trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer); break; + case FONT_TYPE_DISTANCE_SUBPIXEL: font.trueTypeFont->bakeGlyphDistance(_codePoint, glyphInfo, m_buffer); break; + default: BX_CHECK(false, "TextureType not supported yet"); - }; + } //copy bitmap to texture - if(!addBitmap(glyphInfo, m_buffer) ) + if (!addBitmap(glyphInfo, m_buffer) ) { return false; } @@ -717,17 +784,18 @@ bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) glyphInfo.offset_x = (glyphInfo.offset_x * fontInfo.scale); glyphInfo.offset_y = (glyphInfo.offset_y * fontInfo.scale); glyphInfo.height = (glyphInfo.height * fontInfo.scale); - glyphInfo.width = (glyphInfo.width * fontInfo.scale); + glyphInfo.width = (glyphInfo.width * fontInfo.scale); // store cached glyph font.cachedGlyphs[_codePoint] = glyphInfo; return true; - }else + } + else { //retrieve glyph from parent font if any - if(font.masterFontHandle.idx != bgfx::invalidHandle) + if (font.masterFontHandle.idx != bgfx::invalidHandle) { - if(preloadGlyph(font.masterFontHandle, _codePoint)) + if (preloadGlyph(font.masterFontHandle, _codePoint) ) { GlyphInfo glyphInfo; getGlyphInfo(font.masterFontHandle, _codePoint, glyphInfo); @@ -750,33 +818,34 @@ bool FontManager::preloadGlyph(FontHandle _handle, CodePoint_t _codePoint) } const FontInfo& FontManager::getFontInfo(FontHandle _handle) -{ +{ BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); return m_cachedFonts[_handle.idx].fontInfo; } bool FontManager::getGlyphInfo(FontHandle _handle, CodePoint_t _codePoint, GlyphInfo& _outInfo) -{ +{ GlyphHash_t::iterator iter = m_cachedFonts[_handle.idx].cachedGlyphs.find(_codePoint); - if(iter == m_cachedFonts[_handle.idx].cachedGlyphs.end()) + if (iter == m_cachedFonts[_handle.idx].cachedGlyphs.end() ) { - if(preloadGlyph(_handle, _codePoint)) + if (preloadGlyph(_handle, _codePoint) ) { iter = m_cachedFonts[_handle.idx].cachedGlyphs.find(_codePoint); - }else + } + else { return false; } } + _outInfo = iter->second; return true; } // **************************************************************************** - bool FontManager::addBitmap(GlyphInfo& _glyphInfo, const uint8_t* _data) { - _glyphInfo.regionIndex = m_atlas->addRegion((uint16_t) ceil(_glyphInfo.width),(uint16_t) ceil(_glyphInfo.height), _data, AtlasRegion::TYPE_GRAY); + _glyphInfo.regionIndex = m_atlas->addRegion( (uint16_t) ceil(_glyphInfo.width), (uint16_t) ceil(_glyphInfo.height), _data, AtlasRegion::TYPE_GRAY); return true; } diff --git a/examples/common/font/font_manager.h b/examples/common/font/font_manager.h index ce4be0c9..3b0d0745 100644 --- a/examples/common/font/font_manager.h +++ b/examples/common/font/font_manager.h @@ -12,7 +12,7 @@ class Atlas; enum FontType { - FONT_TYPE_ALPHA = 0x00000100 , // L8 + FONT_TYPE_ALPHA = 0x00000100, // L8 //FONT_TYPE_LCD = 0x00000200, // BGRA8 //FONT_TYPE_RGBA = 0x00000300, // BGRA8 FONT_TYPE_DISTANCE = 0x00000400, // L8 @@ -21,7 +21,7 @@ enum FontType struct FontInfo { - //the font height in pixel + //the font height in pixel uint16_t pixelSize; /// Rendering type used for the font int16_t fontType; @@ -36,7 +36,7 @@ struct FontInfo float underline_thickness; /// The position of the underline relatively to the baseline float underline_position; - + //scale to apply to glyph data float scale; }; @@ -47,26 +47,26 @@ struct FontInfo // xmin xmax // | | // |<-------- width -------->| -// | | +// | | // | +-------------------------+----------------- ymax // | | ggggggggg ggggg | ^ ^ -// | | g:::::::::ggg::::g | | | -// | | g:::::::::::::::::g | | | -// | | g::::::ggggg::::::gg | | | -// | | g:::::g g:::::g | | | -// offset_x -|-------->| g:::::g g:::::g | offset_y | -// | | g:::::g g:::::g | | | -// | | g::::::g g:::::g | | | -// | | g:::::::ggggg:::::g | | | +// | | g:::::::::ggg::::g | | | +// | | g:::::::::::::::::g | | | +// | | g::::::ggggg::::::gg | | | +// | | g:::::g g:::::g | | | +// offset_x -|-------->| g:::::g g:::::g | offset_y | +// | | g:::::g g:::::g | | | +// | | g::::::g g:::::g | | | +// | | g:::::::ggggg:::::g | | | // | | g::::::::::::::::g | | height -// | | gg::::::::::::::g | | | +// | | gg::::::::::::::g | | | // baseline ---*---------|---- gggggggg::::::g-----*-------- | -// / | | g:::::g | | -// origin | | gggggg g:::::g | | -// | | g:::::gg gg:::::g | | -// | | g::::::ggg:::::::g | | -// | | gg:::::::::::::g | | -// | | ggg::::::ggg | | +// / | | g:::::g | | +// origin | | gggggg g:::::g | | +// | | g:::::gg gg:::::g | | +// | | g::::::ggg:::::::g | | +// | | gg:::::::::::::g | | +// | | ggg::::::ggg | | // | | gggggg | v // | +-------------------------+----------------- ymin // | | @@ -75,18 +75,18 @@ struct FontInfo /// Unicode value of a character typedef int32_t CodePoint_t; -/// A structure that describe a glyph. +/// A structure that describe a glyph. struct GlyphInfo { /// Index for faster retrieval int32_t glyphIndex; - + /// Glyph's width in pixels. float width; /// Glyph's height in pixels. float height; - + /// Glyph's left offset in pixels float offset_x; @@ -98,15 +98,15 @@ struct GlyphInfo /// For horizontal text layouts, this is the unscaled horizontal distance in pixels /// used to increment the pen position when the glyph is drawn as part of a string of text. float advance_x; - + /// For vertical text layouts, this is the unscaled vertical distance in pixels /// used to increment the pen position when the glyph is drawn as part of a string of text. float advance_y; - + /// region index in the atlas storing textures uint16_t regionIndex; ///32 bits alignment - int16_t padding; + int16_t padding; }; BGFX_HANDLE(TrueTypeHandle); @@ -115,94 +115,100 @@ BGFX_HANDLE(FontHandle); class FontManager { public: - /// create the font manager using an external cube atlas (doesn't take ownership of the atlas) - FontManager(Atlas* _atlas); - /// create the font manager and create the texture cube as BGRA8 with linear filtering - FontManager(uint32_t _textureSideWidth = 512); +/// create the font manager using an external cube atlas (doesn't take ownership of the atlas) +FontManager(Atlas* _atlas); +/// create the font manager and create the texture cube as BGRA8 with linear filtering +FontManager(uint32_t _textureSideWidth = 512); - ~FontManager(); +~FontManager(); - /// retrieve the atlas used by the font manager (e.g. to add stuff to it) - Atlas* getAtlas() { return m_atlas; } - - /// load a TrueType font from a file path - /// @return invalid handle if the loading fail - TrueTypeHandle loadTrueTypeFromFile(const char* _fontPath); +/// retrieve the atlas used by the font manager (e.g. to add stuff to it) +Atlas* getAtlas() +{ + return m_atlas; +} - /// load a TrueType font from a given buffer. - /// the buffer is copied and thus can be freed or reused after this call - /// @return invalid handle if the loading fail - TrueTypeHandle loadTrueTypeFromMemory(const uint8_t* _buffer, uint32_t _size); +/// load a TrueType font from a file path +/// @return invalid handle if the loading fail +TrueTypeHandle loadTrueTypeFromFile(const char* _fontPath); - /// unload a TrueType font (free font memory) but keep loaded glyphs - void unloadTrueType(TrueTypeHandle _handle); - - /// return a font whose height is a fixed pixel size - FontHandle createFontByPixelSize(TrueTypeHandle _handle, uint32_t _typefaceIndex, uint32_t _pixelSize, FontType _fontType = FONT_TYPE_ALPHA); +/// load a TrueType font from a given buffer. +/// the buffer is copied and thus can be freed or reused after this call +/// @return invalid handle if the loading fail +TrueTypeHandle loadTrueTypeFromMemory(const uint8_t* _buffer, uint32_t _size); - /// return a scaled child font whose height is a fixed pixel size - FontHandle createScaledFontToPixelSize(FontHandle _baseFontHandle, uint32_t _pixelSize); +/// unload a TrueType font (free font memory) but keep loaded glyphs +void unloadTrueType(TrueTypeHandle _handle); - /// load a baked font (the set of glyph is fixed) - /// @return INVALID_HANDLE if the loading fail - FontHandle loadBakedFontFromFile(const char* _imagePath, const char* _descriptorPath); +/// return a font whose height is a fixed pixel size +FontHandle createFontByPixelSize(TrueTypeHandle _handle, uint32_t _typefaceIndex, uint32_t _pixelSize, FontType _fontType = FONT_TYPE_ALPHA); - /// load a baked font (the set of glyph is fixed) - /// @return INVALID_HANDLE if the loading fail - FontHandle loadBakedFontFromMemory(const uint8_t* _imageBuffer, uint32_t _imageSize, const uint8_t* _descriptorBuffer, uint32_t _descriptorSize); +/// return a scaled child font whose height is a fixed pixel size +FontHandle createScaledFontToPixelSize(FontHandle _baseFontHandle, uint32_t _pixelSize); - /// destroy a font (truetype or baked) - void destroyFont(FontHandle _handle); +/// load a baked font (the set of glyph is fixed) +/// @return INVALID_HANDLE if the loading fail +FontHandle loadBakedFontFromFile(const char* _imagePath, const char* _descriptorPath); - /// Preload a set of glyphs from a TrueType file - /// @return true if every glyph could be preloaded, false otherwise - /// if the Font is a baked font, this only do validation on the characters - bool preloadGlyph(FontHandle _handle, const wchar_t* _string); +/// load a baked font (the set of glyph is fixed) +/// @return INVALID_HANDLE if the loading fail +FontHandle loadBakedFontFromMemory(const uint8_t* _imageBuffer, uint32_t _imageSize, const uint8_t* _descriptorBuffer, uint32_t _descriptorSize); - /// Preload a single glyph, return true on success - bool preloadGlyph(FontHandle _handle, CodePoint_t _character); +/// destroy a font (truetype or baked) +void destroyFont(FontHandle _handle); - /// bake a font to disk (the set of preloaded glyph) - /// @return true if the baking succeed, false otherwise - bool saveBakedFont(FontHandle _handle, const char* _fontDirectory, const char* _fontName ); - - /// return the font descriptor of a font - /// @remark the handle is required to be valid - const FontInfo& getFontInfo(FontHandle _handle); - - /// Return the rendering informations about the glyph region - /// Load the glyph from a TrueType font if possible - /// @return true if the Glyph is available - bool getGlyphInfo(FontHandle _handle, CodePoint_t _codePoint, GlyphInfo& _outInfo); +/// Preload a set of glyphs from a TrueType file +/// @return true if every glyph could be preloaded, false otherwise +/// if the Font is a baked font, this only do validation on the characters +bool preloadGlyph(FontHandle _handle, const wchar_t* _string); - GlyphInfo& getBlackGlyph(){ return m_blackGlyph; } +/// Preload a single glyph, return true on success +bool preloadGlyph(FontHandle _handle, CodePoint_t _character); - class TrueTypeFont; //public to shut off Intellisense warning +/// bake a font to disk (the set of preloaded glyph) +/// @return true if the baking succeed, false otherwise +bool saveBakedFont(FontHandle _handle, const char* _fontDirectory, const char* _fontName); + +/// return the font descriptor of a font +/// @remark the handle is required to be valid +const FontInfo& getFontInfo(FontHandle _handle); + +/// Return the rendering informations about the glyph region +/// Load the glyph from a TrueType font if possible +/// @return true if the Glyph is available +bool getGlyphInfo(FontHandle _handle, CodePoint_t _codePoint, GlyphInfo& _outInfo); + +GlyphInfo& getBlackGlyph() +{ + return m_blackGlyph; +} + +class TrueTypeFont; //public to shut off Intellisense warning private: - - struct CachedFont; - struct CachedFile - { - uint8_t* buffer; - uint32_t bufferSize; - }; - void init(); - bool addBitmap(GlyphInfo& _glyphInfo, const uint8_t* _data); +struct CachedFont; +struct CachedFile +{ + uint8_t* buffer; + uint32_t bufferSize; +}; - bool m_ownAtlas; - Atlas* m_atlas; - - bx::HandleAlloc m_fontHandles; - CachedFont* m_cachedFonts; - - bx::HandleAlloc m_filesHandles; - CachedFile* m_cachedFiles; - - GlyphInfo m_blackGlyph; +void init(); +bool addBitmap(GlyphInfo& _glyphInfo, const uint8_t* _data); - //temporary buffer to raster glyph - uint8_t* m_buffer; +bool m_ownAtlas; +Atlas* m_atlas; + +bx::HandleAlloc m_fontHandles; +CachedFont* m_cachedFonts; + +bx::HandleAlloc m_filesHandles; +CachedFile* m_cachedFiles; + +GlyphInfo m_blackGlyph; + +//temporary buffer to raster glyph +uint8_t* m_buffer; }; #endif // __FONT_MANAGER_H__ diff --git a/examples/common/font/text_buffer_manager.cpp b/examples/common/font/text_buffer_manager.cpp index c5047c3f..ee851b79 100644 --- a/examples/common/font/text_buffer_manager.cpp +++ b/examples/common/font/text_buffer_manager.cpp @@ -16,173 +16,220 @@ #include "vs_font_distance_field_subpixel.bin.h" #include "fs_font_distance_field_subpixel.bin.h" - -#define MAX_TEXT_BUFFER_COUNT 64 +#define MAX_TEXT_BUFFER_COUNT 64 #define MAX_BUFFERED_CHARACTERS 8192 // Table from Flexible and Economical UTF-8 Decoder // Copyright (c) 2008-2009 Bjoern Hoehrmann // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. -static const uint8_t utf8d[] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df - 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef - 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff - 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 - 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 - 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 - 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 +static const uint8_t utf8d[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df + 0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3,0x3, // e0..ef + 0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8,0x8, // f0..ff + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1,0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // s7..s8 }; #define UTF8_ACCEPT 0 #define UTF8_REJECT 1 -inline uint32_t utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte) { - uint32_t type = utf8d[byte]; +inline uint32_t utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte) +{ + uint32_t type = utf8d[byte]; - *codep = (*state != UTF8_ACCEPT) ? - (byte & 0x3fu) | (*codep << 6) : - (0xff >> type) & (byte); + *codep = (*state != UTF8_ACCEPT) ? + (byte & 0x3fu) | (*codep << 6) : + (0xff >> type) & (byte); - *state = utf8d[256 + *state*16 + type]; - return *state; + *state = utf8d[256 + *state * 16 + type]; + return *state; } -inline int utf8_strlen(uint8_t* s, size_t* count) { - uint32_t codepoint; - uint32_t state = 0; +inline int utf8_strlen(uint8_t* s, size_t* count) +{ + uint32_t codepoint; + uint32_t state = 0; - for (*count = 0; *s; ++s) - if (!utf8_decode(&state, &codepoint, *s)) - *count += 1; + for (*count = 0; *s; ++s) + { + if (!utf8_decode(&state, &codepoint, *s) ) + { + *count += 1; + } + } - return state != UTF8_ACCEPT; + return state != UTF8_ACCEPT; } - class TextBuffer { -public: - - /// TextBuffer is bound to a fontManager for glyph retrieval - /// @remark the ownership of the manager is not taken - TextBuffer(FontManager* _fontManager); - ~TextBuffer(); +public: - void setStyle(uint32_t _flags = STYLE_NORMAL) { m_styleFlags = _flags; } - void setTextColor(uint32_t _rgba = 0x000000FF) { m_textColor = toABGR(_rgba); } - void setBackgroundColor(uint32_t _rgba = 0x000000FF) { m_backgroundColor = toABGR(_rgba); } +/// TextBuffer is bound to a fontManager for glyph retrieval +/// @remark the ownership of the manager is not taken +TextBuffer(FontManager* _fontManager); +~TextBuffer(); - void setOverlineColor(uint32_t _rgba = 0x000000FF) { m_overlineColor = toABGR(_rgba); } - void setUnderlineColor(uint32_t _rgba = 0x000000FF) { m_underlineColor = toABGR(_rgba); } - void setStrikeThroughColor(uint32_t _rgba = 0x000000FF) { m_strikeThroughColor = toABGR(_rgba); } - - void setPenPosition(float _x, float _y) { m_penX = _x; m_penY = _y; } - - /// return the size of the text - //Rectangle measureText(FontHandle _fontHandle, const char * _string); - //Rectangle measureText(FontHandle _fontHandle, const wchar_t * _string); +void setStyle(uint32_t _flags = STYLE_NORMAL) +{ + m_styleFlags = _flags; +} +void setTextColor(uint32_t _rgba = 0x000000FF) +{ + m_textColor = toABGR(_rgba); +} +void setBackgroundColor(uint32_t _rgba = 0x000000FF) +{ + m_backgroundColor = toABGR(_rgba); +} - /// append an ASCII/utf-8 string to the buffer using current pen position and color - void appendText(FontHandle _fontHandle, const char * _string); +void setOverlineColor(uint32_t _rgba = 0x000000FF) +{ + m_overlineColor = toABGR(_rgba); +} +void setUnderlineColor(uint32_t _rgba = 0x000000FF) +{ + m_underlineColor = toABGR(_rgba); +} +void setStrikeThroughColor(uint32_t _rgba = 0x000000FF) +{ + m_strikeThroughColor = toABGR(_rgba); +} - /// append a wide char unicode string to the buffer using current pen position and color - void appendText(FontHandle _fontHandle, const wchar_t * _string); +void setPenPosition(float _x, float _y) +{ + m_penX = _x; m_penY = _y; +} - /// Clear the text buffer and reset its state (pen/color) - void clearTextBuffer(); - - /// get pointer to the vertex buffer to submit it to the graphic card - const uint8_t* getVertexBuffer(){ return (uint8_t*) m_vertexBuffer; } - /// number of vertex in the vertex buffer - uint32_t getVertexCount(){ return m_vertexCount; } - /// size in bytes of a vertex - uint32_t getVertexSize(){ return sizeof(TextVertex); } - - /// get a pointer to the index buffer to submit it to the graphic - const uint16_t* getIndexBuffer(){ return m_indexBuffer; } - /// number of index in the index buffer - uint32_t getIndexCount(){ return m_indexCount; } - /// size in bytes of an index - uint32_t getIndexSize(){ return sizeof(uint16_t); } +/// return the size of the text +//Rectangle measureText(FontHandle _fontHandle, const char * _string); +//Rectangle measureText(FontHandle _fontHandle, const wchar_t * _string); - uint32_t getTextColor(){ return toABGR(m_textColor); } +/// append an ASCII/utf-8 string to the buffer using current pen position and color +void appendText(FontHandle _fontHandle, const char* _string); - TextRectangle getRectangle() const { return m_rectangle; } +/// append a wide char unicode string to the buffer using current pen position and color +void appendText(FontHandle _fontHandle, const wchar_t* _string); + +/// Clear the text buffer and reset its state (pen/color) +void clearTextBuffer(); + +/// get pointer to the vertex buffer to submit it to the graphic card +const uint8_t* getVertexBuffer() +{ + return (uint8_t*) m_vertexBuffer; +} +/// number of vertex in the vertex buffer +uint32_t getVertexCount() +{ + return m_vertexCount; +} +/// size in bytes of a vertex +uint32_t getVertexSize() +{ + return sizeof(TextVertex); +} + +/// get a pointer to the index buffer to submit it to the graphic +const uint16_t* getIndexBuffer() +{ + return m_indexBuffer; +} +/// number of index in the index buffer +uint32_t getIndexCount() +{ + return m_indexCount; +} +/// size in bytes of an index +uint32_t getIndexSize() +{ + return sizeof(uint16_t); +} + +uint32_t getTextColor() +{ + return toABGR(m_textColor); +} + +TextRectangle getRectangle() const +{ + return m_rectangle; +} private: - void appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, const GlyphInfo& _glyphInfo); - void verticalCenterLastLine(float _txtDecalY, float _top, float _bottom); - uint32_t toABGR(uint32_t _rgba) - { - return (((_rgba >> 0) & 0xff) << 24) | - (((_rgba >> 8) & 0xff) << 16) | - (((_rgba >> 16) & 0xff) << 8) | - (((_rgba >> 24) & 0xff) << 0); - } - - uint32_t m_styleFlags; +void appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, const GlyphInfo& _glyphInfo); +void verticalCenterLastLine(float _txtDecalY, float _top, float _bottom); +uint32_t toABGR(uint32_t _rgba) +{ + return ( ( (_rgba >> 0) & 0xff) << 24) | + ( ( (_rgba >> 8) & 0xff) << 16) | + ( ( (_rgba >> 16) & 0xff) << 8) | + ( ( (_rgba >> 24) & 0xff) << 0); +} - // color states - uint32_t m_textColor; +uint32_t m_styleFlags; - uint32_t m_backgroundColor; - uint32_t m_overlineColor; - uint32_t m_underlineColor; - uint32_t m_strikeThroughColor; +// color states +uint32_t m_textColor; - //position states - float m_penX; - float m_penY; +uint32_t m_backgroundColor; +uint32_t m_overlineColor; +uint32_t m_underlineColor; +uint32_t m_strikeThroughColor; - float m_originX; - float m_originY; +//position states +float m_penX; +float m_penY; - float m_lineAscender; - float m_lineDescender; - float m_lineGap; - - TextRectangle m_rectangle; +float m_originX; +float m_originY; - /// - FontManager* m_fontManager; - - void setVertex(uint32_t _i, float _x, float _y, uint32_t _rgba, uint8_t _style = STYLE_NORMAL) - { - m_vertexBuffer[_i].x = _x; - m_vertexBuffer[_i].y = _y; - m_vertexBuffer[_i].rgba = _rgba; - m_styleBuffer[_i] = _style; - } +float m_lineAscender; +float m_lineDescender; +float m_lineGap; - struct TextVertex - { - float x,y; - int16_t u,v,w,t; - uint32_t rgba; - }; +TextRectangle m_rectangle; - TextVertex* m_vertexBuffer; - uint16_t* m_indexBuffer; - uint8_t* m_styleBuffer; - - uint32_t m_vertexCount; - uint32_t m_indexCount; - uint32_t m_lineStartIndex; +/// +FontManager* m_fontManager; + +void setVertex(uint32_t _i, float _x, float _y, uint32_t _rgba, uint8_t _style = STYLE_NORMAL) +{ + m_vertexBuffer[_i].x = _x; + m_vertexBuffer[_i].y = _y; + m_vertexBuffer[_i].rgba = _rgba; + m_styleBuffer[_i] = _style; +} + +struct TextVertex +{ + float x, y; + int16_t u, v, w, t; + uint32_t rgba; }; +TextVertex* m_vertexBuffer; +uint16_t* m_indexBuffer; +uint8_t* m_styleBuffer; - +uint32_t m_vertexCount; +uint32_t m_indexCount; +uint32_t m_lineStartIndex; +}; TextBuffer::TextBuffer(FontManager* _fontManager) -{ +{ m_styleFlags = STYLE_NORMAL; //0xAABBGGRR m_textColor = 0xFFFFFFFF; @@ -198,18 +245,16 @@ TextBuffer::TextBuffer(FontManager* _fontManager) m_lineAscender = 0; m_lineDescender = 0; m_lineGap = 0; - m_fontManager = _fontManager; + m_fontManager = _fontManager; m_rectangle.width = 0; m_rectangle.height = 0; - + m_vertexBuffer = new TextVertex[MAX_BUFFERED_CHARACTERS * 4]; m_indexBuffer = new uint16_t[MAX_BUFFERED_CHARACTERS * 6]; m_styleBuffer = new uint8_t[MAX_BUFFERED_CHARACTERS * 4]; m_vertexCount = 0; m_indexCount = 0; m_lineStartIndex = 0; - - } TextBuffer::~TextBuffer() @@ -218,67 +263,70 @@ TextBuffer::~TextBuffer() delete[] m_indexBuffer; } -void TextBuffer::appendText(FontHandle _fontHandle, const char * _string) -{ +void TextBuffer::appendText(FontHandle _fontHandle, const char* _string) +{ GlyphInfo glyph; - const FontInfo& font = m_fontManager->getFontInfo(_fontHandle); - - if(m_vertexCount == 0) + const FontInfo& font = m_fontManager->getFontInfo(_fontHandle); + + if (m_vertexCount == 0) { m_originX = m_penX; m_originY = m_penY; - m_lineDescender = 0;// font.m_descender; - m_lineAscender = 0;//font.m_ascender; - - + m_lineDescender = 0; // font.m_descender; + m_lineAscender = 0; //font.m_ascender; } - + uint32_t codepoint; uint32_t state = 0; for (; *_string; ++_string) - if (!utf8_decode(&state, &codepoint, *_string)) + { + if (!utf8_decode(&state, &codepoint, *_string) ) { - if(m_fontManager->getGlyphInfo(_fontHandle, (CodePoint_t)codepoint, glyph)) + if (m_fontManager->getGlyphInfo(_fontHandle, (CodePoint_t)codepoint, glyph) ) { - appendGlyph((CodePoint_t)codepoint, font, glyph); - }else + appendGlyph( (CodePoint_t)codepoint, font, glyph); + } + else { BX_CHECK(false, "Glyph not found"); } } - //printf("U+%04X\n", codepoint); + } + + //printf("U+%04X\n", codepoint); if (state != UTF8_ACCEPT) { - // assert(false && "The string is not well-formed"); + // assert(false && "The string is not well-formed"); return; //"The string is not well-formed\n" } } -void TextBuffer::appendText(FontHandle _fontHandle, const wchar_t * _string) -{ +void TextBuffer::appendText(FontHandle _fontHandle, const wchar_t* _string) +{ GlyphInfo glyph; - const FontInfo& font = m_fontManager->getFontInfo(_fontHandle); - - if(m_vertexCount == 0) + const FontInfo& font = m_fontManager->getFontInfo(_fontHandle); + + if (m_vertexCount == 0) { m_originX = m_penX; m_originY = m_penY; - m_lineDescender = 0;// font.m_descender; - m_lineAscender = 0;//font.m_ascender; + m_lineDescender = 0; // font.m_descender; + m_lineAscender = 0; //font.m_ascender; m_lineGap = 0; } //parse string - for( uint32_t ii=0, end = wcslen(_string) ; ii < end; ++ii ) + for (uint32_t ii = 0, end = wcslen(_string); ii < end; ++ii) { //if glyph cached, continue uint32_t _codePoint = _string[ii]; - if(m_fontManager->getGlyphInfo(_fontHandle, _codePoint, glyph)) + if (m_fontManager->getGlyphInfo(_fontHandle, _codePoint, glyph) ) { appendGlyph(_codePoint, font, glyph); - }else + } + else { BX_CHECK(false, "Glyph not found"); } @@ -286,7 +334,7 @@ void TextBuffer::appendText(FontHandle _fontHandle, const wchar_t * _string) } /* TextBuffer::Rectangle TextBuffer::measureText(FontHandle _fontHandle, const char * _string) -{ +{ } TextBuffer::Rectangle TextBuffer::measureText(FontHandle _fontHandle, const wchar_t * _string) @@ -306,198 +354,211 @@ void TextBuffer::clearTextBuffer() } void TextBuffer::appendGlyph(CodePoint_t _codePoint, const FontInfo& _font, const GlyphInfo& _glyphInfo) -{ +{ //handle newlines - if(_codePoint == L'\n' ) - { - m_penX = m_originX; - m_penY -= m_lineDescender; + if (_codePoint == L'\n') + { + m_penX = m_originX; + m_penY -= m_lineDescender; m_penY += m_lineGap; m_lineDescender = 0; m_lineAscender = 0; - m_lineStartIndex = m_vertexCount; - + m_lineStartIndex = m_vertexCount; + return; - } - - if( _font.ascender > m_lineAscender || (_font.descender < m_lineDescender) ) - { - if( _font.descender < m_lineDescender ) + } + + if (_font.ascender > m_lineAscender + || (_font.descender < m_lineDescender) ) + { + if (_font.descender < m_lineDescender) { m_lineDescender = _font.descender; m_lineGap = _font.lineGap; } - + float txtDecals = (_font.ascender - m_lineAscender); m_lineAscender = _font.ascender; - m_lineGap = _font.lineGap; - + m_lineGap = _font.lineGap; + m_penY += txtDecals; - verticalCenterLastLine((txtDecals), (m_penY - m_lineAscender), (m_penY - m_lineDescender+m_lineGap)); - } - + verticalCenterLastLine( (txtDecals), (m_penY - m_lineAscender), (m_penY - m_lineDescender + m_lineGap) ); + } + //handle kerning float kerning = 0; - /* - if( previous && markup->font->kerning ) - { - kerning = texture_glyph_get_kerning( glyph, previous ); - } + /* + if( previous && markup->font->kerning ) + { + kerning = texture_glyph_get_kerning( glyph, previous ); + } */ m_penX += kerning * _font.scale; GlyphInfo& blackGlyph = m_fontManager->getBlackGlyph(); - - if( m_styleFlags & STYLE_BACKGROUND && m_backgroundColor & 0xFF000000) + + if (m_styleFlags & STYLE_BACKGROUND + && m_backgroundColor & 0xFF000000) { - float x0 = ( m_penX - kerning ); - float y0 = ( m_penY - m_lineAscender); - float x1 = ( (float)x0 + (_glyphInfo.advance_x)); - float y1 = ( m_penY - m_lineDescender + m_lineGap ); - - m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); - - setVertex(m_vertexCount+0, x0, y0, m_backgroundColor,STYLE_BACKGROUND); - setVertex(m_vertexCount+1, x0, y1, m_backgroundColor,STYLE_BACKGROUND); - setVertex(m_vertexCount+2, x1, y1, m_backgroundColor,STYLE_BACKGROUND); - setVertex(m_vertexCount+3, x1, y0, m_backgroundColor,STYLE_BACKGROUND); - - m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; - m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; - m_vertexCount += 4; - m_indexCount += 6; - } - - if( m_styleFlags & STYLE_UNDERLINE && m_underlineColor & 0xFF000000) - { - float x0 = ( m_penX - kerning ); - float y0 = (m_penY - m_lineDescender/2 ); - float x1 = ( (float)x0 + (_glyphInfo.advance_x)); - float y1 = y0+_font.underline_thickness; - - m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); - - setVertex(m_vertexCount+0, x0, y0, m_underlineColor,STYLE_UNDERLINE); - setVertex(m_vertexCount+1, x0, y1, m_underlineColor,STYLE_UNDERLINE); - setVertex(m_vertexCount+2, x1, y1, m_underlineColor,STYLE_UNDERLINE); - setVertex(m_vertexCount+3, x1, y0, m_underlineColor,STYLE_UNDERLINE); - - m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; - m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; - m_vertexCount += 4; - m_indexCount += 6; - } - - if( m_styleFlags & STYLE_OVERLINE && m_overlineColor & 0xFF000000) - { - float x0 = ( m_penX - kerning ); - float y0 = (m_penY - _font.ascender ); - float x1 = ( (float)x0 + (_glyphInfo.advance_x)); - float y1 = y0+_font.underline_thickness; - - m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); - - setVertex(m_vertexCount+0, x0, y0, m_overlineColor,STYLE_OVERLINE); - setVertex(m_vertexCount+1, x0, y1, m_overlineColor,STYLE_OVERLINE); - setVertex(m_vertexCount+2, x1, y1, m_overlineColor,STYLE_OVERLINE); - setVertex(m_vertexCount+3, x1, y0, m_overlineColor,STYLE_OVERLINE); - - m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; - m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; - m_vertexCount += 4; - m_indexCount += 6; - } - - - if( m_styleFlags & STYLE_STRIKE_THROUGH && m_strikeThroughColor & 0xFF000000) - { - float x0 = ( m_penX - kerning ); - float y0 = (m_penY - _font.ascender/3 ); + float x0 = (m_penX - kerning); + float y0 = (m_penY - m_lineAscender); float x1 = ( (float)x0 + (_glyphInfo.advance_x) ); - float y1 = y0+_font.underline_thickness; - - m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer,sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + float y1 = (m_penY - m_lineDescender + m_lineGap); - setVertex(m_vertexCount+0, x0, y0, m_strikeThroughColor,STYLE_STRIKE_THROUGH); - setVertex(m_vertexCount+1, x0, y1, m_strikeThroughColor,STYLE_STRIKE_THROUGH); - setVertex(m_vertexCount+2, x1, y1, m_strikeThroughColor,STYLE_STRIKE_THROUGH); - setVertex(m_vertexCount+3, x1, y0, m_strikeThroughColor,STYLE_STRIKE_THROUGH); + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex) ); - m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; - m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; + setVertex(m_vertexCount + 0, x0, y0, m_backgroundColor, STYLE_BACKGROUND); + setVertex(m_vertexCount + 1, x0, y1, m_backgroundColor, STYLE_BACKGROUND); + setVertex(m_vertexCount + 2, x1, y1, m_backgroundColor, STYLE_BACKGROUND); + setVertex(m_vertexCount + 3, x1, y0, m_backgroundColor, STYLE_BACKGROUND); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3; + m_vertexCount += 4; + m_indexCount += 6; + } + + if (m_styleFlags & STYLE_UNDERLINE + && m_underlineColor & 0xFF000000) + { + float x0 = (m_penX - kerning); + float y0 = (m_penY - m_lineDescender / 2); + float x1 = ( (float)x0 + (_glyphInfo.advance_x) ); + float y1 = y0 + _font.underline_thickness; + + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex) ); + + setVertex(m_vertexCount + 0, x0, y0, m_underlineColor, STYLE_UNDERLINE); + setVertex(m_vertexCount + 1, x0, y1, m_underlineColor, STYLE_UNDERLINE); + setVertex(m_vertexCount + 2, x1, y1, m_underlineColor, STYLE_UNDERLINE); + setVertex(m_vertexCount + 3, x1, y0, m_underlineColor, STYLE_UNDERLINE); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3; + m_vertexCount += 4; + m_indexCount += 6; + } + + if (m_styleFlags & STYLE_OVERLINE + && m_overlineColor & 0xFF000000) + { + float x0 = (m_penX - kerning); + float y0 = (m_penY - _font.ascender); + float x1 = ( (float)x0 + (_glyphInfo.advance_x) ); + float y1 = y0 + _font.underline_thickness; + + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex) ); + + setVertex(m_vertexCount + 0, x0, y0, m_overlineColor, STYLE_OVERLINE); + setVertex(m_vertexCount + 1, x0, y1, m_overlineColor, STYLE_OVERLINE); + setVertex(m_vertexCount + 2, x1, y1, m_overlineColor, STYLE_OVERLINE); + setVertex(m_vertexCount + 3, x1, y0, m_overlineColor, STYLE_OVERLINE); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3; + m_vertexCount += 4; + m_indexCount += 6; + } + + if (m_styleFlags & STYLE_STRIKE_THROUGH + && m_strikeThroughColor & 0xFF000000) + { + float x0 = (m_penX - kerning); + float y0 = (m_penY - _font.ascender / 3); + float x1 = ( (float)x0 + (_glyphInfo.advance_x) ); + float y1 = y0 + _font.underline_thickness; + + m_fontManager->getAtlas()->packUV(blackGlyph.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex) ); + + setVertex(m_vertexCount + 0, x0, y0, m_strikeThroughColor, STYLE_STRIKE_THROUGH); + setVertex(m_vertexCount + 1, x0, y1, m_strikeThroughColor, STYLE_STRIKE_THROUGH); + setVertex(m_vertexCount + 2, x1, y1, m_strikeThroughColor, STYLE_STRIKE_THROUGH); + setVertex(m_vertexCount + 3, x1, y0, m_strikeThroughColor, STYLE_STRIKE_THROUGH); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3; m_vertexCount += 4; m_indexCount += 6; } - //handle glyph float x0_precise = m_penX + (_glyphInfo.offset_x); - float x0 = ( x0_precise); - float y0 = ( m_penY + (_glyphInfo.offset_y)); - float x1 = ( x0 + _glyphInfo.width ); - float y1 = ( y0 + _glyphInfo.height ); - - m_fontManager->getAtlas()->packUV(_glyphInfo.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) *m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex)); + float x0 = (x0_precise); + float y0 = (m_penY + (_glyphInfo.offset_y) ); + float x1 = (x0 + _glyphInfo.width); + float y1 = (y0 + _glyphInfo.height); - setVertex(m_vertexCount+0, x0, y0, m_textColor); - setVertex(m_vertexCount+1, x0, y1, m_textColor); - setVertex(m_vertexCount+2, x1, y1, m_textColor); - setVertex(m_vertexCount+3, x1, y0, m_textColor); + m_fontManager->getAtlas()->packUV(_glyphInfo.regionIndex, (uint8_t*)m_vertexBuffer, sizeof(TextVertex) * m_vertexCount + offsetof(TextVertex, u), sizeof(TextVertex) ); - m_indexBuffer[m_indexCount + 0] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 1] = m_vertexCount+1; - m_indexBuffer[m_indexCount + 2] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 3] = m_vertexCount+0; - m_indexBuffer[m_indexCount + 4] = m_vertexCount+2; - m_indexBuffer[m_indexCount + 5] = m_vertexCount+3; + setVertex(m_vertexCount + 0, x0, y0, m_textColor); + setVertex(m_vertexCount + 1, x0, y1, m_textColor); + setVertex(m_vertexCount + 2, x1, y1, m_textColor); + setVertex(m_vertexCount + 3, x1, y0, m_textColor); + + m_indexBuffer[m_indexCount + 0] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 1] = m_vertexCount + 1; + m_indexBuffer[m_indexCount + 2] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 3] = m_vertexCount + 0; + m_indexBuffer[m_indexCount + 4] = m_vertexCount + 2; + m_indexBuffer[m_indexCount + 5] = m_vertexCount + 3; m_vertexCount += 4; m_indexCount += 6; - + m_penX += _glyphInfo.advance_x; - if(m_penX > m_rectangle.width) m_rectangle.width = m_penX; - if( (m_penY - m_lineDescender) > m_rectangle.height) m_rectangle.height = (m_penY - m_lineDescender); - //if(x1 > m_rectangle.width) m_rectangle.width = x1; + if (m_penX > m_rectangle.width) + { + m_rectangle.width = m_penX; + } + + if ( (m_penY - m_lineDescender) > m_rectangle.height) + { + m_rectangle.height = (m_penY - m_lineDescender); + } + + //if(x1 > m_rectangle.width) m_rectangle.width = x1; //if(y1 > m_rectangle.height) m_rectangle.height = y1; } void TextBuffer::verticalCenterLastLine(float _dy, float _top, float _bottom) -{ - for( uint32_t ii=m_lineStartIndex; ii < m_vertexCount; ii+=4 ) - { - if( m_styleBuffer[ii] == STYLE_BACKGROUND) +{ + for (uint32_t ii = m_lineStartIndex; ii < m_vertexCount; ii += 4) + { + if (m_styleBuffer[ii] == STYLE_BACKGROUND) { - m_vertexBuffer[ii+0].y = _top; - m_vertexBuffer[ii+1].y = _bottom; - m_vertexBuffer[ii+2].y = _bottom; - m_vertexBuffer[ii+3].y = _top; - }else{ - m_vertexBuffer[ii+0].y += _dy; - m_vertexBuffer[ii+1].y += _dy; - m_vertexBuffer[ii+2].y += _dy; - m_vertexBuffer[ii+3].y += _dy; + m_vertexBuffer[ii + 0].y = _top; + m_vertexBuffer[ii + 1].y = _bottom; + m_vertexBuffer[ii + 2].y = _bottom; + m_vertexBuffer[ii + 3].y = _top; } - } + else + { + m_vertexBuffer[ii + 0].y += _dy; + m_vertexBuffer[ii + 1].y += _dy; + m_vertexBuffer[ii + 2].y += _dy; + m_vertexBuffer[ii + 3].y += _dy; + } + } } // **************************************************************** -TextBufferManager::TextBufferManager(FontManager* _fontManager):m_fontManager(_fontManager), m_textBufferHandles(MAX_TEXT_BUFFER_COUNT) +TextBufferManager::TextBufferManager(FontManager* _fontManager) : m_fontManager(_fontManager), m_textBufferHandles(MAX_TEXT_BUFFER_COUNT) { m_textBuffers = new BufferCache[MAX_TEXT_BUFFER_COUNT]; @@ -511,17 +572,17 @@ TextBufferManager::TextBufferManager(FontManager* _fontManager):m_fontManager(_f switch (bgfx::getRendererType() ) { case bgfx::RendererType::Direct3D9: - vs_font_basic = bgfx::makeRef(vs_font_basic_dx9, sizeof(vs_font_basic_dx9) ); - fs_font_basic = bgfx::makeRef(fs_font_basic_dx9, sizeof(fs_font_basic_dx9) ); + vs_font_basic = bgfx::makeRef(vs_font_basic_dx9, sizeof(vs_font_basic_dx9) ); + fs_font_basic = bgfx::makeRef(fs_font_basic_dx9, sizeof(fs_font_basic_dx9) ); vs_font_distance_field = bgfx::makeRef(vs_font_distance_field_dx9, sizeof(vs_font_distance_field_dx9) ); fs_font_distance_field = bgfx::makeRef(fs_font_distance_field_dx9, sizeof(fs_font_distance_field_dx9) ); vs_font_distance_field_subpixel = bgfx::makeRef(vs_font_distance_field_subpixel_dx9, sizeof(vs_font_distance_field_subpixel_dx9) ); - fs_font_distance_field_subpixel = bgfx::makeRef(fs_font_distance_field_subpixel_dx9, sizeof(fs_font_distance_field_subpixel_dx9) ); + fs_font_distance_field_subpixel = bgfx::makeRef(fs_font_distance_field_subpixel_dx9, sizeof(fs_font_distance_field_subpixel_dx9) ); break; case bgfx::RendererType::Direct3D11: - vs_font_basic = bgfx::makeRef(vs_font_basic_dx11, sizeof(vs_font_basic_dx11) ); - fs_font_basic = bgfx::makeRef(fs_font_basic_dx11, sizeof(fs_font_basic_dx11) ); + vs_font_basic = bgfx::makeRef(vs_font_basic_dx11, sizeof(vs_font_basic_dx11) ); + fs_font_basic = bgfx::makeRef(fs_font_basic_dx11, sizeof(fs_font_basic_dx11) ); vs_font_distance_field = bgfx::makeRef(vs_font_distance_field_dx11, sizeof(vs_font_distance_field_dx11) ); fs_font_distance_field = bgfx::makeRef(fs_font_distance_field_dx11, sizeof(fs_font_distance_field_dx11) ); vs_font_distance_field_subpixel = bgfx::makeRef(vs_font_distance_field_subpixel_dx11, sizeof(vs_font_distance_field_subpixel_dx11) ); @@ -529,8 +590,8 @@ TextBufferManager::TextBufferManager(FontManager* _fontManager):m_fontManager(_f break; default: - vs_font_basic = bgfx::makeRef(vs_font_basic_glsl, sizeof(vs_font_basic_glsl) ); - fs_font_basic = bgfx::makeRef(fs_font_basic_glsl, sizeof(fs_font_basic_glsl) ); + vs_font_basic = bgfx::makeRef(vs_font_basic_glsl, sizeof(vs_font_basic_glsl) ); + fs_font_basic = bgfx::makeRef(fs_font_basic_glsl, sizeof(fs_font_basic_glsl) ); vs_font_distance_field = bgfx::makeRef(vs_font_distance_field_glsl, sizeof(vs_font_distance_field_glsl) ); fs_font_distance_field = bgfx::makeRef(fs_font_distance_field_glsl, sizeof(fs_font_distance_field_glsl) ); vs_font_distance_field_subpixel = bgfx::makeRef(vs_font_distance_field_subpixel_glsl, sizeof(vs_font_distance_field_subpixel_glsl) ); @@ -540,24 +601,24 @@ TextBufferManager::TextBufferManager(FontManager* _fontManager):m_fontManager(_f bgfx::VertexShaderHandle vsh; bgfx::FragmentShaderHandle fsh; - - vsh = bgfx::createVertexShader(vs_font_basic); + + vsh = bgfx::createVertexShader(vs_font_basic); fsh = bgfx::createFragmentShader(fs_font_basic); m_basicProgram = bgfx::createProgram(vsh, fsh); bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); + bgfx::destroyFragmentShader(fsh); - vsh = bgfx::createVertexShader(vs_font_distance_field); + vsh = bgfx::createVertexShader(vs_font_distance_field); fsh = bgfx::createFragmentShader(fs_font_distance_field); m_distanceProgram = bgfx::createProgram(vsh, fsh); bgfx::destroyVertexShader(vsh); bgfx::destroyFragmentShader(fsh); - vsh = bgfx::createVertexShader(vs_font_distance_field_subpixel); + vsh = bgfx::createVertexShader(vs_font_distance_field_subpixel); fsh = bgfx::createFragmentShader(fs_font_distance_field_subpixel); m_distanceSubpixelProgram = bgfx::createProgram(vsh, fsh); bgfx::destroyVertexShader(vsh); - bgfx::destroyFragmentShader(fsh); + bgfx::destroyFragmentShader(fsh); m_vertexDecl.begin(); m_vertexDecl.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float); @@ -577,50 +638,54 @@ TextBufferManager::~TextBufferManager() bgfx::destroyUniform(u_texColor); bgfx::destroyUniform(u_inverse_gamma); - bgfx::destroyProgram(m_basicProgram); - bgfx::destroyProgram(m_distanceProgram); - bgfx::destroyProgram(m_distanceSubpixelProgram); + bgfx::destroyProgram(m_basicProgram); + bgfx::destroyProgram(m_distanceProgram); + bgfx::destroyProgram(m_distanceSubpixelProgram); } TextBufferHandle TextBufferManager::createTextBuffer(FontType _type, BufferType _bufferType) -{ +{ uint16_t textIdx = m_textBufferHandles.alloc(); BufferCache& bc = m_textBuffers[textIdx]; - - bc.textBuffer = new TextBuffer(m_fontManager); + + bc.textBuffer = new TextBuffer(m_fontManager); bc.fontType = _type; - bc.bufferType = _bufferType; + bc.bufferType = _bufferType; bc.indexBufferHandle = bgfx::invalidHandle; bc.vertexBufferHandle = bgfx::invalidHandle; TextBufferHandle ret = {textIdx}; - return ret; + return ret; } void TextBufferManager::destroyTextBuffer(TextBufferHandle _handle) -{ - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; m_textBufferHandles.free(_handle.idx); delete bc.textBuffer; bc.textBuffer = NULL; - if(bc.vertexBufferHandle == bgfx::invalidHandle ) return; - - switch(bc.bufferType) + if (bc.vertexBufferHandle == bgfx::invalidHandle) + { + return; + } + + switch (bc.bufferType) { case STATIC: - { + { bgfx::IndexBufferHandle ibh; bgfx::VertexBufferHandle vbh; ibh.idx = bc.indexBufferHandle; vbh.idx = bc.vertexBufferHandle; bgfx::destroyIndexBuffer(ibh); bgfx::destroyVertexBuffer(vbh); - } + } + + break; - break; case DYNAMIC: bgfx::DynamicIndexBufferHandle ibh; bgfx::DynamicVertexBufferHandle vbh; @@ -628,114 +693,122 @@ void TextBufferManager::destroyTextBuffer(TextBufferHandle _handle) vbh.idx = bc.vertexBufferHandle; bgfx::destroyDynamicIndexBuffer(ibh); bgfx::destroyDynamicVertexBuffer(vbh); - + break; + case TRANSIENT: //naturally destroyed - break; - } + break; + } } void TextBufferManager::submitTextBuffer(TextBufferHandle _handle, uint8_t _id, int32_t _depth) { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - + uint32_t indexSize = bc.textBuffer->getIndexCount() * bc.textBuffer->getIndexSize(); uint32_t vertexSize = bc.textBuffer->getVertexCount() * bc.textBuffer->getVertexSize(); const bgfx::Memory* mem; - bgfx::setTexture(0, u_texColor, m_fontManager->getAtlas()->getTextureHandle()); - float inverse_gamme = 1.0f/2.2f; + bgfx::setTexture(0, u_texColor, m_fontManager->getAtlas()->getTextureHandle() ); + float inverse_gamme = 1.0f / 2.2f; bgfx::setUniform(u_inverse_gamma, &inverse_gamme); - + switch (bc.fontType) { case FONT_TYPE_ALPHA: bgfx::setProgram(m_basicProgram); - bgfx::setState( BGFX_STATE_RGB_WRITE | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) ); + bgfx::setState(BGFX_STATE_RGB_WRITE | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) ); break; + case FONT_TYPE_DISTANCE: bgfx::setProgram(m_distanceProgram); - bgfx::setState( BGFX_STATE_RGB_WRITE | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) ); + bgfx::setState(BGFX_STATE_RGB_WRITE | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA) ); break; + case FONT_TYPE_DISTANCE_SUBPIXEL: bgfx::setProgram(m_distanceSubpixelProgram); - bgfx::setState( BGFX_STATE_RGB_WRITE |BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR) , bc.textBuffer->getTextColor()); - break; - } + bgfx::setState(BGFX_STATE_RGB_WRITE | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_FACTOR, BGFX_STATE_BLEND_INV_SRC_COLOR), bc.textBuffer->getTextColor() ); + break; + } - switch(bc.bufferType) + switch (bc.bufferType) { - case STATIC: + case STATIC: + { + bgfx::IndexBufferHandle ibh; + bgfx::VertexBufferHandle vbh; + + if (bc.vertexBufferHandle == bgfx::invalidHandle) { - bgfx::IndexBufferHandle ibh; - bgfx::VertexBufferHandle vbh; + mem = bgfx::alloc(indexSize); + memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); + ibh = bgfx::createIndexBuffer(mem); - if(bc.vertexBufferHandle == bgfx::invalidHandle) - { - mem = bgfx::alloc(indexSize); - memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); - ibh = bgfx::createIndexBuffer(mem); + mem = bgfx::alloc(vertexSize); + memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); + vbh = bgfx::createVertexBuffer(mem, m_vertexDecl); - mem = bgfx::alloc(vertexSize); - memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); - vbh = bgfx::createVertexBuffer(mem, m_vertexDecl); - - bc.indexBufferHandle = ibh.idx ; - bc.vertexBufferHandle = vbh.idx; - }else - { - ibh.idx = bc.indexBufferHandle; - vbh.idx = bc.vertexBufferHandle; - } - bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount()); - bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount()); - }break; - case DYNAMIC: + bc.indexBufferHandle = ibh.idx; + bc.vertexBufferHandle = vbh.idx; + } + else { - bgfx::DynamicIndexBufferHandle ibh; - bgfx::DynamicVertexBufferHandle vbh; + ibh.idx = bc.indexBufferHandle; + vbh.idx = bc.vertexBufferHandle; + } - if(bc.vertexBufferHandle == bgfx::invalidHandle) - { - mem = bgfx::alloc(indexSize); - memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); - ibh = bgfx::createDynamicIndexBuffer(mem); + bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount() ); + bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount() ); + } break; - mem = bgfx::alloc(vertexSize); - memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); - vbh = bgfx::createDynamicVertexBuffer(mem, m_vertexDecl); + case DYNAMIC: + { + bgfx::DynamicIndexBufferHandle ibh; + bgfx::DynamicVertexBufferHandle vbh; - bc.indexBufferHandle = ibh.idx ; - bc.vertexBufferHandle = vbh.idx; - }else - { - ibh.idx = bc.indexBufferHandle; - vbh.idx = bc.vertexBufferHandle; - - mem = bgfx::alloc(indexSize); - memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); - bgfx::updateDynamicIndexBuffer(ibh, mem); - - mem = bgfx::alloc(vertexSize); - memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); - bgfx::updateDynamicVertexBuffer(vbh, mem); - } - bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount()); - bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount()); - - }break; - case TRANSIENT: + if (bc.vertexBufferHandle == bgfx::invalidHandle) { - bgfx::TransientIndexBuffer tib; - bgfx::TransientVertexBuffer tvb; - bgfx::allocTransientIndexBuffer(&tib, bc.textBuffer->getIndexCount()); - bgfx::allocTransientVertexBuffer(&tvb, bc.textBuffer->getVertexCount(), m_vertexDecl); - memcpy(tib.data, bc.textBuffer->getIndexBuffer(), indexSize); - memcpy(tvb.data, bc.textBuffer->getVertexBuffer(), vertexSize); - bgfx::setVertexBuffer(&tvb, bc.textBuffer->getVertexCount()); - bgfx::setIndexBuffer(&tib, bc.textBuffer->getIndexCount()); - }break; + mem = bgfx::alloc(indexSize); + memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); + ibh = bgfx::createDynamicIndexBuffer(mem); + + mem = bgfx::alloc(vertexSize); + memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); + vbh = bgfx::createDynamicVertexBuffer(mem, m_vertexDecl); + + bc.indexBufferHandle = ibh.idx; + bc.vertexBufferHandle = vbh.idx; + } + else + { + ibh.idx = bc.indexBufferHandle; + vbh.idx = bc.vertexBufferHandle; + + mem = bgfx::alloc(indexSize); + memcpy(mem->data, bc.textBuffer->getIndexBuffer(), indexSize); + bgfx::updateDynamicIndexBuffer(ibh, mem); + + mem = bgfx::alloc(vertexSize); + memcpy(mem->data, bc.textBuffer->getVertexBuffer(), vertexSize); + bgfx::updateDynamicVertexBuffer(vbh, mem); + } + + bgfx::setVertexBuffer(vbh, bc.textBuffer->getVertexCount() ); + bgfx::setIndexBuffer(ibh, bc.textBuffer->getIndexCount() ); + } break; + + case TRANSIENT: + { + bgfx::TransientIndexBuffer tib; + bgfx::TransientVertexBuffer tvb; + bgfx::allocTransientIndexBuffer(&tib, bc.textBuffer->getIndexCount() ); + bgfx::allocTransientVertexBuffer(&tvb, bc.textBuffer->getVertexCount(), m_vertexDecl); + memcpy(tib.data, bc.textBuffer->getIndexBuffer(), indexSize); + memcpy(tvb.data, bc.textBuffer->getVertexBuffer(), vertexSize); + bgfx::setVertexBuffer(&tvb, bc.textBuffer->getVertexCount() ); + bgfx::setIndexBuffer(&tib, bc.textBuffer->getIndexCount() ); + } break; } bgfx::submit(_id, _depth); @@ -747,79 +820,79 @@ void TextBufferManager::submitTextBufferMask(TextBufferHandle /*_handle*/, uint3 BX_CHECK(false, "TODO TODO"); } -void TextBufferManager::setStyle(TextBufferHandle _handle, uint32_t _flags ) -{ - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setStyle(_flags); -} - -void TextBufferManager::setTextColor(TextBufferHandle _handle, uint32_t _rgba ) -{ - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setTextColor(_rgba); -} - -void TextBufferManager::setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba ) -{ - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setBackgroundColor(_rgba); -} - -void TextBufferManager::setOverlineColor(TextBufferHandle _handle, uint32_t _rgba ) -{ - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setOverlineColor(_rgba); -} - -void TextBufferManager::setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba ) +void TextBufferManager::setStyle(TextBufferHandle _handle, uint32_t _flags) { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setUnderlineColor(_rgba); + bc.textBuffer->setStyle(_flags); } -void TextBufferManager::setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba ) -{ - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); - BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setStrikeThroughColor(_rgba); -} - -void TextBufferManager::setPenPosition(TextBufferHandle _handle, float _x, float _y) +void TextBufferManager::setTextColor(TextBufferHandle _handle, uint32_t _rgba) { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; - bc.textBuffer->setPenPosition(_x,_y); + bc.textBuffer->setTextColor(_rgba); } -void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char * _string) +void TextBufferManager::setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba) { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setBackgroundColor(_rgba); +} + +void TextBufferManager::setOverlineColor(TextBufferHandle _handle, uint32_t _rgba) +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setOverlineColor(_rgba); +} + +void TextBufferManager::setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba) +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setUnderlineColor(_rgba); +} + +void TextBufferManager::setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba) +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setStrikeThroughColor(_rgba); +} + +void TextBufferManager::setPenPosition(TextBufferHandle _handle, float _x, float _y) +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BufferCache& bc = m_textBuffers[_handle.idx]; + bc.textBuffer->setPenPosition(_x, _y); +} + +void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char* _string) +{ + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.textBuffer->appendText(_fontHandle, _string); } -void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t * _string) +void TextBufferManager::appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t* _string) { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.textBuffer->appendText(_fontHandle, _string); } void TextBufferManager::clearTextBuffer(TextBufferHandle _handle) { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; bc.textBuffer->clearTextBuffer(); } TextRectangle TextBufferManager::getRectangle(TextBufferHandle _handle) const { - BX_CHECK( bgfx::invalidHandle != _handle.idx, "Invalid handle used"); + BX_CHECK(bgfx::invalidHandle != _handle.idx, "Invalid handle used"); BufferCache& bc = m_textBuffers[_handle.idx]; return bc.textBuffer->getRectangle(); } diff --git a/examples/common/font/text_buffer_manager.h b/examples/common/font/text_buffer_manager.h index b9742aca..8e2af8db 100644 --- a/examples/common/font/text_buffer_manager.h +++ b/examples/common/font/text_buffer_manager.h @@ -9,27 +9,27 @@ #include "font_manager.h" BGFX_HANDLE(TextBufferHandle); - + /// type of vertex and index buffer to use with a TextBuffer enum BufferType { STATIC, - DYNAMIC , + DYNAMIC, TRANSIENT }; /// special style effect (can be combined) enum TextStyleFlags { - STYLE_NORMAL = 0, - STYLE_OVERLINE = 1, - STYLE_UNDERLINE = 1<<1, - STYLE_STRIKE_THROUGH = 1<<2, - STYLE_BACKGROUND = 1<<3, + STYLE_NORMAL = 0, + STYLE_OVERLINE = 1, + STYLE_UNDERLINE = 1 << 1, + STYLE_STRIKE_THROUGH = 1 << 2, + STYLE_BACKGROUND = 1 << 3, }; struct TextRectangle -{ +{ float width, height; }; @@ -37,63 +37,63 @@ class TextBuffer; class TextBufferManager { public: - TextBufferManager(FontManager* _fontManager); - ~TextBufferManager(); - - TextBufferHandle createTextBuffer(FontType _type, BufferType _bufferType); - void destroyTextBuffer(TextBufferHandle _handle); - void submitTextBuffer(TextBufferHandle _handle, uint8_t _id, int32_t _depth = 0); - void submitTextBufferMask(TextBufferHandle _handle, uint32_t _viewMask, int32_t _depth = 0); - - void setStyle(TextBufferHandle _handle, uint32_t _flags = STYLE_NORMAL); - void setTextColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - void setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); +TextBufferManager(FontManager* _fontManager); +~TextBufferManager(); - void setOverlineColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - void setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - void setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - - void setPenPosition(TextBufferHandle _handle, float _x, float _y); +TextBufferHandle createTextBuffer(FontType _type, BufferType _bufferType); +void destroyTextBuffer(TextBufferHandle _handle); +void submitTextBuffer(TextBufferHandle _handle, uint8_t _id, int32_t _depth = 0); +void submitTextBufferMask(TextBufferHandle _handle, uint32_t _viewMask, int32_t _depth = 0); - /// append an ASCII/utf-8 string to the buffer using current pen position and color - void appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char * _string); +void setStyle(TextBufferHandle _handle, uint32_t _flags = STYLE_NORMAL); +void setTextColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); +void setBackgroundColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - /// append a wide char unicode string to the buffer using current pen position and color - void appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t * _string); +void setOverlineColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); +void setUnderlineColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); +void setStrikeThroughColor(TextBufferHandle _handle, uint32_t _rgba = 0x000000FF); - /// Clear the text buffer and reset its state (pen/color) - void clearTextBuffer(TextBufferHandle _handle); +void setPenPosition(TextBufferHandle _handle, float _x, float _y); - TextRectangle getRectangle(TextBufferHandle _handle) const; - - /// return the size of the text - //Rectangle measureText(FontHandle fontHandle, const char * _string); - //Rectangle measureText(FontHandle fontHandle, const wchar_t * _string); +/// append an ASCII/utf-8 string to the buffer using current pen position and color +void appendText(TextBufferHandle _handle, FontHandle _fontHandle, const char* _string); + +/// append a wide char unicode string to the buffer using current pen position and color +void appendText(TextBufferHandle _handle, FontHandle _fontHandle, const wchar_t* _string); + +/// Clear the text buffer and reset its state (pen/color) +void clearTextBuffer(TextBufferHandle _handle); + +TextRectangle getRectangle(TextBufferHandle _handle) const; + +/// return the size of the text +//Rectangle measureText(FontHandle fontHandle, const char * _string); +//Rectangle measureText(FontHandle fontHandle, const wchar_t * _string); private: - - struct BufferCache - { - uint16_t indexBufferHandle; - uint16_t vertexBufferHandle; - TextBuffer* textBuffer; - BufferType bufferType; - FontType fontType; - }; - BufferCache* m_textBuffers; - bx::HandleAlloc m_textBufferHandles; - FontManager* m_fontManager; - bgfx::VertexDecl m_vertexDecl; - bgfx::UniformHandle u_texColor; - bgfx::UniformHandle u_inverse_gamma; - //shaders program - bgfx::ProgramHandle m_basicProgram; - bgfx::ProgramHandle m_distanceProgram; - bgfx::ProgramHandle m_distanceSubpixelProgram; +struct BufferCache +{ + uint16_t indexBufferHandle; + uint16_t vertexBufferHandle; + TextBuffer* textBuffer; + BufferType bufferType; + FontType fontType; +}; - float m_height; - float m_width; +BufferCache* m_textBuffers; +bx::HandleAlloc m_textBufferHandles; +FontManager* m_fontManager; +bgfx::VertexDecl m_vertexDecl; +bgfx::UniformHandle u_texColor; +bgfx::UniformHandle u_inverse_gamma; +//shaders program +bgfx::ProgramHandle m_basicProgram; +bgfx::ProgramHandle m_distanceProgram; +bgfx::ProgramHandle m_distanceSubpixelProgram; + +float m_height; +float m_width; }; #endif // __TEXT_BUFFER_MANAGER_H__