diff --git a/CMakeLists.txt b/CMakeLists.txt index c68536b314..4847d04707 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,6 +152,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/external ${CMAKE_CURRENT_SOURCE_DIR}/external/tinyxml2 ${CMAKE_CURRENT_SOURCE_DIR}/external/unzip + ${CMAKE_CURRENT_SOURCE_DIR}/external/edtaa3func ${CMAKE_CURRENT_SOURCE_DIR}/external/chipmunk/include/chipmunk ${CMAKE_CURRENT_SOURCE_DIR}/cocos/2d/platform/${PLATFORM_FOLDER} ${CMAKE_CURRENT_SOURCE_DIR}/external/jpeg/include/${PLATFORM_FOLDER} diff --git a/cocos/2d/Android.mk b/cocos/2d/Android.mk index 789cae2d91..2f2b304594 100644 --- a/cocos/2d/Android.mk +++ b/cocos/2d/Android.mk @@ -158,7 +158,8 @@ platform/CCThread.cpp \ ../physics/chipmunk/CCPhysicsWorldInfo_chipmunk.cpp \ ../../external/tinyxml2/tinyxml2.cpp \ ../../external/unzip/ioapi.cpp \ -../../external/unzip/unzip.cpp +../../external/unzip/unzip.cpp \ +../../external/edtaa3func/edtaa3func.cpp LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) \ @@ -177,7 +178,8 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH) \ $(LOCAL_PATH)/../base \ $(LOCAL_PATH)/../../external/tinyxml2 \ $(LOCAL_PATH)/../../external/unzip \ - $(LOCAL_PATH)/../../external/chipmunk/include/chipmunk + $(LOCAL_PATH)/../../external/chipmunk/include/chipmunk \ + $(LOCAL_PATH)/../../external/edtaa3func LOCAL_LDLIBS := -lGLESv2 \ diff --git a/cocos/2d/CCFont.cpp b/cocos/2d/CCFont.cpp index c48acdc0b5..471346a5ad 100644 --- a/cocos/2d/CCFont.cpp +++ b/cocos/2d/CCFont.cpp @@ -27,15 +27,21 @@ #include "CCFontFNT.h" #include "CCFontFreeType.h" +#include "edtaa3func.h" NS_CC_BEGIN +const int Font::DistanceMapSpread = 3; + const char * Font::_glyphASCII = "\"!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ "; const char * Font::_glyphNEHE = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "; -Font::Font() : _usedGlyphs(GlyphCollection::ASCII), _customGlyphs(nullptr) +Font::Font() : +_usedGlyphs(GlyphCollection::ASCII) +, _customGlyphs(nullptr) +,_distanceFieldEnabled(false) { } @@ -109,6 +115,164 @@ Font* Font::createWithFNT(const std::string& fntFilePath) return FontFNT::create(fntFilePath); } +unsigned char * Font::makeDistanceMap( unsigned char *img, unsigned int width, unsigned int height) +{ + unsigned int pixelAmount = (width + 2 * DistanceMapSpread) * (height + 2 * DistanceMapSpread); + + short * xdist = (short *) malloc( pixelAmount * sizeof(short) ); + short * ydist = (short *) malloc( pixelAmount * sizeof(short) ); + double * gx = (double *) calloc( pixelAmount, sizeof(double) ); + double * gy = (double *) calloc( pixelAmount, sizeof(double) ); + double * data = (double *) calloc( pixelAmount, sizeof(double) ); + double * outside = (double *) calloc( pixelAmount, sizeof(double) ); + double * inside = (double *) calloc( pixelAmount, sizeof(double) ); + unsigned int i,j; + + // Convert img into double (data) rescale image levels between 0 and 1 + unsigned int outWidth = width + 2 * DistanceMapSpread; + for (i = 0; i < width; ++i) + { + for (j = 0; j < height; ++j) + { + data[j * outWidth + DistanceMapSpread + i] = img[j * width + i] / 255.0; + } + } + + width += 2 * DistanceMapSpread; + height += 2 * DistanceMapSpread; + + // Transform background (outside contour, in areas of 0's) + computegradient( data, width, height, gx, gy); + edtaa3(data, gx, gy, width, height, xdist, ydist, outside); + for( i=0; i< pixelAmount; i++) + if( outside[i] < 0.0 ) + outside[i] = 0.0; + + // Transform foreground (inside contour, in areas of 1's) + for( i=0; i< pixelAmount; i++) + data[i] = 1 - data[i]; + computegradient( data, width, height, gx, gy); + edtaa3(data, gx, gy, width, height, xdist, ydist, inside); + for( i=0; i< pixelAmount; i++) + if( inside[i] < 0.0 ) + inside[i] = 0.0; + + // The bipolar distance field is now outside-inside + double dist; + /* Single channel 8-bit output (bad precision and range, but simple) */ + unsigned char *out = (unsigned char *) malloc( pixelAmount * sizeof(unsigned char) ); + for( i=0; i < pixelAmount; i++) + { + dist = outside[i] - inside[i]; + dist = 128.0 - dist*16; + if( dist < 0 ) dist = 0; + if( dist > 255 ) dist = 255; + out[i] = (unsigned char) dist; + } + /* Dual channel 16-bit output (more complicated, but good precision and range) */ + /*unsigned char *out = (unsigned char *) malloc( pixelAmount * 3 * sizeof(unsigned char) ); + for( i=0; i< pixelAmount; i++) + { + dist = outside[i] - inside[i]; + dist = 128.0 - dist*16; + if( dist < 0.0 ) dist = 0.0; + if( dist >= 256.0 ) dist = 255.999; + // R channel is a copy of the original grayscale image + out[3*i] = img[i]; + // G channel is fraction + out[3*i + 1] = (unsigned char) ( 256 - (dist - floor(dist)* 256.0 )); + // B channel is truncated integer part + out[3*i + 2] = (unsigned char)dist; + }*/ + + free( xdist ); + free( ydist ); + free( gx ); + free( gy ); + free( data ); + free( outside ); + free( inside ); + + return out; +} + +void Font::setDistanceFieldEnabled(bool distanceFieldEnabled) +{ + _distanceFieldEnabled = distanceFieldEnabled; +} + +bool Font::renderCharAt(unsigned short int charToRender, int posX, int posY, unsigned char *destMemory, int destSize) +{ + unsigned char *sourceBitmap = 0; + int sourceWidth = 0; + int sourceHeight = 0; + + sourceBitmap = getGlyphBitmap(charToRender, sourceWidth, sourceHeight); + + if (!sourceBitmap) + return false; + + if (_distanceFieldEnabled) + { + unsigned char * out = makeDistanceMap(sourceBitmap,sourceWidth,sourceHeight); + + int iX = posX; + int iY = posY; + + sourceWidth += 2 * DistanceMapSpread; + sourceHeight += 2 * DistanceMapSpread; + + for (int y = 0; y < sourceHeight; ++y) + { + int bitmap_y = y * sourceWidth; + + for (int x = 0; x < sourceWidth; ++x) + { + /* Dual channel 16-bit output (more complicated, but good precision and range) */ + /*int index = (iX + ( iY * destSize )) * 3; + int index2 = (bitmap_y + x)*3; + destMemory[index] = out[index2]; + destMemory[index + 1] = out[index2 + 1]; + destMemory[index + 2] = out[index2 + 2];*/ + + //Single channel 8-bit output + destMemory[iX + ( iY * destSize )] = out[bitmap_y + x]; + + iX += 1; + } + + iX = posX; + iY += 1; + } + free(out); + return true; + } + + int iX = posX; + int iY = posY; + + for (int y = 0; y < sourceHeight; ++y) + { + int bitmap_y = y * sourceWidth; + + for (int x = 0; x < sourceWidth; ++x) + { + unsigned char cTemp = sourceBitmap[bitmap_y + x]; + + // the final pixel + destMemory[(iX + ( iY * destSize ) )] = cTemp; + + iX += 1; + } + + iX = posX; + iY += 1; + } + + //everything good + return true; +} + unsigned short int * Font::getUTF16Text(const char *text, int &outNumLetters) const { unsigned short* utf16String = cc_utf8_to_utf16(text); diff --git a/cocos/2d/CCFont.h b/cocos/2d/CCFont.h index cf3084011d..dfd5dd7ecc 100644 --- a/cocos/2d/CCFont.h +++ b/cocos/2d/CCFont.h @@ -40,11 +40,16 @@ class FontAtlas; class CC_DLL Font : public Object { public: - + static const int DistanceMapSpread; // create the font static Font* createWithTTF(const std::string& fntName, int fontSize, GlyphCollection glyphs, const char *customGlyphs); static Font* createWithFNT(const std::string& fntFilePath); + static unsigned char * makeDistanceMap(unsigned char *img, unsigned int width, unsigned int height); + void setDistanceFieldEnabled(bool distanceFieldEnabled); + bool isDistanceFieldEnabled() const { return _distanceFieldEnabled;} + bool renderCharAt(unsigned short int charToRender, int posX, int posY, unsigned char *destMemory, int destSize); + virtual FontAtlas *createFontAtlas() = 0; virtual Size* getAdvancesForTextUTF16(unsigned short *text, int &outNumLetters) const = 0; @@ -76,7 +81,8 @@ protected: char * _customGlyphs; static const char * _glyphASCII; static const char * _glyphNEHE; - + bool _distanceFieldEnabled; + }; NS_CC_END diff --git a/cocos/2d/CCFontAtlas.cpp b/cocos/2d/CCFontAtlas.cpp index e0b97aa286..a4dcb8fd19 100644 --- a/cocos/2d/CCFontAtlas.cpp +++ b/cocos/2d/CCFontAtlas.cpp @@ -21,12 +21,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ - #include "cocos2d.h" #include "CCFontAtlas.h" #include "CCFont.h" #include "CCFontFreeType.h" +#define PAGE_WIDTH 1024 +#define PAGE_HEIGHT 1024 + NS_CC_BEGIN FontAtlas::FontAtlas(Font &theFont) : @@ -34,7 +36,8 @@ _font(&theFont), _currentPageData(nullptr) { _font->retain(); - + _makeDistanceMap = _font->isDistanceFieldEnabled(); + FontFreeType* fontTTf = dynamic_cast(_font); if (fontTTf && fontTTf->isDynamicGlyphCollection()) { @@ -45,7 +48,17 @@ _currentPageData(nullptr) _currentPageOrigX = 0; _currentPageOrigY = 0; _letterPadding = 5; - _currentPageDataSize = (1024 * 1024 * 4); + + if(_makeDistanceMap) + { + _commonLineHeight += 2 * Font::DistanceMapSpread; + _letterPadding += 2 * Font::DistanceMapSpread; + _currentPageDataSize = (PAGE_WIDTH * PAGE_HEIGHT * 1); + } + else + { + _currentPageDataSize = (PAGE_WIDTH * PAGE_HEIGHT * 1); + } _currentPageData = new unsigned char[_currentPageDataSize]; memset(_currentPageData, 0, _currentPageDataSize); @@ -97,16 +110,20 @@ bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String) FontFreeType* fontTTf = (FontFreeType*)_font; - std::vector fontDefs; + std::unordered_map fontDefs; int length = cc_wcslen(utf16String); //find out new letter for (int i = 0; i < length; ++i) { auto outIterator = _fontLetterDefinitions.find(utf16String[i]); - + if (outIterator == _fontLetterDefinitions.end()) - { + { + auto outIterator2 = fontDefs.find(utf16String[i]); + if(outIterator2 != fontDefs.end()) + continue; + Rect tempRect; FontLetterDefinition tempDef; @@ -135,28 +152,30 @@ bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String) tempDef.offsetY = tempRect.origin.y; tempDef.commonLineHeight = _currentPageLineHeight; - } - fontDefs.push_back(tempDef); + } + fontDefs[utf16String[i]] = tempDef; } } + Size _pageContentSize = Size(PAGE_WIDTH,PAGE_HEIGHT); float scaleFactor = CC_CONTENT_SCALE_FACTOR(); - size_t newLetterCount = fontDefs.size(); float glyphWidth; - for (int i = 0; i < newLetterCount; ++i) + Texture2D::PixelFormat pixelFormat = _makeDistanceMap ? Texture2D::PixelFormat::A8 : Texture2D::PixelFormat::A8; + + for(auto it = fontDefs.begin(); it != fontDefs.end(); it++) { - if (fontDefs[i].validDefinition) + if(it->second.validDefinition) { _currentPageOrigX += _letterPadding; - glyphWidth = fontDefs[i].width - _letterPadding; + glyphWidth = it->second.width - _letterPadding; - if (_currentPageOrigX + glyphWidth > 1024) + if (_currentPageOrigX + glyphWidth > PAGE_WIDTH) { _currentPageOrigY += _currentPageLineHeight; - if(_currentPageOrigY >= 1024) + _currentPageOrigX = 0; + if(_currentPageOrigY >= PAGE_HEIGHT) { - _atlasTextures[_currentPage]->initWithData(_currentPageData, _currentPageDataSize, Texture2D::PixelFormat::RGBA8888, 1024, 1024, Size(1024, 1024) ); - _currentPageOrigX = 0; + _atlasTextures[_currentPage]->initWithData(_currentPageData, _currentPageDataSize, pixelFormat, PAGE_WIDTH, PAGE_HEIGHT, _pageContentSize ); _currentPageOrigY = 0; delete []_currentPageData; @@ -170,63 +189,25 @@ bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String) tex->release(); } } - renderCharAt(fontDefs[i].letteCharUTF16,_currentPageOrigX,_currentPageOrigY,_currentPageData,1024); + _font->renderCharAt(it->second.letteCharUTF16,_currentPageOrigX,_currentPageOrigY,_currentPageData,PAGE_WIDTH); - fontDefs[i].U = _currentPageOrigX - 1; - fontDefs[i].V = _currentPageOrigY; - fontDefs[i].textureID = _currentPage; + it->second.U = _currentPageOrigX - 1; + it->second.V = _currentPageOrigY; + it->second.textureID = _currentPage; // take from pixels to points - fontDefs[i].width = fontDefs[i].width / scaleFactor; - fontDefs[i].height = fontDefs[i].height / scaleFactor; - fontDefs[i].U = fontDefs[i].U / scaleFactor; - fontDefs[i].V = fontDefs[i].V / scaleFactor; + it->second.width = it->second.width / scaleFactor; + it->second.height = it->second.height / scaleFactor; + it->second.U = it->second.U / scaleFactor; + it->second.V = it->second.V / scaleFactor; } else glyphWidth = 0; - this->addLetterDefinition(fontDefs[i]); + _fontLetterDefinitions[it->second.letteCharUTF16] = it->second; _currentPageOrigX += glyphWidth; } - if(newLetterCount > 0) - _atlasTextures[_currentPage]->initWithData(_currentPageData, _currentPageDataSize, Texture2D::PixelFormat::RGBA8888, 1024, 1024, Size(1024, 1024) ); - return true; -} - -bool FontAtlas::renderCharAt(unsigned short int charToRender, int posX, int posY, unsigned char *destMemory, int destSize) -{ - unsigned char *sourceBitmap = 0; - int sourceWidth = 0; - int sourceHeight = 0; - - // get the glyph's bitmap - sourceBitmap = _font->getGlyphBitmap(charToRender, sourceWidth, sourceHeight); - - if (!sourceBitmap) - return false; - - int iX = posX; - int iY = posY; - - for (int y = 0; y < sourceHeight; ++y) - { - int bitmap_y = y * sourceWidth; - - for (int x = 0; x < sourceWidth; ++x) - { - unsigned char cTemp = sourceBitmap[bitmap_y + x]; - - // the final pixel - int iTemp = cTemp << 24 | cTemp << 16 | cTemp << 8 | cTemp; - *(int*) &destMemory[(iX + ( iY * destSize ) ) * 4] = iTemp; - - iX += 1; - } - - iX = posX; - iY += 1; - } - - //everything good + if(fontDefs.size() > 0) + _atlasTextures[_currentPage]->initWithData(_currentPageData, _currentPageDataSize, pixelFormat, PAGE_WIDTH, PAGE_HEIGHT, _pageContentSize ); return true; } @@ -248,6 +229,8 @@ float FontAtlas::getCommonLineHeight() const void FontAtlas::setCommonLineHeight(float newHeight) { + if(_makeDistanceMap) + newHeight += 2 * Font::DistanceMapSpread; _commonLineHeight = newHeight; } diff --git a/cocos/2d/CCFontAtlas.h b/cocos/2d/CCFontAtlas.h index 317a06561d..044b0cdb5e 100644 --- a/cocos/2d/CCFontAtlas.h +++ b/cocos/2d/CCFontAtlas.h @@ -73,7 +73,6 @@ public: const Font* getFont() const; private: - bool renderCharAt(unsigned short int charToRender, int posX, int posY, unsigned char *destMemory, int destSize); void relaseTextures(); std::unordered_map _atlasTextures; @@ -89,6 +88,7 @@ private: float _currentPageOrigY; float _currentPageLineHeight; float _letterPadding; + bool _makeDistanceMap; }; diff --git a/cocos/2d/CCFontAtlasCache.cpp b/cocos/2d/CCFontAtlasCache.cpp index 00fc1e2a1f..197aacde7f 100644 --- a/cocos/2d/CCFontAtlasCache.cpp +++ b/cocos/2d/CCFontAtlasCache.cpp @@ -30,14 +30,14 @@ NS_CC_BEGIN std::unordered_map FontAtlasCache::_atlasMap; -FontAtlas * FontAtlasCache::getFontAtlasTTF(const char *fontFileName, int size, GlyphCollection glyphs, const char *customGlyphs) +FontAtlas * FontAtlasCache::getFontAtlasTTF(const char *fontFileName, int size, GlyphCollection glyphs, const char *customGlyphs, bool useDistanceField) { - std::string atlasName = generateFontName(fontFileName, size, glyphs); + std::string atlasName = generateFontName(fontFileName, size, glyphs, useDistanceField); FontAtlas *tempAtlas = _atlasMap[atlasName]; if ( !tempAtlas ) { - tempAtlas = FontAtlasFactory::createAtlasFromTTF(fontFileName, size, glyphs, customGlyphs); + tempAtlas = FontAtlasFactory::createAtlasFromTTF(fontFileName, size, glyphs, customGlyphs, useDistanceField); if (tempAtlas) _atlasMap[atlasName] = tempAtlas; } @@ -51,7 +51,7 @@ FontAtlas * FontAtlasCache::getFontAtlasTTF(const char *fontFileName, int size, FontAtlas * FontAtlasCache::getFontAtlasFNT(const char *fontFileName) { - std::string atlasName = generateFontName(fontFileName, 0, GlyphCollection::CUSTOM); + std::string atlasName = generateFontName(fontFileName, 0, GlyphCollection::CUSTOM,false); FontAtlas *tempAtlas = _atlasMap[atlasName]; if ( !tempAtlas ) @@ -68,7 +68,7 @@ FontAtlas * FontAtlasCache::getFontAtlasFNT(const char *fontFileName) return tempAtlas; } -std::string FontAtlasCache::generateFontName(const char *fontFileName, int size, GlyphCollection theGlyphs) +std::string FontAtlasCache::generateFontName(const char *fontFileName, int size, GlyphCollection theGlyphs, bool useDistanceField) { std::string tempName(fontFileName); @@ -93,7 +93,8 @@ std::string FontAtlasCache::generateFontName(const char *fontFileName, int size, default: break; } - + if(useDistanceField) + tempName.append("df"); // std::to_string is not supported on android, using std::stringstream instead. std::stringstream ss; ss << size; diff --git a/cocos/2d/CCFontAtlasCache.h b/cocos/2d/CCFontAtlasCache.h index f5f8ca7df4..b64d9ea6f3 100644 --- a/cocos/2d/CCFontAtlasCache.h +++ b/cocos/2d/CCFontAtlasCache.h @@ -38,14 +38,14 @@ class CC_DLL FontAtlasCache public: - static FontAtlas * getFontAtlasTTF(const char *fontFileName, int size, GlyphCollection glyphs, const char *customGlyphs = 0); + static FontAtlas * getFontAtlasTTF(const char *fontFileName, int size, GlyphCollection glyphs, const char *customGlyphs = 0, bool useDistanceField = false); static FontAtlas * getFontAtlasFNT(const char *fontFileName); static bool releaseFontAtlas(FontAtlas *atlas); private: - static std::string generateFontName(const char *fontFileName, int size, GlyphCollection theGlyphs); + static std::string generateFontName(const char *fontFileName, int size, GlyphCollection theGlyphs, bool useDistanceField); static std::unordered_map _atlasMap; }; diff --git a/cocos/2d/CCFontAtlasFactory.cpp b/cocos/2d/CCFontAtlasFactory.cpp index b1cd69172f..5c06b2ba9c 100644 --- a/cocos/2d/CCFontAtlasFactory.cpp +++ b/cocos/2d/CCFontAtlasFactory.cpp @@ -30,14 +30,19 @@ NS_CC_BEGIN -FontAtlas * FontAtlasFactory::createAtlasFromTTF(const char* fntFilePath, int fontSize, GlyphCollection glyphs, const char *customGlyphs) +FontAtlas * FontAtlasFactory::createAtlasFromTTF(const char* fntFilePath, int fontSize, GlyphCollection glyphs, const char *customGlyphs, bool useDistanceField) { Font *font = Font::createWithTTF(fntFilePath, fontSize, glyphs, customGlyphs); if (font) + { + font->setDistanceFieldEnabled(useDistanceField); return font->createFontAtlas(); + } else + { return nullptr; + } } FontAtlas * FontAtlasFactory::createAtlasFromFNT(const char* fntFilePath) @@ -46,8 +51,7 @@ FontAtlas * FontAtlasFactory::createAtlasFromFNT(const char* fntFilePath) if(font) { - FontAtlas * atlas = font->createFontAtlas(); - return atlas; + return font->createFontAtlas(); } else { diff --git a/cocos/2d/CCFontAtlasFactory.h b/cocos/2d/CCFontAtlasFactory.h index f1b785f4c1..d1f3604ad1 100644 --- a/cocos/2d/CCFontAtlasFactory.h +++ b/cocos/2d/CCFontAtlasFactory.h @@ -36,7 +36,7 @@ class CC_DLL FontAtlasFactory public: - static FontAtlas * createAtlasFromTTF(const char* fntFilePath, int fontSize, GlyphCollection glyphs, const char *customGlyphs = 0); + static FontAtlas * createAtlasFromTTF(const char* fntFilePath, int fontSize, GlyphCollection glyphs, const char *customGlyphs = 0, bool useDistanceField = false); static FontAtlas * createAtlasFromFNT(const char* fntFilePath); private: diff --git a/cocos/2d/CCFontFreeType.cpp b/cocos/2d/CCFontFreeType.cpp index 08e8d0304d..2f9de7861a 100644 --- a/cocos/2d/CCFontFreeType.cpp +++ b/cocos/2d/CCFontFreeType.cpp @@ -93,6 +93,8 @@ _letterPadding(5), _ttfData(nullptr), _dynamicGlyphCollection(dynamicGlyphCollection) { + if(_distanceFieldEnabled) + _letterPadding += 2 * DistanceMapSpread; } bool FontFreeType::createFontObject(const std::string &fontName, int fontSize) @@ -354,23 +356,21 @@ int FontFreeType::getFontMaxHeight() const return (static_cast(_fontRef->size->metrics.height >> 6)); } -unsigned char * FontFreeType::getGlyphBitmap(unsigned short theChar, int &outWidth, int &outHeight) const +unsigned char * FontFreeType::getGlyphBitmap(unsigned short theChar, int &outWidth, int &outHeight) const { if (!_fontRef) return 0; - // get the ID to the char we need - int glyphIndex = FT_Get_Char_Index(_fontRef, theChar); - - if (!glyphIndex) - return 0; - - // load glyph infos - if (FT_Load_Glyph(_fontRef, glyphIndex, FT_LOAD_DEFAULT)) - return 0; - - if (FT_Render_Glyph( _fontRef->glyph, FT_RENDER_MODE_NORMAL )) - return 0; + if (_distanceFieldEnabled) + { + if (FT_Load_Char(_fontRef,theChar,FT_LOAD_RENDER | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT)) + return 0; + } + else + { + if (FT_Load_Char(_fontRef,theChar,FT_LOAD_RENDER)) + return 0; + } outWidth = _fontRef->glyph->bitmap.width; outHeight = _fontRef->glyph->bitmap.rows; diff --git a/cocos/2d/CCFontFreeType.h b/cocos/2d/CCFontFreeType.h index a305b2253e..948ce9a601 100644 --- a/cocos/2d/CCFontFreeType.h +++ b/cocos/2d/CCFontFreeType.h @@ -71,7 +71,7 @@ private: static FT_Library _FTlibrary; static bool _FTInitialized; FT_Face _fontRef; - const int _letterPadding; + int _letterPadding; std::string _fontName; unsigned char* _ttfData; bool _dynamicGlyphCollection; diff --git a/cocos/2d/CCGLProgram.cpp b/cocos/2d/CCGLProgram.cpp index 44d180877b..09f7647902 100644 --- a/cocos/2d/CCGLProgram.cpp +++ b/cocos/2d/CCGLProgram.cpp @@ -54,6 +54,12 @@ const char* GLProgram::SHADER_NAME_POSITION_TEXTURE_A8_COLOR = "ShaderPositionTe const char* GLProgram::SHADER_NAME_POSITION_U_COLOR = "ShaderPosition_uColor"; const char* GLProgram::SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR = "ShaderPositionLengthTextureColor"; +const char* GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_NORMAL = "ShaderLabelNormol"; +const char* GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_GLOW = "ShaderLabelGlow"; +const char* GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_OUTLINE = "ShaderLabelOutline"; +const char* GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_SHADOW = "ShaderLabelShadow"; + + // uniform names const char* GLProgram::UNIFORM_NAME_P_MATRIX = "CC_PMatrix"; const char* GLProgram::UNIFORM_NAME_MV_MATRIX = "CC_MVMatrix"; diff --git a/cocos/2d/CCGLProgram.h b/cocos/2d/CCGLProgram.h index a46fa4eaa5..1691ef980d 100644 --- a/cocos/2d/CCGLProgram.h +++ b/cocos/2d/CCGLProgram.h @@ -85,6 +85,11 @@ public: static const char* SHADER_NAME_POSITION_TEXTURE_A8_COLOR; static const char* SHADER_NAME_POSITION_U_COLOR; static const char* SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR; + + static const char* SHADER_NAME_LABEL_DISTANCEFIELD_NORMAL; + static const char* SHADER_NAME_LABEL_DISTANCEFIELD_GLOW; + static const char* SHADER_NAME_LABEL_DISTANCEFIELD_OUTLINE; + static const char* SHADER_NAME_LABEL_DISTANCEFIELD_SHADOW; // uniform names static const char* UNIFORM_NAME_P_MATRIX; diff --git a/cocos/2d/CCLabel.cpp b/cocos/2d/CCLabel.cpp index ca94d2b4f9..ba6847e7c4 100644 --- a/cocos/2d/CCLabel.cpp +++ b/cocos/2d/CCLabel.cpp @@ -27,20 +27,28 @@ #include "CCFontAtlasCache.h" #include "CCLabelTextFormatter.h" +#define DISTANCEFIELD_ATLAS_FONTSIZE 50 + NS_CC_BEGIN -Label* Label::createWithTTF(const std::string& label, const std::string& fontFilePath, int fontSize, int lineSize, TextHAlignment alignment, GlyphCollection glyphs, const char *customGlyphs ) +Label* Label::createWithTTF(const std::string& label, const std::string& fontFilePath, int fontSize, int lineSize, TextHAlignment alignment, GlyphCollection glyphs, const char *customGlyphs, bool useDistanceField) { - FontAtlas *tmpAtlas = FontAtlasCache::getFontAtlasTTF(fontFilePath.c_str(), fontSize, glyphs, customGlyphs); + FontAtlas *tmpAtlas = nullptr; + if(useDistanceField) + tmpAtlas = FontAtlasCache::getFontAtlasTTF(fontFilePath.c_str(), DISTANCEFIELD_ATLAS_FONTSIZE, glyphs, customGlyphs,true); + else + tmpAtlas = FontAtlasCache::getFontAtlasTTF(fontFilePath.c_str(), fontSize, glyphs, customGlyphs,false); if (!tmpAtlas) return nullptr; // create the actual label - Label* templabel = Label::createWithAtlas(tmpAtlas, alignment, lineSize); + Label* templabel = Label::createWithAtlas(tmpAtlas, alignment, lineSize, useDistanceField,true); if (templabel) { + if(useDistanceField) + templabel->setFontSize(fontSize); templabel->setText(label, lineSize, alignment, false); return templabel; } @@ -71,9 +79,9 @@ Label* Label::createWithBMFont(const std::string& label, const std::string& bmfo return 0; } -Label* Label::createWithAtlas(FontAtlas *atlas, TextHAlignment alignment, int lineSize) +Label* Label::createWithAtlas(FontAtlas *atlas, TextHAlignment alignment, int lineSize, bool useDistanceField,bool useA8Shader) { - Label *ret = new Label(atlas, alignment); + Label *ret = new Label(atlas, alignment, useDistanceField,useA8Shader); if (!ret) return 0; @@ -92,9 +100,10 @@ Label* Label::createWithAtlas(FontAtlas *atlas, TextHAlignment alignment, int li return ret; } -Label::Label(FontAtlas *atlas, TextHAlignment alignment) +Label::Label(FontAtlas *atlas, TextHAlignment alignment, bool useDistanceField,bool useA8Shader) : _reusedLetter(nullptr) , _lineBreakWithoutSpaces(false) +,_multilineEnable(true) , _alignment(alignment) , _currentUTF16String(0) , _originalUTF16String(0) @@ -107,6 +116,8 @@ Label::Label(FontAtlas *atlas, TextHAlignment alignment) , _displayedOpacity(255) , _realOpacity(255) , _isOpacityModifyRGB(true) +,_useDistanceField(useDistanceField) +,_useA8Shader(useA8Shader) { } @@ -124,19 +135,31 @@ Label::~Label() bool Label::init() { + bool ret = true; if(_fontAtlas) { _reusedLetter = Sprite::createWithTexture(&_fontAtlas->getTexture(0)); _reusedLetter->setOpacityModifyRGB(_isOpacityModifyRGB); + ret = SpriteBatchNode::initWithTexture(&_fontAtlas->getTexture(0), 30); _reusedLetter->retain(); - return SpriteBatchNode::initWithTexture(&_fontAtlas->getTexture(0), 30); } + if (_useDistanceField) + setLabelEffect(LabelEffect::NORMAL,Color3B::BLACK); + else if(_useA8Shader) + setShaderProgram(ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_A8_COLOR)); - return true; + return ret; } void Label::setString(const std::string &stringToRender) { + _multilineEnable = true; + setText(stringToRender, _width, TextHAlignment::CENTER, false); +} + +void Label::setString(const std::string &stringToRender,bool multilineEnable) +{ + _multilineEnable = multilineEnable; setText(stringToRender, _width, TextHAlignment::CENTER, false); } @@ -221,20 +244,53 @@ void Label::setLineBreakWithoutSpace(bool breakWithoutSpace) void Label::setScale(float scale) { + if (_useDistanceField) + { + scale *= 1.0f * _fontSize / DISTANCEFIELD_ATLAS_FONTSIZE; + } Node::setScale(scale); - alignText(); } void Label::setScaleX(float scaleX) { + if (_useDistanceField) + { + scaleX *= 1.0f * _fontSize / DISTANCEFIELD_ATLAS_FONTSIZE; + } Node::setScaleX(scaleX); - alignText(); } void Label::setScaleY(float scaleY) { + if (_useDistanceField) + { + scaleY *= 1.0f * _fontSize / DISTANCEFIELD_ATLAS_FONTSIZE; + } Node::setScaleY(scaleY); - alignText(); +} + +float Label::getScaleY() const +{ + if (_useDistanceField) + { + return _scaleY / (1.0f * _fontSize / DISTANCEFIELD_ATLAS_FONTSIZE); + } + else + { + return _scaleY; + } +} + +float Label::getScaleX() const +{ + if (_useDistanceField) + { + return _scaleX / (1.0f * _fontSize / DISTANCEFIELD_ATLAS_FONTSIZE); + } + else + { + return _scaleX; + } } void Label::alignText() @@ -243,14 +299,13 @@ void Label::alignText() _textureAtlas->removeAllQuads(); _fontAtlas->prepareLetterDefinitions(_currentUTF16String); LabelTextFormatter::createStringSprites(this); - if( LabelTextFormatter::multilineText(this) ) + if(_multilineEnable && LabelTextFormatter::multilineText(this) ) LabelTextFormatter::createStringSprites(this); LabelTextFormatter::alignText(this); int strLen = cc_wcslen(_currentUTF16String); - - _children.forEach([this, &strLen](Node* child){ + _children.forEach([this,&strLen](Node* child){ if (child) { int tag = child->getTag(); @@ -415,6 +470,69 @@ void Label::addChild(Node * child, int zOrder/* =0 */, int tag/* =0 */) CCASSERT(0, "addChild: is not supported on Label."); } +void Label::setLabelEffect(LabelEffect effect,const Color3B& effectColor) +{ + if(_useDistanceField == false) + return; + + _currLabelEffect = effect; + _effectColor = effectColor; + + switch (_currLabelEffect) + { + case cocos2d::LabelEffect::NORMAL: + setShaderProgram(ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_NORMAL)); + break; + case cocos2d::LabelEffect::OUTLINE: + setShaderProgram(ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_OUTLINE)); + break; + case cocos2d::LabelEffect::SHADOW: + setShaderProgram(ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_SHADOW)); + break; + case cocos2d::LabelEffect::GLOW: + setShaderProgram(ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_GLOW)); + break; + default: + return; + } + + _uniformEffectColor = glGetUniformLocation(_shaderProgram->getProgram(), "v_effectColor"); +} + +void Label::setFontSize(int fontSize) +{ + _fontSize = fontSize; + Node::setScale(1.0f*_fontSize/DISTANCEFIELD_ATLAS_FONTSIZE); +} + +void Label::draw() +{ + CC_PROFILER_START("CCSpriteBatchNode - draw"); + + // Optimization: Fast Dispatch + if( _textureAtlas->getTotalQuads() == 0 ) + { + return; + } + + CC_NODE_DRAW_SETUP(); + + if (_useDistanceField && _currLabelEffect != LabelEffect::NORMAL) + { + _shaderProgram->setUniformLocationWith3f(_uniformEffectColor, _effectColor.r/255.0f,_effectColor.g/255.0f,_effectColor.b/255.0f); + } + + _children.forEach([](Node* child){ + child->updateTransform(); + }); + + GL::blendFunc( _blendFunc.src, _blendFunc.dst ); + + _textureAtlas->drawQuads(); + + CC_PROFILER_STOP("CCSpriteBatchNode - draw"); +} + ///// PROTOCOL STUFF Sprite * Label::getLetter(int ID) @@ -434,7 +552,7 @@ Sprite * Label::getLetter(int ID) uvRect.origin.x = _lettersInfo[ID].def.U; uvRect.origin.y = _lettersInfo[ID].def.V; - sp = Sprite::createWithTexture(&_fontAtlas->getTexture(_lettersInfo[ID].def.textureID), uvRect); + sp = Sprite::createWithTexture(&_fontAtlas->getTexture(_lettersInfo[ID].def.textureID),uvRect); sp->setBatchNode(this); sp->setAnchorPoint(Point(_lettersInfo[ID].def.anchorX, _lettersInfo[ID].def.anchorY)); sp->setPosition(_lettersInfo[ID].position); @@ -636,7 +754,7 @@ void Label::updateDisplayedOpacity(GLubyte parentOpacity) _children.forEach([this](Node* child){ Sprite *item = static_cast( child ); - item->updateDisplayedOpacity(_displayedOpacity); + item->updateDisplayedOpacity(_displayedOpacity); }); V3F_C4B_T2F_Quad *quads = _textureAtlas->getQuads(); @@ -702,7 +820,7 @@ void Label::updateDisplayedColor(const Color3B& parentColor) _children.forEach([this](Node* child){ Sprite *item = static_cast( child ); - item->updateDisplayedColor(_displayedColor); + item->updateDisplayedColor(_displayedColor); }); V3F_C4B_T2F_Quad *quads = _textureAtlas->getQuads(); diff --git a/cocos/2d/CCLabel.h b/cocos/2d/CCLabel.h index 9e3facffa4..5a742c71d9 100644 --- a/cocos/2d/CCLabel.h +++ b/cocos/2d/CCLabel.h @@ -40,6 +40,14 @@ enum class GlyphCollection { CUSTOM }; +enum class LabelEffect { + + NORMAL, + OUTLINE, + SHADOW, + GLOW +}; + //fwd struct FontLetterDefinition; class FontAtlas; @@ -51,19 +59,24 @@ class CC_DLL Label : public SpriteBatchNode, public LabelProtocol, public RGBAPr public: // static create - static Label* createWithTTF(const std::string& label, const std::string& fontFilePath, int fontSize, int lineSize = 0, TextHAlignment alignment = TextHAlignment::CENTER, GlyphCollection glyphs = GlyphCollection::NEHE, const char *customGlyphs = 0); + static Label* createWithTTF(const std::string& label, const std::string& fontFilePath, int fontSize, int lineSize = 0, TextHAlignment alignment = TextHAlignment::CENTER, GlyphCollection glyphs = GlyphCollection::NEHE, const char *customGlyphs = 0, bool useDistanceField = false); static Label* createWithBMFont(const std::string& label, const std::string& bmfontFilePath, TextHAlignment alignment = TextHAlignment::CENTER, int lineSize = 0); bool setText(const std::string& stringToRender, float lineWidth, TextHAlignment alignment = TextHAlignment::LEFT, bool lineBreakWithoutSpaces = false); + + void setLabelEffect(LabelEffect effect,const Color3B& effectColor); virtual void setString(const std::string &stringToRender) override; + void setString(const std::string &stringToRender,bool multilineEnable); virtual void setAlignment(TextHAlignment alignment); virtual void setWidth(float width); virtual void setLineBreakWithoutSpace(bool breakWithoutSpace); virtual void setScale(float scale) override; virtual void setScaleX(float scaleX) override; virtual void setScaleY(float scaleY) override; + virtual float getScaleX() const; + virtual float getScaleY() const; // RGBAProtocol virtual bool isOpacityModifyRGB() const override; @@ -117,19 +130,22 @@ public: void addChild(Node * child, int zOrder=0, int tag=0) override; virtual std::string getDescription() const override; + virtual void draw(void) override; private: /** * @js NA */ - Label(FontAtlas *atlas, TextHAlignment alignment); + Label(FontAtlas *atlas, TextHAlignment alignment, bool useDistanceField = false,bool useA8Shader = false); /** * @js NA * @lua NA */ ~Label(); - static Label* createWithAtlas(FontAtlas *atlas, TextHAlignment alignment = TextHAlignment::LEFT, int lineSize = 0); + static Label* createWithAtlas(FontAtlas *atlas, TextHAlignment alignment = TextHAlignment::LEFT, int lineSize = 0, bool useDistanceField = false,bool useA8Shader = false); + + void setFontSize(int fontSize); bool init(); @@ -147,6 +163,7 @@ private: Sprite *_reusedLetter; std::vector _lettersInfo; + bool _multilineEnable; float _commonLineHeight; bool _lineBreakWithoutSpaces; float _width; @@ -162,7 +179,15 @@ private: unsigned char _displayedOpacity; unsigned char _realOpacity; bool _isOpacityModifyRGB; - + + bool _useDistanceField; + bool _useA8Shader; + int _fontSize; + + LabelEffect _currLabelEffect; + Color3B _effectColor; + + GLuint _uniformEffectColor; }; diff --git a/cocos/2d/CCLabelTextFormatter.cpp b/cocos/2d/CCLabelTextFormatter.cpp index ca1fa7ac04..1094fda4b9 100644 --- a/cocos/2d/CCLabelTextFormatter.cpp +++ b/cocos/2d/CCLabelTextFormatter.cpp @@ -58,7 +58,7 @@ bool LabelTextFormatter::multilineText(LabelTextFormatProtocol *theLabel) std::vector *leterInfo = theLabel->getLettersInfo(); int tIndex = 0; - for (int j = 0; j < strLen; j++) + for (int j = 0; j+skip < strLen; j++) { LetterInfo* info = &leterInfo->at(j+skip); diff --git a/cocos/2d/CCShaderCache.cpp b/cocos/2d/CCShaderCache.cpp index e875ecaadd..6ede30a084 100644 --- a/cocos/2d/CCShaderCache.cpp +++ b/cocos/2d/CCShaderCache.cpp @@ -40,7 +40,10 @@ enum { kShaderType_PositionTextureA8Color, kShaderType_Position_uColor, kShaderType_PositionLengthTexureColor, - + kShaderType_LabelDistanceFieldNormal, + kShaderType_LabelDistanceFieldGlow, + kShaderType_LabelDistanceFieldOutline, + kShaderType_LabelDistanceFieldShadow, kShaderType_MAX, }; @@ -149,6 +152,22 @@ void ShaderCache::loadDefaultShaders() p = new GLProgram(); loadDefaultShader(p, kShaderType_PositionLengthTexureColor); _programs.insert( std::make_pair(GLProgram::SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR, p) ); + + p = new GLProgram(); + loadDefaultShader(p, kShaderType_LabelDistanceFieldNormal); + _programs.insert( std::make_pair(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_NORMAL, p) ); + + p = new GLProgram(); + loadDefaultShader(p, kShaderType_LabelDistanceFieldGlow); + _programs.insert( std::make_pair(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_GLOW, p) ); + + p = new GLProgram(); + loadDefaultShader(p, kShaderType_LabelDistanceFieldOutline); + _programs.insert( std::make_pair(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_OUTLINE, p) ); + + p = new GLProgram(); + loadDefaultShader(p, kShaderType_LabelDistanceFieldShadow); + _programs.insert( std::make_pair(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_SHADOW, p) ); } void ShaderCache::reloadDefaultShaders() @@ -206,6 +225,22 @@ void ShaderCache::reloadDefaultShaders() p = getProgram(GLProgram::SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR); p->reset(); loadDefaultShader(p, kShaderType_PositionLengthTexureColor); + + p = getProgram(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_NORMAL); + p->reset(); + loadDefaultShader(p, kShaderType_LabelDistanceFieldNormal); + + p = getProgram(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_GLOW); + p->reset(); + loadDefaultShader(p, kShaderType_LabelDistanceFieldGlow); + + p = getProgram(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_OUTLINE); + p->reset(); + loadDefaultShader(p, kShaderType_LabelDistanceFieldOutline); + + p = getProgram(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_SHADOW); + p->reset(); + loadDefaultShader(p, kShaderType_LabelDistanceFieldShadow); } void ShaderCache::loadDefaultShader(GLProgram *p, int type) @@ -269,6 +304,38 @@ void ShaderCache::loadDefaultShader(GLProgram *p, int type) p->addAttribute(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS); p->addAttribute(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR); + break; + case kShaderType_LabelDistanceFieldNormal: + p->initWithVertexShaderByteArray(ccLabelDistanceFieldNormal_vert, ccLabelDistanceFieldNormal_frag); + + p->addAttribute(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION); + p->addAttribute(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR); + p->addAttribute(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS); + + break; + case kShaderType_LabelDistanceFieldGlow: + p->initWithVertexShaderByteArray(ccLabelDistanceFieldGlow_vert, ccLabelDistanceFieldGlow_frag); + + p->addAttribute(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION); + p->addAttribute(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR); + p->addAttribute(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS); + + break; + case kShaderType_LabelDistanceFieldOutline: + p->initWithVertexShaderByteArray(ccLabelDistanceFieldOutline_vert, ccLabelDistanceFieldOutline_frag); + + p->addAttribute(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION); + p->addAttribute(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR); + p->addAttribute(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS); + + break; + case kShaderType_LabelDistanceFieldShadow: + p->initWithVertexShaderByteArray(ccLabelDistanceFieldShadow_vert, ccLabelDistanceFieldShadow_frag); + + p->addAttribute(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION); + p->addAttribute(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR); + p->addAttribute(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS); + break; default: CCLOG("cocos2d: %s:%d, error shader type", __FUNCTION__, __LINE__); diff --git a/cocos/2d/CCTextImage.cpp b/cocos/2d/CCTextImage.cpp index 1fb7016bd9..931b89f88e 100644 --- a/cocos/2d/CCTextImage.cpp +++ b/cocos/2d/CCTextImage.cpp @@ -88,8 +88,8 @@ bool TextPageDef::generatePageTexture(bool releasePageData) if (!_pageTexture) return false; - int dataLenght = (_width * _height * 4); - bool textureCreated = _pageTexture->initWithData(_pageData, dataLenght, Texture2D::PixelFormat::RGBA8888, _width, _height, imageSize); + int dataLenght = (_width * _height * 1); + bool textureCreated = _pageTexture->initWithData(_pageData, dataLenght, Texture2D::PixelFormat::A8, _width, _height, imageSize); // release the page data if requested if (releasePageData && textureCreated) @@ -421,7 +421,7 @@ unsigned char * TextImage::renderGlyphData(TextPageDef *thePage) int pageHeight = thePage->getHeight(); // prepare memory and clean to 0 - int sizeInBytes = (pageWidth * pageHeight * 4); + int sizeInBytes = (pageWidth * pageHeight * 1); unsigned char* data = new unsigned char[sizeInBytes]; if (!data) @@ -443,7 +443,7 @@ unsigned char * TextImage::renderGlyphData(TextPageDef *thePage) for (int cglyph = 0; cglyph < numGlyphToRender; ++cglyph) { GlyphDef currGlyph = currentLine->getGlyphAt(cglyph); - renderCharAt(currGlyph.getUTF8Letter(), origX, origY, data, pageWidth); + _font->renderCharAt(currGlyph.getUTF8Letter(), origX, origY, data, pageWidth); origX += (currGlyph.getRect().size.width + _font->getLetterPadding()); } } @@ -462,47 +462,6 @@ unsigned char * TextImage::renderGlyphData(TextPageDef *thePage) return data; } -bool TextImage::renderCharAt(unsigned short int charToRender, int posX, int posY, unsigned char *destMemory, int destSize) -{ - if (!_font) - return false; - - unsigned char *sourceBitmap = 0; - int sourceWidth = 0; - int sourceHeight = 0; - - // get the glyph's bitmap - sourceBitmap = _font->getGlyphBitmap(charToRender, sourceWidth, sourceHeight); - - if (!sourceBitmap) - return false; - - int iX = posX; - int iY = posY; - - for (int y = 0; y < sourceHeight; ++y) - { - int bitmap_y = y * sourceWidth; - - for (int x = 0; x < sourceWidth; ++x) - { - unsigned char cTemp = sourceBitmap[bitmap_y + x]; - - // the final pixel - int iTemp = cTemp << 24 | cTemp << 16 | cTemp << 8 | cTemp; - *(int*) &destMemory[(iX + ( iY * destSize ) ) * 4] = iTemp; - - iX += 1; - } - - iX = posX; - iY += 1; - } - - //everything good - return true; -} - NS_CC_END diff --git a/cocos/2d/CCTextImage.h b/cocos/2d/CCTextImage.h index 2c3265ff5b..29252e7494 100644 --- a/cocos/2d/CCTextImage.h +++ b/cocos/2d/CCTextImage.h @@ -197,7 +197,6 @@ private: // glyph rendering unsigned char * renderGlyphData(TextPageDef *thePage); - bool renderCharAt(unsigned short int charToRender, int posX, int posY, unsigned char *destMemory, int destSize); std::map _textGlyphs; TextFontPagesDef * _fontPages; diff --git a/cocos/2d/CMakeLists.txt b/cocos/2d/CMakeLists.txt index a5838f5dcb..09ce389341 100644 --- a/cocos/2d/CMakeLists.txt +++ b/cocos/2d/CMakeLists.txt @@ -138,6 +138,7 @@ set(COCOS2D_SRC platform/CCThread.cpp platform/CCEGLViewProtocol.cpp platform/CCFileUtils.cpp + ../../external/edtaa3func/edtaa3func.cpp ) include(../physics/CMakeLists.txt) diff --git a/cocos/2d/ccShader_Label_frag.h b/cocos/2d/ccShader_Label_frag.h new file mode 100644 index 0000000000..8b843571fb --- /dev/null +++ b/cocos/2d/ccShader_Label_frag.h @@ -0,0 +1,24 @@ +" \n\ +#ifdef GL_ES \n\ +precision lowp float; \n\ +#endif \n\ + \n\ +varying vec4 v_fragmentColor; \n\ +varying vec2 v_texCoord; \n\ +uniform sampler2D CC_Texture0; \n\ + \n\ +void main() \n\ +{ \n\ + vec4 color = texture2D(CC_Texture0, v_texCoord); \n\ + //the texture use dual channel 16-bit output for distance_map \n\ + //float dist = color.b+color.g/256.0; \n\ + // the texture use single channel 8-bit output for distance_map \n\ + float dist = color.a; \n\ + //todo:Implementation 'fwidth' for glsl 1.0 \n\ + //float width = fwidth(dist); \n\ + //assign width for constant will lead to a little bit fuzzy,it's temporary measure.\n\ + float width = 0.04; \n\ + float alpha = smoothstep(0.5-width, 0.5+width, dist); \n\ + gl_FragColor = vec4(v_fragmentColor.rgb,alpha); \n\ +} \n\ +"; diff --git a/cocos/2d/ccShader_Label_frag_glow.h b/cocos/2d/ccShader_Label_frag_glow.h new file mode 100644 index 0000000000..2753d718bb --- /dev/null +++ b/cocos/2d/ccShader_Label_frag_glow.h @@ -0,0 +1,24 @@ +" \n\ +#ifdef GL_ES \n\ +precision lowp float; \n\ +#endif \n\ + \n\ +varying vec4 v_fragmentColor; \n\ +varying vec2 v_texCoord; \n\ +uniform sampler2D CC_Texture0; \n\ +uniform vec3 v_effectColor; \n\ + \n\ +void main() \n\ +{ \n\ + float dist = texture2D(CC_Texture0, v_texCoord).a; \n\ + //todo:Implementation 'fwidth' for glsl 1.0 \n\ + //float width = fwidth(dist); \n\ + //assign width for constant will lead to a little bit fuzzy,it's temporary measure.\n\ + float width = 0.04; \n\ + float alpha = smoothstep(0.5-width, 0.5+width, dist); \n\ + //glow \n\ + float mu = smoothstep(0.5, 1.0, sqrt(dist)); \n\ + vec3 rgb = v_effectColor*(1.0-alpha) + v_fragmentColor.rgb*alpha; \n\ + gl_FragColor = vec4(rgb, max(alpha,mu)); \n\ +} \n\ +"; diff --git a/cocos/2d/ccShader_Label_frag_outline.h b/cocos/2d/ccShader_Label_frag_outline.h new file mode 100644 index 0000000000..672715fc18 --- /dev/null +++ b/cocos/2d/ccShader_Label_frag_outline.h @@ -0,0 +1,24 @@ +" \n\ +#ifdef GL_ES \n\ +precision lowp float; \n\ +#endif \n\ + \n\ +varying vec4 v_fragmentColor; \n\ +varying vec2 v_texCoord; \n\ +uniform sampler2D CC_Texture0; \n\ +uniform vec3 v_effectColor; \n\ + \n\ +void main() \n\ +{ \n\ + float dist = texture2D(CC_Texture0, v_texCoord).a; \n\ + //todo:Implementation 'fwidth' for glsl 1.0 \n\ + //float width = fwidth(dist); \n\ + //assign width for constant will lead to a little bit fuzzy,it's temporary measure.\n\ + float width = 0.04; \n\ + float alpha = smoothstep(0.5-width, 0.5+width, dist); \n\ + //outline \n\ + float mu = smoothstep(0.545-width, 0.545+width, dist); \n\ + vec3 rgb = v_effectColor*(1.0-mu) + v_fragmentColor.rgb*mu; \n\ + gl_FragColor = vec4(rgb, max(alpha,mu)); \n\ +} \n\ +"; diff --git a/cocos/2d/ccShader_Label_frag_shadow.h b/cocos/2d/ccShader_Label_frag_shadow.h new file mode 100644 index 0000000000..66d24a0c19 --- /dev/null +++ b/cocos/2d/ccShader_Label_frag_shadow.h @@ -0,0 +1,34 @@ +" \n\ +#ifdef GL_ES \n\ +precision lowp float; \n\ +#endif \n\ + \n\ +varying vec4 v_fragmentColor; \n\ +varying vec2 v_texCoord; \n\ +uniform sampler2D CC_Texture0; \n\ +uniform vec3 v_effectColor; \n\ +uniform vec2 v_shadowOffset; \n\ + \n\ +void main() \n\ +{ \n\ + float dist = texture2D(CC_Texture0, v_texCoord).a; \n\ + //todo:support for assign offset,but the shadow is limited by renderable area\n\ \n\ + vec2 offset = vec2(-0.0015,-0.0015); \n\ + float dist2 = texture2D(CC_Texture0, v_texCoord+offset).a; \n\ + //todo:Implementation 'fwidth' for glsl 1.0 \n\ + //float width = fwidth(dist); \n\ + //assign width for constant will lead to a little bit fuzzy,it's temporary measure.\n\ + float width = 0.04; \n\ + // If v is 1 then it's inside the Glyph; if it's 0 then it's outside \n\ + float v = smoothstep(0.5-width, 0.5+width, dist); \n\ + // If s is 1 then it's inside the shadow; if it's 0 then it's outside \n\ + float s = smoothstep(0.5-width, 0.5+width, dist2); \n\ + if(v == 1.0) gl_FragColor = vec4(v_fragmentColor.rgb,1.0); \n\ + else if(v == 0.0) gl_FragColor = vec4(v_effectColor,s); \n\ + else \n\ + { \n\ + vec3 color = v_fragmentColor.rgb*v + v_effectColor*s*(1.0-v); \n\ + gl_FragColor = vec4(color,max(s,v)); \n\ + } \n\ +} \n\ +"; diff --git a/cocos/2d/ccShader_Label_vert.h b/cocos/2d/ccShader_Label_vert.h new file mode 100644 index 0000000000..f509caf016 --- /dev/null +++ b/cocos/2d/ccShader_Label_vert.h @@ -0,0 +1,45 @@ +/* + * cocos2d for iPhone: http://www.cocos2d-iphone.org + * + * Copyright (c) 2011 Ricardo Quesada + * Copyright (c) 2012 Zynga Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +" \n\ +attribute vec4 a_position; \n\ +attribute vec2 a_texCoord; \n\ +attribute vec4 a_color; \n\ + \n\ +#ifdef GL_ES \n\ +varying lowp vec4 v_fragmentColor; \n\ +varying mediump vec2 v_texCoord; \n\ +#else \n\ +varying vec4 v_fragmentColor; \n\ +varying vec2 v_texCoord; \n\ +#endif \n\ + \n\ +void main() \n\ +{ \n\ + gl_Position = CC_MVPMatrix * a_position; \n\ + v_fragmentColor = a_color; \n\ + v_texCoord = a_texCoord; \n\ +} \n\ +"; diff --git a/cocos/2d/ccShaders.cpp b/cocos/2d/ccShaders.cpp index 56ce1bf821..9a7821d18b 100644 --- a/cocos/2d/ccShaders.cpp +++ b/cocos/2d/ccShaders.cpp @@ -74,4 +74,24 @@ const GLchar * ccPositionColorLengthTexture_frag = const GLchar * ccPositionColorLengthTexture_vert = #include "ccShader_PositionColorLengthTexture_vert.h" +const GLchar * ccLabelDistanceFieldNormal_frag = +#include "ccShader_Label_frag.h" +const GLchar * ccLabelDistanceFieldNormal_vert = +#include "ccShader_Label_vert.h" + +const GLchar * ccLabelDistanceFieldGlow_frag = +#include "ccShader_Label_frag_glow.h" +const GLchar * ccLabelDistanceFieldGlow_vert = +#include "ccShader_Label_vert.h" + +const GLchar * ccLabelDistanceFieldOutline_frag = +#include "ccShader_Label_frag_outline.h" +const GLchar * ccLabelDistanceFieldOutline_vert = +#include "ccShader_Label_vert.h" + +const GLchar * ccLabelDistanceFieldShadow_frag = +#include "ccShader_Label_frag_shadow.h" +const GLchar * ccLabelDistanceFieldShadow_vert = +#include "ccShader_Label_vert.h" + NS_CC_END diff --git a/cocos/2d/ccShaders.h b/cocos/2d/ccShaders.h index b7bea82383..1dd3673e28 100644 --- a/cocos/2d/ccShaders.h +++ b/cocos/2d/ccShaders.h @@ -58,6 +58,18 @@ extern CC_DLL const GLchar * ccPositionTexture_uColor_vert; extern CC_DLL const GLchar * ccPositionColorLengthTexture_frag; extern CC_DLL const GLchar * ccPositionColorLengthTexture_vert; +extern CC_DLL const GLchar * ccLabelDistanceFieldNormal_frag; +extern CC_DLL const GLchar * ccLabelDistanceFieldNormal_vert; + +extern CC_DLL const GLchar * ccLabelDistanceFieldGlow_frag; +extern CC_DLL const GLchar * ccLabelDistanceFieldGlow_vert; + +extern CC_DLL const GLchar * ccLabelDistanceFieldOutline_frag; +extern CC_DLL const GLchar * ccLabelDistanceFieldOutline_vert; + +extern CC_DLL const GLchar * ccLabelDistanceFieldShadow_frag; +extern CC_DLL const GLchar * ccLabelDistanceFieldShadow_vert; + extern CC_DLL const GLchar * ccExSwitchMask_frag; // end of shaders group diff --git a/cocos/2d/cocos2d.vcxproj b/cocos/2d/cocos2d.vcxproj index a026926c95..34e36daad3 100644 --- a/cocos/2d/cocos2d.vcxproj +++ b/cocos/2d/cocos2d.vcxproj @@ -73,7 +73,7 @@ Disabled - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;$(EngineRoot)external\sqlite3\include;$(EngineRoot)external\unzip;$(EngineRoot)external\tinyxml2;$(EngineRoot)external\png\include\win32;$(EngineRoot)external\jpeg\include\win32;$(EngineRoot)external\tiff\include\win32;$(EngineRoot)external\webp\include\win32;$(EngineRoot)external\freetype2\include\win32;$(EngineRoot)external\win32-specific\icon\include;$(EngineRoot)external\win32-specific\zlib\include;$(EngineRoot)external\chipmunk\include\chipmunk;%(AdditionalIncludeDirectories) + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;$(EngineRoot)external\sqlite3\include;$(EngineRoot)external\unzip;$(EngineRoot)external\edtaa3func;$(EngineRoot)external\tinyxml2;$(EngineRoot)external\png\include\win32;$(EngineRoot)external\jpeg\include\win32;$(EngineRoot)external\tiff\include\win32;$(EngineRoot)external\webp\include\win32;$(EngineRoot)external\freetype2\include\win32;$(EngineRoot)external\win32-specific\icon\include;$(EngineRoot)external\win32-specific\zlib\include;$(EngineRoot)external\chipmunk\include\chipmunk;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_LIB;COCOS2DXWIN32_EXPORTS;GL_GLEXT_PROTOTYPES;COCOS2D_DEBUG=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -120,7 +120,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\win32-specific\gles\prebuilt\*.*" "$(Ou - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;$(EngineRoot)external\sqlite3\include;$(EngineRoot)external\unzip;$(EngineRoot)external\tinyxml2;$(EngineRoot)external\png\include\win32;$(EngineRoot)external\jpeg\include\win32;$(EngineRoot)external\tiff\include\win32;$(EngineRoot)external\webp\include\win32;$(EngineRoot)external\freetype2\include\win32;$(EngineRoot)external\win32-specific\icon\include;$(EngineRoot)external\win32-specific\zlib\include;$(EngineRoot)external\chipmunk\include\chipmunk;%(AdditionalIncludeDirectories) + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;$(EngineRoot)external\sqlite3\include;$(EngineRoot)external\unzip;$(EngineRoot)external\edtaa3func;$(EngineRoot)external\tinyxml2;$(EngineRoot)external\png\include\win32;$(EngineRoot)external\jpeg\include\win32;$(EngineRoot)external\tiff\include\win32;$(EngineRoot)external\webp\include\win32;$(EngineRoot)external\freetype2\include\win32;$(EngineRoot)external\win32-specific\icon\include;$(EngineRoot)external\win32-specific\zlib\include;$(EngineRoot)external\chipmunk\include\chipmunk;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_LIB;COCOS2DXWIN32_EXPORTS;GL_GLEXT_PROTOTYPES;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL @@ -162,6 +162,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\win32-specific\gles\prebuilt\*.*" "$(Ou + @@ -321,6 +322,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\win32-specific\gles\prebuilt\*.*" "$(Ou + diff --git a/cocos/2d/cocos2d.vcxproj.filters b/cocos/2d/cocos2d.vcxproj.filters index 69900696e1..1fa70cf86d 100644 --- a/cocos/2d/cocos2d.vcxproj.filters +++ b/cocos/2d/cocos2d.vcxproj.filters @@ -566,6 +566,9 @@ base + + label_nodes + @@ -1143,5 +1146,8 @@ base + + label_nodes + \ No newline at end of file diff --git a/cocos/editor-support/cocostudio/proj.win32/libCocosStudio.vcxproj b/cocos/editor-support/cocostudio/proj.win32/libCocosStudio.vcxproj index 77de7fdb61..76bdf5947c 100644 --- a/cocos/editor-support/cocostudio/proj.win32/libCocosStudio.vcxproj +++ b/cocos/editor-support/cocostudio/proj.win32/libCocosStudio.vcxproj @@ -162,7 +162,8 @@ MaxSpeed true true - true + + WIN32;_WINDOWS;_LIB;COCOS2DXWIN32_EXPORTS;GL_GLEXT_PROTOTYPES;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) $(EngineRoot);$(EngineRoot)cocos;$(EngineRoot)cocos\audio\include;$(EngineRoot)cocos\editor-support;$(EngineRoot)external;$(EngineRoot)external\tinyxml2;$(EngineRoot)external\chipmunk\include\chipmunk;$(EngineRoot)extensions;%(AdditionalIncludeDirectories) diff --git a/external/edtaa3func/edtaa3func.cpp b/external/edtaa3func/edtaa3func.cpp new file mode 100644 index 0000000000..a75716b313 --- /dev/null +++ b/external/edtaa3func/edtaa3func.cpp @@ -0,0 +1,574 @@ +/* + * edtaa3() + * + * Sweep-and-update Euclidean distance transform of an + * image. Positive pixels are treated as object pixels, + * zero or negative pixels are treated as background. + * An attempt is made to treat antialiased edges correctly. + * The input image must have pixels in the range [0,1], + * and the antialiased image should be a box-filter + * sampling of the ideal, crisp edge. + * If the antialias region is more than 1 pixel wide, + * the result from this transform will be inaccurate. + * + * By Stefan Gustavson (stefan.gustavson@gmail.com). + * + * Originally written in 1994, based on a verbal + * description of Per-Erik Danielsson's SSED8 algorithm + * as presented in the PhD dissertation of Ingemar + * Ragnemalm. This is Per-Erik Danielsson's scanline + * scheme from 1979 - I only implemented it in C. + * + * Updated in 2004 to treat border pixels correctly, + * and cleaned up the code to improve readability. + * + * Updated in 2009 to handle anti-aliased edges, + * as published in the article "Anti-aliased Euclidean + * distance transform" by Stefan Gustavson and Robin Strand, + * Pattern Recognition Letters 32 (2011) 252C257. + * + * Updated in 2011 to avoid a corner case causing an + * infinite loop for some input data. + * +*/ + +/* + Copyright (C) 2009-2011 Stefan Gustavson (stefan.gustavson@gmail.com) + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +The GNU General Public License is available on . + */ +#ifdef __cplusplus +extern "C" { +#endif +#include + +/* + * Compute the local gradient at edge pixels using convolution filters. + * The gradient is computed only at edge pixels. At other places in the + * image, it is never used, and it's mostly zero anyway. + */ +void computegradient(double *img, int w, int h, double *gx, double *gy) +{ + int i,j,k; + double glength; +#define SQRT2 1.4142136 + for(i = 1; i < h-1; i++) { // Avoid edges where the kernels would spill over + for(j = 1; j < w-1; j++) { + k = i*w + j; + if((img[k]>0.0) && (img[k]<1.0)) { // Compute gradient for edge pixels only + gx[k] = -img[k-w-1] - SQRT2*img[k-1] - img[k+w-1] + img[k-w+1] + SQRT2*img[k+1] + img[k+w+1]; + gy[k] = -img[k-w-1] - SQRT2*img[k-w] - img[k+w-1] + img[k-w+1] + SQRT2*img[k+w] + img[k+w+1]; + glength = gx[k]*gx[k] + gy[k]*gy[k]; + if(glength > 0.0) { // Avoid division by zero + glength = sqrt(glength); + gx[k]=gx[k]/glength; + gy[k]=gy[k]/glength; + } + } + } + } + // TODO: Compute reasonable values for gx, gy also around the image edges. + // (These are zero now, which reduces the accuracy for a 1-pixel wide region + // around the image edge.) 2x2 kernels would be suitable for this. +} + +/* + * A somewhat tricky function to approximate the distance to an edge in a + * certain pixel, with consideration to either the local gradient (gx,gy) + * or the direction to the pixel (dx,dy) and the pixel greyscale value a. + * The latter alternative, using (dx,dy), is the metric used by edtaa2(). + * Using a local estimate of the edge gradient (gx,gy) yields much better + * accuracy at and near edges, and reduces the error even at distant pixels + * provided that the gradient direction is accurately estimated. + */ +double edgedf(double gx, double gy, double a) +{ + double df, glength, temp, a1; + + if ((gx == 0) || (gy == 0)) { // Either A) gu or gv are zero, or B) both + df = 0.5-a; // Linear approximation is A) correct or B) a fair guess + } else { + glength = sqrt(gx*gx + gy*gy); + if(glength>0) { + gx = gx/glength; + gy = gy/glength; + } + /* Everything is symmetric wrt sign and transposition, + * so move to first octant (gx>=0, gy>=0, gx>=gy) to + * avoid handling all possible edge directions. + */ + gx = fabs(gx); + gy = fabs(gy); + if(gx 1.0) a = 1.0; + if(a < 0.0) a = 0.0; // Clip grayscale values outside the range [0,1] + if(a == 0.0) return 1000000.0; // Not an object pixel, return "very far" ("don't know yet") + + dx = (double)xi; + dy = (double)yi; + di = sqrt(dx*dx + dy*dy); // Length of integer vector, like a traditional EDT + if(di==0) { // Use local gradient only at edges + // Estimate based on local gradient only + df = edgedf(gx, gy, a); + } else { + // Estimate gradient based on direction to edge (accurate for large di) + df = edgedf(dx, dy, a); + } + return di + df; // Same metric as edtaa2, except at edges (where di=0) +} + +// Shorthand macro: add ubiquitous parameters img, gx, gy and w and call distaa3() +#define DISTAA(c,xc,yc,xi,yi) (distaa3(img, gx, gy, w, c, xc, yc, xi, yi)) + +void edtaa3(double *img, double *gx, double *gy, int w, int h, short *distx, short *disty, double *dist) +{ + int x, y, i, c; + int offset_u, offset_ur, offset_r, offset_rd, + offset_d, offset_dl, offset_l, offset_lu; + double olddist, newdist; + int cdistx, cdisty, newdistx, newdisty; + int changed; + double epsilon = 1e-3; // Safeguard against errors due to limited precision + + /* Initialize index offsets for the current image width */ + offset_u = -w; + offset_ur = -w+1; + offset_r = 1; + offset_rd = w+1; + offset_d = w; + offset_dl = w-1; + offset_l = -1; + offset_lu = -w-1; + + /* Initialize the distance images */ + for(i=0; i 0) // If non-zero distance or not set yet + { + c = i + offset_u; // Index of candidate for testing + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx; + newdisty = cdisty+1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_ur; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx-1; + newdisty = cdisty+1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + changed = 1; + } + } + i++; + + /* Middle pixels have all neighbors */ + for(x=1; x 0) // If not already zero distance + { + c = i+offset_l; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx+1; + newdisty = cdisty; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_lu; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx+1; + newdisty = cdisty+1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_u; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx; + newdisty = cdisty+1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + changed = 1; + } + } + + /* Move index to second rightmost pixel of current row. */ + /* Rightmost pixel is skipped, it has no right neighbor. */ + i = y*w + w-2; + + /* scan left, propagate distance from right */ + for(x=w-2; x>=0; x--, i--) + { + olddist = dist[i]; + if(olddist <= 0) continue; // Already zero distance + + c = i+offset_r; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx-1; + newdisty = cdisty; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + changed = 1; + } + } + } + + /* Scan rows in reverse order, except last row */ + for(y=h-2; y>=0; y--) + { + /* move index to rightmost pixel of current row */ + i = y*w + w-1; + + /* Scan left, propagate distances from below & right */ + + /* Rightmost pixel is special, has no right neighbors */ + olddist = dist[i]; + if(olddist > 0) // If not already zero distance + { + c = i+offset_d; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_dl; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx+1; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + changed = 1; + } + } + i--; + + /* Middle pixels have all neighbors */ + for(x=w-2; x>0; x--, i--) + { + olddist = dist[i]; + if(olddist <= 0) continue; // Already zero distance + + c = i+offset_r; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx-1; + newdisty = cdisty; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_rd; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx-1; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_d; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_dl; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx+1; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + changed = 1; + } + } + /* Leftmost pixel is special, has no left neighbors */ + olddist = dist[i]; + if(olddist > 0) // If not already zero distance + { + c = i+offset_r; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx-1; + newdisty = cdisty; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_rd; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx-1; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_d; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + changed = 1; + } + } + + /* Move index to second leftmost pixel of current row. */ + /* Leftmost pixel is skipped, it has no left neighbor. */ + i = y*w + 1; + for(x=1; x + + +/* + * Compute the local gradient at edge pixels using convolution filters. + * The gradient is computed only at edge pixels. At other places in the + * image, it is never used, and it's mostly zero anyway. + */ +void computegradient(double *img, int w, int h, double *gx, double *gy); + +/* + * A somewhat tricky function to approximate the distance to an edge in a + * certain pixel, with consideration to either the local gradient (gx,gy) + * or the direction to the pixel (dx,dy) and the pixel greyscale value a. + * The latter alternative, using (dx,dy), is the metric used by edtaa2(). + * Using a local estimate of the edge gradient (gx,gy) yields much better + * accuracy at and near edges, and reduces the error even at distant pixels + * provided that the gradient direction is accurately estimated. + */ +double edgedf(double gx, double gy, double a); + + +double distaa3(double *img, double *gximg, double *gyimg, int w, int c, int xc, int yc, int xi, int yi); + +// Shorthand macro: add ubiquitous parameters dist, gx, gy, img and w and call distaa3() +#define DISTAA(c,xc,yc,xi,yi) (distaa3(img, gx, gy, w, c, xc, yc, xi, yi)) + +void edtaa3(double *img, double *gx, double *gy, int w, int h, short *distx, short *disty, double *dist); + + +#ifdef __cplusplus +} +#endif + +#endif // __EDTAA3FUNC_H__ diff --git a/samples/Cpp/TestCpp/Android.mk b/samples/Cpp/TestCpp/Android.mk index 42c2d338c7..39022ceb4c 100644 --- a/samples/Cpp/TestCpp/Android.mk +++ b/samples/Cpp/TestCpp/Android.mk @@ -120,6 +120,7 @@ Classes/PerformanceTest/PerformanceSpriteTest.cpp \ Classes/PerformanceTest/PerformanceTest.cpp \ Classes/PerformanceTest/PerformanceTextureTest.cpp \ Classes/PerformanceTest/PerformanceTouchesTest.cpp \ +Classes/PerformanceTest/PerformanceLabelTest.cpp \ Classes/PhysicsTest/PhysicsTest.cpp \ Classes/RenderTextureTest/RenderTextureTest.cpp \ Classes/RotateWorldTest/RotateWorldTest.cpp \ diff --git a/samples/Cpp/TestCpp/CMakeLists.txt b/samples/Cpp/TestCpp/CMakeLists.txt index 8d205fd236..474020e345 100644 --- a/samples/Cpp/TestCpp/CMakeLists.txt +++ b/samples/Cpp/TestCpp/CMakeLists.txt @@ -102,6 +102,7 @@ set(SAMPLE_SRC Classes/PerformanceTest/PerformanceTest.cpp Classes/PerformanceTest/PerformanceTextureTest.cpp Classes/PerformanceTest/PerformanceTouchesTest.cpp + Classes/PerformanceTest/PerformanceLabelTest.cpp Classes/PhysicsTest/PhysicsTest.cpp Classes/RenderTextureTest/RenderTextureTest.cpp Classes/RotateWorldTest/RotateWorldTest.cpp diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp index 6c18c415af..227462eca5 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp @@ -63,7 +63,9 @@ static std::function createFunctions[] = CL(LabelTTFFontsTestNew), CL(LabelTTFDynamicAlignment), CL(LabelTTFUnicodeNew), - CL(LabelBMFontTestNew) + CL(LabelBMFontTestNew), + CL(LabelTTFDistanceField), + CL(LabelTTFDistanceFieldEffect) }; #define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0])) @@ -1134,3 +1136,77 @@ std::string LabelBMFontTestNew::subtitle() return "Uses the new Label with .FNT file"; } +LabelTTFDistanceField::LabelTTFDistanceField() +{ + auto size = Director::getInstance()->getWinSize(); + + auto label1 = Label::createWithTTF("Distance Field", "fonts/arial.ttf", 80, size.width, TextHAlignment::CENTER, GlyphCollection::DYNAMIC,nullptr,true); + label1->setPosition( Point(size.width/2, size.height/2) ); + label1->setColor( Color3B::GREEN ); + label1->setAnchorPoint(Point(0.5, 0.5)); + addChild(label1); + + auto action = Sequence::create( + DelayTime::create(1.0f), + ScaleTo::create(6.0f,5.0f,5.0f), + ScaleTo::create(6.0f,1.0f,1.0f), + nullptr); + label1->runAction(RepeatForever::create(action)); + + auto label2 = Label::createWithTTF("Distance Field", "fonts/arial.ttf", 80, size.width, TextHAlignment::CENTER, GlyphCollection::DYNAMIC,nullptr,true); + label2->setPosition( Point(size.width/2, size.height/5) ); + label2->setColor( Color3B::RED ); + label2->setAnchorPoint(Point(0.5, 0.5)); + addChild(label2); + +} + +std::string LabelTTFDistanceField::title() +{ + return "New Label + .TTF"; +} + +std::string LabelTTFDistanceField::subtitle() +{ + return "Testing rendering base on DistanceField"; +} + +LabelTTFDistanceFieldEffect::LabelTTFDistanceFieldEffect() +{ + auto size = Director::getInstance()->getWinSize(); + + auto bg = LayerColor::create(Color4B(200,191,231,255)); + this->addChild(bg); + + auto label1 = Label::createWithTTF("Glow", "fonts/arial.ttf", 80, size.width, TextHAlignment::CENTER, GlyphCollection::DYNAMIC,nullptr,true); + label1->setPosition( Point(size.width/2, size.height*0.5) ); + label1->setColor( Color3B::GREEN ); + label1->setAnchorPoint(Point(0.5, 0.5)); + label1->setLabelEffect(LabelEffect::GLOW,Color3B::YELLOW); + addChild(label1); + + auto label2 = Label::createWithTTF("Outline", "fonts/arial.ttf", 80, size.width, TextHAlignment::CENTER, GlyphCollection::DYNAMIC,nullptr,true); + label2->setPosition( Point(size.width/2, size.height*0.375) ); + label2->setColor( Color3B::RED ); + label2->setAnchorPoint(Point(0.5, 0.5)); + label2->setLabelEffect(LabelEffect::OUTLINE,Color3B::BLUE); + addChild(label2); + + auto label3 = Label::createWithTTF("Shadow", "fonts/arial.ttf", 80, size.width, TextHAlignment::CENTER, GlyphCollection::DYNAMIC,nullptr,true); + label3->setPosition( Point(size.width/2, size.height*0.25f) ); + label3->setColor( Color3B::RED ); + label3->setAnchorPoint(Point(0.5, 0.5)); + label3->setLabelEffect(LabelEffect::SHADOW,Color3B::BLACK); + addChild(label3); + +} + +std::string LabelTTFDistanceFieldEffect::title() +{ + return "New Label + .TTF"; +} + +std::string LabelTTFDistanceFieldEffect::subtitle() +{ + return "Testing effect base on DistanceField"; +} diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h index 03e94cc682..1bb5216fb5 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h @@ -318,6 +318,27 @@ public: private: }; +class LabelTTFDistanceField : public AtlasDemoNew +{ +public: + CREATE_FUNC(LabelTTFDistanceField); + + LabelTTFDistanceField(); + + virtual std::string title(); + virtual std::string subtitle(); +}; + +class LabelTTFDistanceFieldEffect : public AtlasDemoNew +{ +public: + CREATE_FUNC(LabelTTFDistanceFieldEffect); + + LabelTTFDistanceFieldEffect(); + + virtual std::string title(); + virtual std::string subtitle(); +}; // we don't support linebreak mode diff --git a/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceLabelTest.cpp b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceLabelTest.cpp new file mode 100644 index 0000000000..f5c91270a8 --- /dev/null +++ b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceLabelTest.cpp @@ -0,0 +1,449 @@ +#include "PerformanceLabelTest.h" + +enum { + kMaxNodes = 200, + kNodesIncrease = 2, + + TEST_COUNT = 5, +}; + +enum { + kTagInfoLayer = 1, + kTagMainLayer, + kTagAutoTestMenu, + kTagMenuLayer = (kMaxNodes + 1000), +}; + +enum { + kCaseLabelTTFUpdate = 0, + kCaseLabelBMFontUpdate, + kCaseLabelUpdate, + kCaseLabelBMFontBigLabels, + kCaseLabelBigLabels +}; + +#define LongSentencesExample "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\ +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\ +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + + +//////////////////////////////////////////////////////// +// +// LabelMenuLayer +// +//////////////////////////////////////////////////////// +void LabelMenuLayer::restartCallback(Object* sender) +{ + if ( LabelMainScene::_s_autoTest ) + { + log("It's auto label performance testing,so this operation is invalid"); + return; + } + + PerformBasicLayer::restartCallback(sender); +} + +void LabelMenuLayer::nextCallback(Object* sender) +{ + if ( LabelMainScene::_s_autoTest ) + { + log("It's auto label performance testing,so this operation is invalid"); + return; + } + + PerformBasicLayer::nextCallback(sender); +} + +void LabelMenuLayer::backCallback(Object* sender) +{ + if ( LabelMainScene::_s_autoTest ) + { + log("It's auto label performance testing,so this operation is invalid"); + return; + } + + PerformBasicLayer::backCallback(sender); +} + +void LabelMenuLayer::showCurrentTest() +{ + auto scene = (LabelMainScene*) getParent(); + scene->autoShowLabelTests(_curCase,LabelMainScene::AUTO_TEST_NODE_NUM); +} +//////////////////////////////////////////////////////// +// +// LabelMainScene +// +//////////////////////////////////////////////////////// + +bool LabelMainScene::_s_autoTest = false; +int LabelMainScene::_s_labelCurCase = 0; + +void LabelMainScene::initWithSubTest(int nodes) +{ + //srandom(0); + auto s = Director::getInstance()->getWinSize(); + + _lastRenderedCount = 0; + _quantityNodes = 0; + + _labelContainer = Layer::create(); + addChild(_labelContainer); + + MenuItemFont::setFontSize(65); + auto decrease = MenuItemFont::create(" - ", CC_CALLBACK_1(LabelMainScene::onDecrease, this)); + decrease->setColor(Color3B(0,200,20)); + auto increase = MenuItemFont::create(" + ", CC_CALLBACK_1(LabelMainScene::onIncrease, this)); + increase->setColor(Color3B(0,200,20)); + + auto menu = Menu::create(decrease, increase, NULL); + menu->alignItemsHorizontally(); + menu->setPosition(Point(s.width/2, s.height-65)); + addChild(menu, 1); + + auto infoLabel = LabelTTF::create("0 nodes", "Marker Felt", 30); + infoLabel->setColor(Color3B(0,200,20)); + infoLabel->setPosition(Point(s.width/2, s.height-90)); + addChild(infoLabel, 1, kTagInfoLayer); + + // add menu + auto menuLayer = new LabelMenuLayer(true, TEST_COUNT, LabelMainScene::_s_labelCurCase); + addChild(menuLayer, 1, kTagMenuLayer); + menuLayer->release(); + + /** + * auto test menu + */ + + auto menuAutoTest = Menu::create(); + menuAutoTest->setPosition( Point::ZERO ); + MenuItemFont::setFontName("Arial"); + MenuItemFont::setFontSize(24); + + MenuItemFont* autoTestItem = NULL; + if (LabelMainScene::_s_autoTest) + { + autoTestItem = MenuItemFont::create("Auto Test On",CC_CALLBACK_1(LabelMainScene::onAutoTest, this)); + } + else + { + autoTestItem = MenuItemFont::create("Auto Test Off",CC_CALLBACK_1(LabelMainScene::onAutoTest, this)); + } + autoTestItem->setTag(1); + autoTestItem->setPosition(Point( s.width - 90, s.height / 2)); + autoTestItem->setColor(Color3B::RED); + menuAutoTest->addChild(autoTestItem); + addChild( menuAutoTest, 3, kTagAutoTestMenu ); + + _title = LabelTTF::create(title().c_str(), "Arial", 32); + addChild(_title, 1); + _title->setPosition(Point(s.width/2, s.height-32)); + _title->setColor(Color3B(255,255,40)); + + while(_quantityNodes < nodes) + onIncrease(this); +} + +std::string LabelMainScene::title() +{ + switch (_s_labelCurCase) + { + case kCaseLabelTTFUpdate: + return "Testing LabelTTF Update"; + case kCaseLabelBMFontUpdate: + return "Testing LabelBMFont Update"; + case kCaseLabelUpdate: + return "Testing Label Update"; + case kCaseLabelBMFontBigLabels: + return "Testing LabelBMFont Big Labels"; + case kCaseLabelBigLabels: + return "Testing Label Big Labels"; + default: + break; + } + return "No title"; +} + +LabelMainScene::~LabelMainScene() +{ + +} + +void LabelMainScene::updateNodes() +{ + if( _quantityNodes != _lastRenderedCount ) + { + auto infoLabel = (LabelTTF *) getChildByTag(kTagInfoLayer); + char str[16] = {0}; + sprintf(str, "%u nodes", _quantityNodes); + infoLabel->setString(str); + + _lastRenderedCount = _quantityNodes; + } +} + +void LabelMainScene::onIncrease(Object* sender) +{ + if( _quantityNodes >= kMaxNodes) + return; + + auto size = Director::getInstance()->getWinSize(); + + switch (_s_labelCurCase) + { + case kCaseLabelTTFUpdate: + for( int i=0;i< kNodesIncrease;i++) + { + auto label = LabelTTF::create("LabelTTF", "Marker Felt", 30); + label->setPosition(Point((size.width/2 + rand() % 50), ((int)size.height/2 + rand() % 50))); + _labelContainer->addChild(label, 1, _quantityNodes); + + _quantityNodes++; + } + break; + case kCaseLabelBMFontUpdate: + for( int i=0;i< kNodesIncrease;i++) + { + auto label = LabelBMFont::create("LabelBMFont", "fonts/bitmapFontTest3.fnt"); + label->setPosition(Point((size.width/2 + rand() % 50), ((int)size.height/2 + rand() % 50))); + _labelContainer->addChild(label, 1, _quantityNodes); + + _quantityNodes++; + } + break; + case kCaseLabelUpdate: + for( int i=0;i< kNodesIncrease;i++) + { + auto label = Label::createWithTTF("Label", "fonts/arial.ttf", 60, size.width, TextHAlignment::CENTER, GlyphCollection::DYNAMIC,nullptr,true); + label->setPosition(Point((size.width/2 + rand() % 50), ((int)size.height/2 + rand() % 50))); + _labelContainer->addChild(label, 1, _quantityNodes); + + _quantityNodes++; + } + break; + case kCaseLabelBMFontBigLabels: + for( int i=0;i< kNodesIncrease;i++) + { + auto label = LabelBMFont::create(LongSentencesExample, "fonts/bitmapFontTest3.fnt"); + label->setPosition(Point((size.width/2 + rand() % 50), ((int)size.height/2 + rand() % 50))); + _labelContainer->addChild(label, 1, _quantityNodes); + + _quantityNodes++; + } + break; + case kCaseLabelBigLabels: + for( int i=0;i< kNodesIncrease;i++) + { + auto label = Label::createWithTTF(LongSentencesExample, "fonts/arial.ttf", 60, size.width, TextHAlignment::CENTER, GlyphCollection::DYNAMIC,nullptr); + label->setPosition(Point((rand() % 50), rand()%((int)size.height/3))); + _labelContainer->addChild(label, 1, _quantityNodes); + + _quantityNodes++; + } + break; + default: + break; + } + + updateNodes(); +} + +void LabelMainScene::onDecrease(Object* sender) +{ + if( _quantityNodes <= 0 ) + return; + + for( int i = 0;i < kNodesIncrease;i++) + { + _quantityNodes--; + _labelContainer->removeChildByTag(_quantityNodes); + } + + updateNodes(); +} + +void LabelMainScene::dumpProfilerFPS() +{ + if (_vecFPS.empty()) + { + log("Error: the FPS vector is empty"); + return; + } + + auto iter = _vecFPS.begin(); + float minFPS = *iter; + float maxFPS = *iter; + float totalFPS = 0.0f; + float averagerFPS = 0.0f; + for (auto fps : _vecFPS) + { + CCLOG("fps is :%f\n",fps); + minFPS = std::min(minFPS, fps); + maxFPS = std::max(maxFPS, fps); + totalFPS += fps; + } + + averagerFPS = totalFPS / _vecFPS.size(); + log("Cur test: %d, cur label nums:%d, the min FPS value is %.1f,the max FPS value is %.1f,the averager FPS is %.1f", LabelMainScene::_s_labelCurCase, _quantityNodes, minFPS, maxFPS, averagerFPS); + +} + +void LabelMainScene::updateAutoTest(float dt) +{ + if (LabelMainScene::_s_autoTest) + { + _executeTimes += 1; + _vecFPS.push_back(Director::getInstance()->getFrameRate()); + if ( _executeTimes >= LabelMainScene::MAX_AUTO_TEST_TIMES ) + { + dumpProfilerFPS(); + nextAutoTest(); + } + } +} + +void LabelMainScene::updateText(float dt) +{ + if(_s_labelCurCase > kCaseLabelUpdate) + return; + + _accumulativeTime += dt; + char text[20]; + sprintf(text,"%.2f",_accumulativeTime); + + switch (_s_labelCurCase) + { + case kCaseLabelTTFUpdate: + _labelContainer->getChildren().forEach([&text](Node* child){ + if (child) + { + LabelTTF* label = (LabelTTF*)child; + label->setString(text); + } + }); + break; + case kCaseLabelBMFontUpdate: + _labelContainer->getChildren().forEach([&text](Node* child){ + if (child) + { + LabelBMFont* label = (LabelBMFont*)child; + label->setString(text); + } + }); + break; + case kCaseLabelUpdate: + _labelContainer->getChildren().forEach([&text](Node* child){ + if (child) + { + Label* label = (Label*)child; + label->setString(text,false); + } + }); + break; + default: + break; + } +} + +void LabelMainScene::onEnter() +{ + Scene::onEnter(); + + auto director = Director::getInstance(); + auto sched = director->getScheduler(); + sched->scheduleSelector(SEL_SCHEDULE(&LabelMainScene::updateText), this, 0.0f, false); + + _vecFPS.clear(); + _executeTimes = 0; + sched->scheduleSelector(SEL_SCHEDULE(&LabelMainScene::updateAutoTest), this, 0.2f, false); +} + +void LabelMainScene::onExit() +{ + auto director = Director::getInstance(); + auto sched = director->getScheduler(); + sched->unscheduleSelector(SEL_SCHEDULE(&LabelMainScene::updateText), this ); + sched->unscheduleSelector(SEL_SCHEDULE(&LabelMainScene::updateAutoTest), this ); + + Scene::onExit(); +} + +void LabelMainScene::autoShowLabelTests(int curCase,int nodes) +{ + LabelMainScene::_s_labelCurCase = curCase; + _title->setString(title()); + _vecFPS.clear(); + _executeTimes = 0; + _labelContainer->removeAllChildren(); + _lastRenderedCount = 0; + _quantityNodes = 0; + _accumulativeTime = 0.0f; + while(_quantityNodes < nodes) + onIncrease(this); +} + +void LabelMainScene::endAutoTest() +{ + LabelMainScene::_s_autoTest = false; + + _vecFPS.clear(); + _executeTimes = 0; +} + +void LabelMainScene::nextAutoTest() +{ + if ( LabelMainScene::_s_labelCurCase + 1 < LabelMainScene::MAX_SUB_TEST_NUMS ) + { + LabelMainScene::_s_labelCurCase += 1; + autoShowLabelTests(LabelMainScene::_s_labelCurCase, LabelMainScene::AUTO_TEST_NODE_NUM); + } + else + { + finishAutoTest(); + } +} + +void LabelMainScene::finishAutoTest() +{ + LabelMainScene::_s_autoTest = false; + + auto autoTestMenu = dynamic_cast(getChildByTag(kTagAutoTestMenu)); + if (nullptr != autoTestMenu) + { + auto menuItemFont = dynamic_cast(autoTestMenu->getChildByTag(1)); + if (nullptr != menuItemFont) + { + menuItemFont->setString("Auto Test finish"); + } + } + + log("Label performance test is finish "); +} + +void LabelMainScene::onAutoTest(Object* sender) +{ + LabelMainScene::_s_autoTest = !LabelMainScene::_s_autoTest; + MenuItemFont* menuItem = dynamic_cast(sender); + if (nullptr != menuItem) + { + if (LabelMainScene::_s_autoTest) + { + menuItem->setString("Auto Test On"); + autoShowLabelTests(0,AUTO_TEST_NODE_NUM); + } + else + { + menuItem->setString("Auto Test Off"); + endAutoTest(); + } + } +} + +void runLabelTest() +{ + LabelMainScene::_s_autoTest = false; + auto scene = new LabelMainScene; + scene->initWithSubTest(LabelMainScene::AUTO_TEST_NODE_NUM); + Director::getInstance()->replaceScene(scene); + scene->release(); +} diff --git a/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceLabelTest.h b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceLabelTest.h new file mode 100644 index 0000000000..f8c60a0433 --- /dev/null +++ b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceLabelTest.h @@ -0,0 +1,74 @@ +#ifndef __PERFORMANCE_LABEL_TEST_H__ +#define __PERFORMANCE_LABEL_TEST_H__ + +#include "PerformanceTest.h" + +class LabelMenuLayer : public PerformBasicLayer +{ +public: + LabelMenuLayer(bool controlMenuVisible, int maxCases = 0, int curCase = 0) + : PerformBasicLayer(controlMenuVisible, maxCases, curCase) + { + } + + virtual void restartCallback(Object* sender) override; + virtual void nextCallback(Object* sender) override; + virtual void backCallback(Object* sender) override; + virtual void showCurrentTest() override; +}; + +class LabelMainScene : public Scene +{ +public: + static const int AUTO_TEST_NODE_NUM = 6; + + virtual ~LabelMainScene(); + + std::string title(); + void initWithSubTest(int nodes); + void updateNodes(); + + void onIncrease(Object* sender); + void onDecrease(Object* sender); + + int getSubTestNum() { return 1; } + int getNodesNum() { return _quantityNodes; } + + void updateAutoTest(float dt); + void updateText(float dt); + void onAutoTest(Object* sender); + + void autoShowLabelTests(int curCase,int nodes); + + virtual void onEnter() override; + virtual void onExit() override; + + static bool _s_autoTest; + static int _s_labelCurCase; + +private: + static const int MAX_AUTO_TEST_TIMES = 50; + static const int MAX_SUB_TEST_NUMS = 5; + + + void dumpProfilerFPS(); + + void endAutoTest(); + void nextAutoTest(); + void finishAutoTest(); + + Layer* _labelContainer; + LabelTTF* _title; + + int _lastRenderedCount; + int _quantityNodes; + + std::vector _vecFPS; + int _executeTimes; + + float _accumulativeTime; +}; + +void runLabelTest(); + +#endif diff --git a/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceTest.cpp b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceTest.cpp index 69e10a75eb..e48ef17f28 100644 --- a/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceTest.cpp +++ b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceTest.cpp @@ -6,6 +6,7 @@ #include "PerformanceTextureTest.h" #include "PerformanceTouchesTest.h" #include "PerformanceAllocTest.h" +#include "PerformanceLabelTest.h" enum { @@ -24,6 +25,7 @@ struct { { "Sprite Perf Test",[](Object*sender){runSpriteTest();} }, { "Texture Perf Test",[](Object*sender){runTextureTest();} }, { "Touches Perf Test",[](Object*sender){runTouchesTest();} }, + { "Label Perf Test",[](Object*sender){runLabelTest();} }, }; static const int g_testMax = sizeof(g_testsName)/sizeof(g_testsName[0]); diff --git a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj index b526f9588d..670f24b7c5 100644 --- a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj +++ b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj @@ -185,6 +185,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\websockets\prebuilt\win32\*.*" "$ + @@ -327,6 +328,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\websockets\prebuilt\win32\*.*" "$ + diff --git a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj.filters b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj.filters index c0fcb15592..ac6fe2734d 100644 --- a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj.filters +++ b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj.filters @@ -709,6 +709,9 @@ Classes\ConsoleTest + + Classes\PerformanceTest + @@ -1303,5 +1306,8 @@ Classes\ConsoleTest + + Classes\PerformanceTest + \ No newline at end of file diff --git a/template/multi-platform-cpp/CMakeLists.txt b/template/multi-platform-cpp/CMakeLists.txt index 88299d0d83..1a3a1e58cf 100644 --- a/template/multi-platform-cpp/CMakeLists.txt +++ b/template/multi-platform-cpp/CMakeLists.txt @@ -60,6 +60,7 @@ include_directories( ${COCOS2D_ROOT}/cocos/math/kazmath/include ${COCOS2D_ROOT}/extensions ${COCOS2D_ROOT}/external + ${COCOS2D_ROOT}/external/edtaa3func ${COCOS2D_ROOT}/external/jpeg/include/linux ${COCOS2D_ROOT}/external/tiff/include/linux ${COCOS2D_ROOT}/external/webp/include/linux diff --git a/template/multi-platform-lua/CMakeLists.txt b/template/multi-platform-lua/CMakeLists.txt index a3cf368403..6080658d0f 100644 --- a/template/multi-platform-lua/CMakeLists.txt +++ b/template/multi-platform-lua/CMakeLists.txt @@ -63,6 +63,7 @@ include_directories( ${COCOS2D_ROOT}/cocos/math/kazmath/include ${COCOS2D_ROOT}/extensions ${COCOS2D_ROOT}/external + ${COCOS2D_ROOT}/external/edtaa3func ${COCOS2D_ROOT}/external/jpeg/include/linux ${COCOS2D_ROOT}/external/tiff/include/linux ${COCOS2D_ROOT}/external/webp/include/linux