mirror of https://github.com/axmolengine/axmol.git
Merge pull request #4460 from Dhilan007/label_distanceField
new label:add support for distanceField
This commit is contained in:
commit
16ed9155c0
|
@ -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}
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<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,16 +110,20 @@ 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
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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<int>(_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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Sprite*>( 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<Sprite*>( child );
|
||||
item->updateDisplayedColor(_displayedColor);
|
||||
item->updateDisplayedColor(_displayedColor);
|
||||
});
|
||||
|
||||
V3F_C4B_T2F_Quad *quads = _textureAtlas->getQuads();
|
||||
|
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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__);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -138,6 +138,7 @@ set(COCOS2D_SRC
|
|||
platform/CCThread.cpp
|
||||
platform/CCEGLViewProtocol.cpp
|
||||
platform/CCFileUtils.cpp
|
||||
../../external/edtaa3func/edtaa3func.cpp
|
||||
)
|
||||
|
||||
include(../physics/CMakeLists.txt)
|
||||
|
|
|
@ -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\
|
||||
";
|
|
@ -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\
|
||||
";
|
|
@ -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\
|
||||
";
|
|
@ -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\
|
||||
";
|
|
@ -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\
|
||||
";
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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
|
|
@ -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__
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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]);
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue