Merge pull request #4460 from Dhilan007/label_distanceField

new label:add support for distanceField
This commit is contained in:
minggo 2013-12-16 23:18:41 -08:00
commit 16ed9155c0
44 changed files with 2011 additions and 170 deletions

View File

@ -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}

View File

@ -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 \

View File

@ -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);

View File

@ -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,6 +81,7 @@ protected:
char * _customGlyphs;
static const char * _glyphASCII;
static const char * _glyphNEHE;
bool _distanceFieldEnabled;
};

View File

@ -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,6 +36,7 @@ _font(&theFont),
_currentPageData(nullptr)
{
_font->retain();
_makeDistanceMap = _font->isDistanceFieldEnabled();
FontFreeType* fontTTf = dynamic_cast<FontFreeType*>(_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,7 +110,7 @@ bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String)
FontFreeType* fontTTf = (FontFreeType*)_font;
std::vector<FontLetterDefinition> fontDefs;
std::unordered_map<unsigned short, FontLetterDefinition> fontDefs;
int length = cc_wcslen(utf16String);
//find out new letter
@ -107,6 +120,10 @@ bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String)
if (outIterator == _fontLetterDefinitions.end())
{
auto outIterator2 = fontDefs.find(utf16String[i]);
if(outIterator2 != fontDefs.end())
continue;
Rect tempRect;
FontLetterDefinition tempDef;
@ -136,27 +153,29 @@ bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String)
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)
{
_atlasTextures[_currentPage]->initWithData(_currentPageData, _currentPageDataSize, Texture2D::PixelFormat::RGBA8888, 1024, 1024, Size(1024, 1024) );
_currentPageOrigX = 0;
if(_currentPageOrigY >= PAGE_HEIGHT)
{
_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;
}

View File

@ -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<int, Texture2D*> _atlasTextures;
@ -89,6 +88,7 @@ private:
float _currentPageOrigY;
float _currentPageLineHeight;
float _letterPadding;
bool _makeDistanceMap;
};

View File

@ -30,14 +30,14 @@ NS_CC_BEGIN
std::unordered_map<std::string, FontAtlas *> 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;

View File

@ -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<std::string, FontAtlas *> _atlasMap;
};

View File

@ -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
{

View File

@ -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:

View File

@ -93,6 +93,8 @@ _letterPadding(5),
_ttfData(nullptr),
_dynamicGlyphCollection(dynamicGlyphCollection)
{
if(_distanceFieldEnabled)
_letterPadding += 2 * DistanceMapSpread;
}
bool FontFreeType::createFontObject(const std::string &fontName, int fontSize)
@ -359,18 +361,16 @@ unsigned char * FontFreeType::getGlyphBitmap(unsigned short theChar, int &outW
if (!_fontRef)
return 0;
// get the ID to the char we need
int glyphIndex = FT_Get_Char_Index(_fontRef, theChar);
if (!glyphIndex)
if (_distanceFieldEnabled)
{
if (FT_Load_Char(_fontRef,theChar,FT_LOAD_RENDER | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT))
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 ))
}
else
{
if (FT_Load_Char(_fontRef,theChar,FT_LOAD_RENDER))
return 0;
}
outWidth = _fontRef->glyph->bitmap.width;
outHeight = _fontRef->glyph->bitmap.rows;

View File

@ -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;

View File

@ -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";

View File

@ -86,6 +86,11 @@ public:
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;
static const char* UNIFORM_NAME_MV_MATRIX;

View File

@ -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);

View File

@ -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<LetterInfo> _lettersInfo;
bool _multilineEnable;
float _commonLineHeight;
bool _lineBreakWithoutSpaces;
float _width;
@ -163,6 +180,14 @@ private:
unsigned char _realOpacity;
bool _isOpacityModifyRGB;
bool _useDistanceField;
bool _useA8Shader;
int _fontSize;
LabelEffect _currLabelEffect;
Color3B _effectColor;
GLuint _uniformEffectColor;
};

View File

@ -58,7 +58,7 @@ bool LabelTextFormatter::multilineText(LabelTextFormatProtocol *theLabel)
std::vector<LetterInfo> *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);

View File

@ -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__);

View File

@ -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

View File

@ -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<unsigned short int, GlyphDef> _textGlyphs;
TextFontPagesDef * _fontPages;

View File

@ -138,6 +138,7 @@ set(COCOS2D_SRC
platform/CCThread.cpp
platform/CCEGLViewProtocol.cpp
platform/CCFileUtils.cpp
../../external/edtaa3func/edtaa3func.cpp
)
include(../physics/CMakeLists.txt)

View File

@ -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\
";

View File

@ -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\
";

View File

@ -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\
";

View File

@ -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\
";

View File

@ -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\
";

View File

@ -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

View File

@ -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

View File

@ -73,7 +73,7 @@
</PreBuildEvent>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(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)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_LIB;COCOS2DXWIN32_EXPORTS;GL_GLEXT_PROTOTYPES;COCOS2D_DEBUG=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
@ -120,7 +120,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\win32-specific\gles\prebuilt\*.*" "$(Ou
</Command>
</PreBuildEvent>
<ClCompile>
<AdditionalIncludeDirectories>$(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)</AdditionalIncludeDirectories>
<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)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_LIB;COCOS2DXWIN32_EXPORTS;GL_GLEXT_PROTOTYPES;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PrecompiledHeader>
@ -162,6 +162,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\win32-specific\gles\prebuilt\*.*" "$(Ou
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\external\edtaa3func\edtaa3func.cpp" />
<ClCompile Include="..\..\external\tinyxml2\tinyxml2.cpp" />
<ClCompile Include="..\..\external\unzip\ioapi.cpp" />
<ClCompile Include="..\..\external\unzip\unzip.cpp" />
@ -321,6 +322,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\external\win32-specific\gles\prebuilt\*.*" "$(Ou
<ClCompile Include="ZipUtils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\external\edtaa3func\edtaa3func.h" />
<ClInclude Include="..\..\external\tinyxml2\tinyxml2.h" />
<ClInclude Include="..\..\external\unzip\ioapi.h" />
<ClInclude Include="..\..\external\unzip\unzip.h" />

View File

@ -566,6 +566,9 @@
<ClCompile Include="..\base\CCValue.cpp">
<Filter>base</Filter>
</ClCompile>
<ClCompile Include="..\..\external\edtaa3func\edtaa3func.cpp">
<Filter>label_nodes</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\physics\CCPhysicsBody.h">
@ -1143,5 +1146,8 @@
<ClInclude Include="..\base\CCVector.h">
<Filter>base</Filter>
</ClInclude>
<ClInclude Include="..\..\external\edtaa3func\edtaa3func.h">
<Filter>label_nodes</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -162,7 +162,8 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<SDLCheck>
</SDLCheck>
<PreprocessorDefinitions>WIN32;_WINDOWS;_LIB;COCOS2DXWIN32_EXPORTS;GL_GLEXT_PROTOTYPES;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(EngineRoot);$(EngineRoot)cocos;$(EngineRoot)cocos\audio\include;$(EngineRoot)cocos\editor-support;$(EngineRoot)external;$(EngineRoot)external\tinyxml2;$(EngineRoot)external\chipmunk\include\chipmunk;$(EngineRoot)extensions;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>

574
external/edtaa3func/edtaa3func.cpp vendored Normal file
View File

@ -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) 252¨C257.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <math.h>
/*
* 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<gy) {
temp = gx;
gx = gy;
gy = temp;
}
a1 = 0.5*gy/gx;
if (a < a1) { // 0 <= a < a1
df = 0.5*(gx + gy) - sqrt(2.0*gx*gy*a);
} else if (a < (1.0-a1)) { // a1 <= a <= 1-a1
df = (0.5-a)*gx;
} else { // 1-a1 < a <= 1
df = -0.5*(gx + gy) + sqrt(2.0*gx*gy*(1.0-a));
}
}
return df;
}
double distaa3(double *img, double *gximg, double *gyimg, int w, int c, int xc, int yc, int xi, int yi)
{
double di, df, dx, dy, gx, gy, a;
int closest;
closest = c-xc-yc*w; // Index to the edge pixel pointed to from c
a = img[closest]; // Grayscale value at the edge pixel
gx = gximg[closest]; // X gradient component at the edge pixel
gy = gyimg[closest]; // Y gradient component at the edge pixel
if(a > 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<w*h; i++) {
distx[i] = 0; // At first, all pixels point to
disty[i] = 0; // themselves as the closest known.
if(img[i] <= 0.0)
{
dist[i]= 1000000.0; // Big value, means "not set yet"
}
else if (img[i]<1.0) {
dist[i] = edgedf(gx[i], gy[i], img[i]); // Gradient-assisted estimate
}
else {
dist[i]= 0.0; // Inside the object
}
}
/* Perform the transformation */
do
{
changed = 0;
/* Scan rows, except first row */
for(y=1; y<h; y++)
{
/* move index to leftmost pixel of current row */
i = y*w;
/* scan right, propagate distances from above & left */
/* Leftmost pixel is special, has no left neighbors */
olddist = dist[i];
if(olddist > 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<w-1; x++, i++)
{
olddist = dist[i];
if(olddist <= 0) continue; // No need to update further
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;
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;
}
}
/* Rightmost pixel of row is special, has no right neighbors */
olddist = dist[i];
if(olddist > 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<w; x++, i++)
{
/* scan right, propagate distance from left */
olddist = dist[i];
if(olddist <= 0) continue; // 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;
changed = 1;
}
}
}
}
while(changed); // Sweep until no more updates are made
/* The transformation is completed. */
}
#ifdef __cplusplus
}
#endif

100
external/edtaa3func/edtaa3func.h vendored Normal file
View File

@ -0,0 +1,100 @@
/*
* Copyright 2009 Stefan Gustavson (stefan.gustavson@gmail.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY STEFAN GUSTAVSON ''AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL STEFAN GUSTAVSON OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of Stefan Gustavson.
*
*
* 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 the SSED8 algorithm published in the
* PhD dissertation of Ingemar Ragnemalm. This is his
* algorithm, 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.
*
* Updated in 2011 to avoid a corner case infinite loop.
*
*/
#ifndef __EDTAA3FUNC_H__
#define __EDTAA3FUNC_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <math.h>
/*
* 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__

View File

@ -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 \

View File

@ -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

View File

@ -63,7 +63,9 @@ static std::function<Layer*()> 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";
}

View File

@ -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

View File

@ -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<Menu*>(getChildByTag(kTagAutoTestMenu));
if (nullptr != autoTestMenu)
{
auto menuItemFont = dynamic_cast<MenuItemFont*>(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<MenuItemFont*>(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();
}

View File

@ -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<float> _vecFPS;
int _executeTimes;
float _accumulativeTime;
};
void runLabelTest();
#endif

View File

@ -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]);

View File

@ -185,6 +185,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\websockets\prebuilt\win32\*.*" "$
<ClCompile Include="..\Classes\LabelTest\LabelTestNew.cpp" />
<ClCompile Include="..\Classes\NewEventDispatcherTest\NewEventDispatcherTest.cpp" />
<ClCompile Include="..\Classes\PerformanceTest\PerformanceAllocTest.cpp" />
<ClCompile Include="..\Classes\PerformanceTest\PerformanceLabelTest.cpp" />
<ClCompile Include="..\Classes\PhysicsTest\PhysicsTest.cpp" />
<ClCompile Include="..\Classes\ShaderTest\ShaderTest2.cpp" />
<ClCompile Include="..\Classes\SpineTest\SpineTest.cpp" />
@ -327,6 +328,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\websockets\prebuilt\win32\*.*" "$
<ClInclude Include="..\Classes\KeyboardTest\KeyboardTest.h" />
<ClInclude Include="..\Classes\LabelTest\LabelTestNew.h" />
<ClInclude Include="..\Classes\NewEventDispatcherTest\NewEventDispatcherTest.h" />
<ClInclude Include="..\Classes\PerformanceTest\PerformanceLabelTest.h" />
<ClInclude Include="..\Classes\PhysicsTest\PhysicsTest.h" />
<ClInclude Include="..\Classes\ShaderTest\ShaderTest2.h" />
<ClInclude Include="..\Classes\SpineTest\SpineTest.h" />

View File

@ -709,6 +709,9 @@
<ClCompile Include="..\Classes\ConsoleTest\ConsoleTest.cpp">
<Filter>Classes\ConsoleTest</Filter>
</ClCompile>
<ClCompile Include="..\Classes\PerformanceTest\PerformanceLabelTest.cpp">
<Filter>Classes\PerformanceTest</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="main.h">
@ -1303,5 +1306,8 @@
<ClInclude Include="..\Classes\ConsoleTest\ConsoleTest.h">
<Filter>Classes\ConsoleTest</Filter>
</ClInclude>
<ClInclude Include="..\Classes\PerformanceTest\PerformanceLabelTest.h">
<Filter>Classes\PerformanceTest</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -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

View File

@ -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