From 67d2f79ab684a21e940de611aacb20de11ea1064 Mon Sep 17 00:00:00 2001 From: rh101 Date: Thu, 30 May 2019 18:59:47 +1000 Subject: [PATCH 1/4] Added RenderTexture::saveToFileAsNonPMA() to save images without PMA. Set the PMA parameter to true when calling initWithRawData() inside RenderTexture::newImage(), since textures are PMA. Renamed Image::premultipliedAlpha() to Image::premultiplyAlpha() to better reflect it's action, and made it public. Added Image::reversePremultipliedAlpha() to allow the reversing of the PMA. Updated CCImage-ios.mm to set the correct bitmapInfo for PMA and non-PMA images before saving a file. Updated RenderTextureTest::RenderTextureSave() to cater for non-PMA file saving. --- cocos/2d/CCRenderTexture.cpp | 50 ++++++++++++-- cocos/2d/CCRenderTexture.h | 27 +++++++- cocos/platform/CCImage.cpp | 27 +++++++- cocos/platform/CCImage.h | 4 +- cocos/platform/ios/CCImage-ios.mm | 9 ++- .../RenderTextureTest/RenderTextureTest.cpp | 65 ++++++++++++++++--- .../RenderTextureTest/RenderTextureTest.h | 6 +- 7 files changed, 168 insertions(+), 20 deletions(-) diff --git a/cocos/2d/CCRenderTexture.cpp b/cocos/2d/CCRenderTexture.cpp index fb63b9cac6cd..3b2b54a5d153 100644 --- a/cocos/2d/CCRenderTexture.cpp +++ b/cocos/2d/CCRenderTexture.cpp @@ -506,6 +506,28 @@ void RenderTexture::visit(Renderer *renderer, const Mat4 &parentTransform, uint3 // setOrderOfArrival(0); } +bool RenderTexture::saveToFileAsNonPMA(const std::string& filename, bool isRGBA, std::function callback) +{ + std::string basename(filename); + std::transform(basename.begin(), basename.end(), basename.begin(), ::tolower); + + if (basename.find(".png") != std::string::npos) + { + return saveToFileAsNonPMA(filename, Image::Format::PNG, isRGBA, callback); + } + else if (basename.find(".jpg") != std::string::npos) + { + if (isRGBA) CCLOG("RGBA is not supported for JPG format."); + return saveToFileAsNonPMA(filename, Image::Format::JPG, false, callback); + } + else + { + CCLOG("Only PNG and JPG format are supported now!"); + } + + return saveToFileAsNonPMA(filename, Image::Format::JPG, false, callback); +} + bool RenderTexture::saveToFile(const std::string& filename, bool isRGBA, std::function callback) { std::string basename(filename); @@ -528,6 +550,22 @@ bool RenderTexture::saveToFile(const std::string& filename, bool isRGBA, std::fu return saveToFile(filename, Image::Format::JPG, false, callback); } +bool RenderTexture::saveToFileAsNonPMA(const std::string& fileName, Image::Format format, bool isRGBA, std::function callback) +{ + CCASSERT(format == Image::Format::JPG || format == Image::Format::PNG, + "the image can only be saved as JPG or PNG format"); + if (isRGBA && format == Image::Format::JPG) CCLOG("RGBA is not supported for JPG format"); + + _saveFileCallback = callback; + + std::string fullpath = FileUtils::getInstance()->getWritablePath() + fileName; + _saveToFileCommand.init(_globalZOrder); + _saveToFileCommand.func = CC_CALLBACK_0(RenderTexture::onSaveToFile, this, fullpath, isRGBA, true); + + Director::getInstance()->getRenderer()->addCommand(&_saveToFileCommand); + return true; +} + bool RenderTexture::saveToFile(const std::string& fileName, Image::Format format, bool isRGBA, std::function callback) { CCASSERT(format == Image::Format::JPG || format == Image::Format::PNG, @@ -538,17 +576,21 @@ bool RenderTexture::saveToFile(const std::string& fileName, Image::Format format std::string fullpath = FileUtils::getInstance()->getWritablePath() + fileName; _saveToFileCommand.init(_globalZOrder); - _saveToFileCommand.func = CC_CALLBACK_0(RenderTexture::onSaveToFile, this, fullpath, isRGBA); + _saveToFileCommand.func = CC_CALLBACK_0(RenderTexture::onSaveToFile, this, fullpath, isRGBA, false); Director::getInstance()->getRenderer()->addCommand(&_saveToFileCommand); return true; } -void RenderTexture::onSaveToFile(const std::string& filename, bool isRGBA) +void RenderTexture::onSaveToFile(const std::string& filename, bool isRGBA, bool forceNonPMA) { Image *image = newImage(true); if (image) { + if (forceNonPMA && image->hasPremultipliedAlpha()) + { + image->reversePremultipliedAlpha(); + } image->saveToFile(filename, !isRGBA); } if(_saveFileCallback) @@ -620,11 +662,11 @@ Image* RenderTexture::newImage(bool flipImage) savedBufferWidth * 4); } - image->initWithRawData(buffer, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8); + image->initWithRawData(buffer, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8, true); } else { - image->initWithRawData(tempData, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8); + image->initWithRawData(tempData, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8, true); } } while (0); diff --git a/cocos/2d/CCRenderTexture.h b/cocos/2d/CCRenderTexture.h index 03a27ab334e4..771645501375 100644 --- a/cocos/2d/CCRenderTexture.h +++ b/cocos/2d/CCRenderTexture.h @@ -151,6 +151,17 @@ class CC_DLL RenderTexture : public Node CC_DEPRECATED_ATTRIBUTE Image* newCCImage(bool flipImage = true) { return newImage(flipImage); }; + /** Saves the texture into a file using JPEG format. The file will be saved in the Documents folder. + * Returns true if the operation is successful. + * + * @param filename The file name. + * @param isRGBA The file is RGBA or not. + * @param callback When the file is save finished,it will callback this function. + * @return Returns true if the operation is successful. + */ + bool saveToFileAsNonPMA(const std::string& filename, bool isRGBA = true, std::function callback = nullptr); + + /** Saves the texture into a file using JPEG format. The file will be saved in the Documents folder. * Returns true if the operation is successful. * @@ -161,6 +172,20 @@ class CC_DLL RenderTexture : public Node */ bool saveToFile(const std::string& filename, bool isRGBA = true, std::function callback = nullptr); + /** saves the texture into a file in non-PMA. The format could be JPG or PNG. The file will be saved in the Documents folder. + Returns true if the operation is successful. + * Notes: since v3.x, saveToFile will generate a custom command, which will be called in the following render->render(). + * So if this function is called in a event handler, the actual save file will be called in the next frame. If we switch to a different scene, the game will crash. + * To solve this, add Director::getInstance()->getRenderer()->render(); after this function. + * + * @param filename The file name. + * @param format The image format. + * @param isRGBA The file is RGBA or not. + * @param callback When the file is save finished,it will callback this function. + * @return Returns true if the operation is successful. + */ + bool saveToFileAsNonPMA(const std::string& fileName, Image::Format format, bool isRGBA, std::function callback); + /** saves the texture into a file. The format could be JPG or PNG. The file will be saved in the Documents folder. Returns true if the operation is successful. * Notes: since v3.x, saveToFile will generate a custom command, which will be called in the following render->render(). @@ -363,7 +388,7 @@ class CC_DLL RenderTexture : public Node void onClear(); void onClearDepth(); - void onSaveToFile(const std::string& fileName, bool isRGBA = true); + void onSaveToFile(const std::string& fileName, bool isRGBA = true, bool forceNonPMA = false); void setupDepthAndStencil(int powW, int powH); diff --git a/cocos/platform/CCImage.cpp b/cocos/platform/CCImage.cpp index 1ffb8e743462..eb01683400c0 100644 --- a/cocos/platform/CCImage.cpp +++ b/cocos/platform/CCImage.cpp @@ -1149,7 +1149,7 @@ bool Image::initWithPngData(const unsigned char * data, ssize_t dataLen) { if (PNG_PREMULTIPLIED_ALPHA_ENABLED) { - premultipliedAlpha(); + premultiplyAlpha(); } else { @@ -2454,7 +2454,7 @@ bool Image::saveImageToJPG(const std::string& filePath) #endif // CC_USE_JPEG } -void Image::premultipliedAlpha() +void Image::premultiplyAlpha() { #if CC_ENABLE_PREMULTIPLIED_ALPHA == 0 _hasPremultipliedAlpha = false; @@ -2473,6 +2473,29 @@ void Image::premultipliedAlpha() #endif } +static inline unsigned char clamp(int x) { + return (unsigned char)(x >= 0 ? (x < 255 ? x : 255) : 0); +} + +void Image::reversePremultipliedAlpha() +{ + CCASSERT(_renderFormat == Texture2D::PixelFormat::RGBA8888, "The pixel format should be RGBA8888!"); + + unsigned int* fourBytes = (unsigned int*)_data; + for (int i = 0; i < _width * _height; i++) + { + unsigned char* p = _data + i * 4; + if (p[3] > 0) + { + fourBytes[i] = clamp(int(std::ceil((p[0] * 255.0f) / p[3]))) | + clamp(int(std::ceil((p[1] * 255.0f) / p[3]))) << 8 | + clamp(int(std::ceil((p[2] * 255.0f) / p[3]))) << 16 | + p[3] << 24; + } + } + + _hasPremultipliedAlpha = false; +} void Image::setPVRImagesHavePremultipliedAlpha(bool haveAlphaPremultiplied) { diff --git a/cocos/platform/CCImage.h b/cocos/platform/CCImage.h index 6a7cebf20a53..a864944905fb 100644 --- a/cocos/platform/CCImage.h +++ b/cocos/platform/CCImage.h @@ -160,6 +160,8 @@ class CC_DLL Image : public Ref @param isToRGB whether the image is saved as RGB format. */ bool saveToFile(const std::string &filename, bool isToRGB = true); + void premultiplyAlpha(); + void reversePremultipliedAlpha(); protected: #if CC_USE_WIC @@ -182,8 +184,6 @@ class CC_DLL Image : public Ref bool saveImageToPNG(const std::string& filePath, bool isToRGB = true); bool saveImageToJPG(const std::string& filePath); - void premultipliedAlpha(); - protected: /** @brief Determine how many mipmaps can we have. diff --git a/cocos/platform/ios/CCImage-ios.mm b/cocos/platform/ios/CCImage-ios.mm index baad43f45aea..da0f1f7548fe 100644 --- a/cocos/platform/ios/CCImage-ios.mm +++ b/cocos/platform/ios/CCImage-ios.mm @@ -91,7 +91,14 @@ of this software and associated documentation files (the "Software"), to deal CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; if (saveToPNG && hasAlpha() && (! isToRGB)) { - bitmapInfo |= kCGImageAlphaPremultipliedLast; + if (_hasPremultipliedAlpha) + { + bitmapInfo |= kCGImageAlphaPremultipliedLast; + } + else + { + bitmapInfo |= kCGImageAlphaLast; + } } CGDataProviderRef provider = CGDataProviderCreateWithData(nullptr, pixels, myDataLength, nullptr); CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); diff --git a/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.cpp b/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.cpp index da772b0dfd55..d2775645c2e4 100644 --- a/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.cpp +++ b/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.cpp @@ -62,12 +62,15 @@ RenderTextureSave::RenderTextureSave() // Save Image menu MenuItemFont::setFontSize(16); - auto item1 = MenuItemFont::create("Save Image", CC_CALLBACK_1(RenderTextureSave::saveImage, this)); - auto item2 = MenuItemFont::create("Clear", CC_CALLBACK_1(RenderTextureSave::clearImage, this)); - auto menu = Menu::create(item1, item2, nullptr); + auto item1 = MenuItemFont::create("Save Image PMA", CC_CALLBACK_1(RenderTextureSave::saveImageWithPremultipliedAlpha, this)); + auto item2 = MenuItemFont::create("Save Image Non-PMA", CC_CALLBACK_1(RenderTextureSave::saveImageWithNonPremultipliedAlpha, this)); + auto item3 = MenuItemFont::create("Add Image", CC_CALLBACK_1(RenderTextureSave::addImage, this)); + auto item4 = MenuItemFont::create("Clear to Random", CC_CALLBACK_1(RenderTextureSave::clearImage, this)); + auto item5 = MenuItemFont::create("Clear to Transparent", CC_CALLBACK_1(RenderTextureSave::clearImageTransparent, this)); + auto menu = Menu::create(item1, item2, item3, item4, item5, nullptr); this->addChild(menu); menu->alignItemsVertically(); - menu->setPosition(Vec2(VisibleRect::rightTop().x - 80, VisibleRect::rightTop().y - 30)); + menu->setPosition(Vec2(VisibleRect::rightTop().x - 80, VisibleRect::rightTop().y - 100)); } std::string RenderTextureSave::title() const @@ -80,17 +83,46 @@ std::string RenderTextureSave::subtitle() const return "Press 'Save Image' to create an snapshot of the render texture"; } -void RenderTextureSave::clearImage(cocos2d::Ref *sender) +void RenderTextureSave::clearImage(cocos2d::Ref* sender) { _target->clear(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1()); } -void RenderTextureSave::saveImage(cocos2d::Ref *sender) +void RenderTextureSave::clearImageTransparent(cocos2d::Ref* sender) +{ + _target->clear(0, 0, 0, 0); +} + +void RenderTextureSave::saveImageWithPremultipliedAlpha(cocos2d::Ref* sender) +{ + static int counter = 0; + + char png[20]; + sprintf(png, "image-pma-%d.png", counter); + + auto callback = [&](RenderTexture* rt, const std::string& path) + { + auto sprite = Sprite::create(path); + addChild(sprite); + sprite->setScale(0.3f); + sprite->setPosition(Vec2(40, 40)); + sprite->setRotation(counter * 3); + }; + + _target->saveToFile(png, Image::Format::PNG, true, callback); + //Add this function to avoid crash if we switch to a new scene. + Director::getInstance()->getRenderer()->render(); + CCLOG("Image saved %s", png); + + counter++; +} + +void RenderTextureSave::saveImageWithNonPremultipliedAlpha(cocos2d::Ref *sender) { static int counter = 0; char png[20]; - sprintf(png, "image-%d.png", counter); + sprintf(png, "image-no-pma-%d.png", counter); auto callback = [&](RenderTexture* rt, const std::string& path) { @@ -101,7 +133,7 @@ void RenderTextureSave::saveImage(cocos2d::Ref *sender) sprite->setRotation(counter * 3); }; - _target->saveToFile(png, Image::Format::PNG, true, callback); + _target->saveToFileAsNonPMA(png, Image::Format::PNG, true, callback); //Add this function to avoid crash if we switch to a new scene. Director::getInstance()->getRenderer()->render(); CCLOG("Image saved %s", png); @@ -109,6 +141,21 @@ void RenderTextureSave::saveImage(cocos2d::Ref *sender) counter++; } +void RenderTextureSave::addImage(cocos2d::Ref* sender) +{ + auto s = Director::getInstance()->getWinSize(); + + // begin drawing to the render texture + _target->begin(); + + Sprite* sprite = Sprite::create("Images/test-rgba1.png"); + sprite->setPosition(sprite->getContentSize().width + CCRANDOM_0_1() * (s.width - sprite->getContentSize().width), sprite->getContentSize().height + CCRANDOM_0_1() * (s.height - sprite->getContentSize().height)); + sprite->visit(); + + // finish drawing and return context back to the screen + _target->end(); +} + RenderTextureSave::~RenderTextureSave() { _target->release(); @@ -849,4 +896,4 @@ std::string RenderTextureWithSprite3DIssue16894::title() const std::string RenderTextureWithSprite3DIssue16894::subtitle() const { return "3 ships, 1st & 3rd are the same"; -} +} \ No newline at end of file diff --git a/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.h b/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.h index 8d0940037b76..591e5ff8ff9c 100644 --- a/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.h +++ b/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.h @@ -44,7 +44,11 @@ class RenderTextureSave : public RenderTextureTest virtual std::string subtitle() const override; void onTouchesMoved(const std::vector& touches, cocos2d::Event* event); void clearImage(cocos2d::Ref* pSender); - void saveImage(cocos2d::Ref* pSender); + void clearImageTransparent(cocos2d::Ref* sender); + void saveImageWithPremultipliedAlpha(cocos2d::Ref* pSender); + void saveImageWithNonPremultipliedAlpha(cocos2d::Ref* pSender); + + void addImage(cocos2d::Ref* sender); private: cocos2d::RenderTexture* _target; From b5bdada7e2be3a87ba950c2c29756c06f0117ba3 Mon Sep 17 00:00:00 2001 From: rh101 Date: Tue, 4 Jun 2019 16:02:39 +1000 Subject: [PATCH 2/4] [CCImage-ios.mm] Fixed indentation. --- cocos/platform/ios/CCImage-ios.mm | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cocos/platform/ios/CCImage-ios.mm b/cocos/platform/ios/CCImage-ios.mm index da0f1f7548fe..ac6b04ed3f0b 100644 --- a/cocos/platform/ios/CCImage-ios.mm +++ b/cocos/platform/ios/CCImage-ios.mm @@ -91,14 +91,14 @@ of this software and associated documentation files (the "Software"), to deal CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; if (saveToPNG && hasAlpha() && (! isToRGB)) { - if (_hasPremultipliedAlpha) - { - bitmapInfo |= kCGImageAlphaPremultipliedLast; - } - else - { - bitmapInfo |= kCGImageAlphaLast; - } + if (_hasPremultipliedAlpha) + { + bitmapInfo |= kCGImageAlphaPremultipliedLast; + } + else + { + bitmapInfo |= kCGImageAlphaLast; + } } CGDataProviderRef provider = CGDataProviderCreateWithData(nullptr, pixels, myDataLength, nullptr); CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); From 58bbde43dae55a444d640da53c6381f01b2011d4 Mon Sep 17 00:00:00 2001 From: rh101 Date: Wed, 6 Nov 2019 19:32:57 +1100 Subject: [PATCH 3/4] [CCFontFNT.cpp/.h] Allow game to override FNT file parsing for extended formats. [CCFontAtlas] Added flag to indicated if a texture is rotated in FontLetterDefinition. This will allow for embedding a font atlas image inside a larger image atlas that supports rotation. [CCLabel.cpp] Ensure that the rotated flag in the font letter definition is used when creating a sprite for the letter. --- cocos/2d/CCFontAtlas.cpp | 2 + cocos/2d/CCFontAtlas.h | 1 + cocos/2d/CCFontCharMap.cpp | 1 + cocos/2d/CCFontFNT.cpp | 95 +-------------------------------- cocos/2d/CCFontFNT.h | 105 +++++++++++++++++++++++++++++++++++-- cocos/2d/CCLabel.cpp | 6 +-- 6 files changed, 109 insertions(+), 101 deletions(-) diff --git a/cocos/2d/CCFontAtlas.cpp b/cocos/2d/CCFontAtlas.cpp index 6256350abd8b..5f9e73c25712 100644 --- a/cocos/2d/CCFontAtlas.cpp +++ b/cocos/2d/CCFontAtlas.cpp @@ -436,6 +436,7 @@ bool FontAtlas::prepareLetterDefinitions(const std::u32string& utf32Text) tempDef.height = tempDef.height / scaleFactor; tempDef.U = tempDef.U / scaleFactor; tempDef.V = tempDef.V / scaleFactor; + tempDef.rotated = false; } else{ delete[] bitmap; @@ -451,6 +452,7 @@ bool FontAtlas::prepareLetterDefinitions(const std::u32string& utf32Text) tempDef.offsetX = 0; tempDef.offsetY = 0; tempDef.textureID = 0; + tempDef.rotated = false; _currentPageOrigX += 1; } diff --git a/cocos/2d/CCFontAtlas.h b/cocos/2d/CCFontAtlas.h index 5d05bcd13ba6..04ad3767a3b0 100644 --- a/cocos/2d/CCFontAtlas.h +++ b/cocos/2d/CCFontAtlas.h @@ -55,6 +55,7 @@ struct FontLetterDefinition int textureID; bool validDefinition; int xAdvance; + bool rotated; }; class CC_DLL FontAtlas : public Ref diff --git a/cocos/2d/CCFontCharMap.cpp b/cocos/2d/CCFontCharMap.cpp index ab958166aba4..2a1f14b27272 100644 --- a/cocos/2d/CCFontCharMap.cpp +++ b/cocos/2d/CCFontCharMap.cpp @@ -126,6 +126,7 @@ FontAtlas * FontCharMap::createFontAtlas() tempDefinition.width = _itemWidth / contentScaleFactor; tempDefinition.height = _itemHeight / contentScaleFactor; tempDefinition.xAdvance = _itemWidth; + tempDefinition.rotated = false; int charId = _mapStartChar; for (int row = 0; row < itemsPerColumn; ++row) diff --git a/cocos/2d/CCFontFNT.cpp b/cocos/2d/CCFontFNT.cpp index daa572081020..806750b3bbc1 100644 --- a/cocos/2d/CCFontFNT.cpp +++ b/cocos/2d/CCFontFNT.cpp @@ -52,99 +52,6 @@ enum { struct _FontDefHashElement; -/** -@struct BMFontDef -BMFont definition -*/ -typedef struct _BMFontDef { - //! ID of the character - unsigned int charID; - //! origin and size of the font - Rect rect; - //! The X amount the image should be offset when drawing the image (in pixels) - short xOffset; - //! The Y amount the image should be offset when drawing the image (in pixels) - short yOffset; - //! The amount to move the current position after drawing the character (in pixels) - short xAdvance; -} BMFontDef; - -/** @struct BMFontPadding -BMFont padding -@since v0.8.2 -*/ -typedef struct _BMFontPadding { - /// padding left - int left; - /// padding top - int top; - /// padding right - int right; - /// padding bottom - int bottom; -} BMFontPadding; - -/** @brief BMFontConfiguration has parsed configuration of the .fnt file -@since v0.8 -*/ -class CC_DLL BMFontConfiguration : public Ref -{ - // FIXME: Creating a public interface so that the bitmapFontArray[] is accessible -public://@public - // BMFont definitions - std::unordered_map _fontDefDictionary; - - //! FNTConfig: Common Height Should be signed (issue #1343) - int _commonHeight; - //! Padding - BMFontPadding _padding; - //! atlas name - std::string _atlasName; - //! values for kerning - std::unordered_map _kerningDictionary; - - // Character Set defines the letters that actually exist in the font - std::set *_characterSet; - //! Font Size - int _fontSize; -public: - /** - * @js ctor - */ - BMFontConfiguration(); - /** - * @js NA - * @lua NA - */ - virtual ~BMFontConfiguration(); - /** - * @js NA - * @lua NA - */ - std::string description() const; - - /** allocates a BMFontConfiguration with a FNT file */ - static BMFontConfiguration * create(const std::string& FNTfile); - - /** initializes a BitmapFontConfiguration with a FNT file */ - bool initWithFNTfile(const std::string& FNTfile); - - const std::string& getAtlasName() { return _atlasName; } - void setAtlasName(const std::string& atlasName) { _atlasName = atlasName; } - - std::set* getCharacterSet() const; -private: - std::set* parseConfigFile(const std::string& controlFile); - std::set* parseBinaryConfigFile(unsigned char* pData, unsigned long size, const std::string& controlFile); - unsigned int parseCharacterDefinition(const char* line); - void parseInfoArguments(const char* line); - void parseCommonArguments(const char* line); - void parseImageFileName(const char* line, const std::string& fntFile); - void parseKerningEntry(const char* line); - void purgeKerningDictionary(); - void purgeFontDefDictionary(); -}; - // //FNTConfig Cache - free functions // @@ -748,6 +655,8 @@ FontAtlas * FontFNT::createFontAtlas() tempDefinition.validDefinition = true; tempDefinition.xAdvance = fontDef.xAdvance; + tempDefinition.rotated = false; + // add the new definition if (65535 < fontDef.charID) { CCLOGWARN("Warning: 65535 < fontDef.charID (%u), ignored", fontDef.charID); diff --git a/cocos/2d/CCFontFNT.h b/cocos/2d/CCFontFNT.h index d0b932fd4f86..31ebdc9007aa 100644 --- a/cocos/2d/CCFontFNT.h +++ b/cocos/2d/CCFontFNT.h @@ -33,7 +33,101 @@ NS_CC_BEGIN -class BMFontConfiguration; +/** +@struct BMFontDef +BMFont definition +*/ +typedef struct _BMFontDef { + //! ID of the character + unsigned int charID; + //! origin and size of the font + Rect rect; + //! The X amount the image should be offset when drawing the image (in pixels) + short xOffset; + //! The Y amount the image should be offset when drawing the image (in pixels) + short yOffset; + //! The amount to move the current position after drawing the character (in pixels) + short xAdvance; +} BMFontDef; + +/** @struct BMFontPadding +BMFont padding +@since v0.8.2 +*/ +typedef struct _BMFontPadding { + /// padding left + int left; + /// padding top + int top; + /// padding right + int right; + /// padding bottom + int bottom; +} BMFontPadding; + +/** @brief BMFontConfiguration has parsed configuration of the .fnt file +@since v0.8 +*/ +class CC_DLL BMFontConfiguration : public Ref +{ + // FIXME: Creating a public interface so that the bitmapFontArray[] is accessible +public://@public + // BMFont definitions + std::unordered_map _fontDefDictionary; + + //! FNTConfig: Common Height Should be signed (issue #1343) + int _commonHeight; + //! Padding + BMFontPadding _padding; + //! atlas name + std::string _atlasName; + //! values for kerning + std::unordered_map _kerningDictionary; + + // Character Set defines the letters that actually exist in the font + std::set* _characterSet; + //! Font Size + int _fontSize; +public: + /** + * @js ctor + */ + BMFontConfiguration(); + /** + * @js NA + * @lua NA + */ + virtual ~BMFontConfiguration(); + /** + * @js NA + * @lua NA + */ + std::string description() const; + + /** allocates a BMFontConfiguration with a FNT file */ + static BMFontConfiguration* create(const std::string& FNTfile); + + /** initializes a BitmapFontConfiguration with a FNT file */ + bool initWithFNTfile(const std::string& FNTfile); + + const std::string& getAtlasName() { return _atlasName; } + void setAtlasName(const std::string& atlasName) { _atlasName = atlasName; } + + std::set* getCharacterSet() const; + +protected: + virtual std::set* parseConfigFile(const std::string& controlFile); + virtual std::set* parseBinaryConfigFile(unsigned char* pData, unsigned long size, const std::string& controlFile); + +private: + unsigned int parseCharacterDefinition(const char* line); + void parseInfoArguments(const char* line); + void parseCommonArguments(const char* line); + void parseImageFileName(const char* line, const std::string& fntFile); + void parseKerningEntry(const char* line); + void purgeKerningDictionary(); + void purgeFontDefDictionary(); +}; class CC_DLL FontFNT : public Font { @@ -47,7 +141,10 @@ class CC_DLL FontFNT : public Font static void purgeCachedData(); virtual int* getHorizontalKerningForTextUTF32(const std::u32string& text, int &outNumLetters) const override; virtual FontAtlas *createFontAtlas() override; + void setFontSize(float fontSize); + float getFontSize() const { return _fontSize; } + int getOriginalFontSize()const; static void reloadBMFontResource(const std::string& fntFilePath); @@ -60,12 +157,10 @@ class CC_DLL FontFNT : public Font * @lua NA */ virtual ~FontFNT(); - -private: - + + BMFontConfiguration* _configuration; int getHorizontalKerningForChars(char32_t firstChar, char32_t secondChar) const; - BMFontConfiguration * _configuration; Vec2 _imageOffset; //User defined font size float _fontSize; diff --git a/cocos/2d/CCLabel.cpp b/cocos/2d/CCLabel.cpp index fa2b2d2dd73d..e488bdec630d 100644 --- a/cocos/2d/CCLabel.cpp +++ b/cocos/2d/CCLabel.cpp @@ -790,7 +790,7 @@ void Label::updateLabelLetters() } else { - letterSprite->setTextureRect(uvRect, false, uvRect.size); + letterSprite->setTextureRect(uvRect, letterDef.rotated, uvRect.size); letterSprite->setTextureAtlas(_batchNodes.at(letterDef.textureID)->getTextureAtlas()); letterSprite->setAtlasIndex(_lettersInfo[letterIndex].atlasIndex); } @@ -971,7 +971,7 @@ bool Label::updateQuads() if (_reusedRect.size.height > 0.f && _reusedRect.size.width > 0.f) { - _reusedLetter->setTextureRect(_reusedRect, false, _reusedRect.size); + _reusedLetter->setTextureRect(_reusedRect, letterDef.rotated, _reusedRect.size); float letterPositionX = _lettersInfo[ctr].positionX + _linesOffsetX[_lettersInfo[ctr].lineIndex]; _reusedLetter->setPosition(letterPositionX, py); auto index = static_cast(_batchNodes.at(letterDef.textureID)->getTextureAtlas()->getTotalQuads()); @@ -1799,7 +1799,7 @@ Sprite* Label::getLetter(int letterIndex) else { this->updateBMFontScale(); - letter = LabelLetter::createWithTexture(_fontAtlas->getTexture(textureID), uvRect); + letter = LabelLetter::createWithTexture(_fontAtlas->getTexture(textureID), uvRect, letterDef.rotated); letter->setTextureAtlas(_batchNodes.at(textureID)->getTextureAtlas()); letter->setAtlasIndex(letterInfo.atlasIndex); auto px = letterInfo.positionX + _bmfontScale * uvRect.size.width / 2 + _linesOffsetX[letterInfo.lineIndex]; From 75664c99523f4c613ec49ba80e14aee63e44c69c Mon Sep 17 00:00:00 2001 From: rh101 Date: Wed, 6 Nov 2019 21:58:29 +1100 Subject: [PATCH 4/4] [CCFontFNT.h] Fixed missing include statements. --- cocos/2d/CCFontFNT.cpp | 2 -- cocos/2d/CCFontFNT.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cocos/2d/CCFontFNT.cpp b/cocos/2d/CCFontFNT.cpp index 806750b3bbc1..ec8e43f45764 100644 --- a/cocos/2d/CCFontFNT.cpp +++ b/cocos/2d/CCFontFNT.cpp @@ -34,8 +34,6 @@ #include "renderer/CCTextureCache.h" #include -#include -#include NS_CC_BEGIN diff --git a/cocos/2d/CCFontFNT.h b/cocos/2d/CCFontFNT.h index 31ebdc9007aa..457de4a5f114 100644 --- a/cocos/2d/CCFontFNT.h +++ b/cocos/2d/CCFontFNT.h @@ -30,6 +30,8 @@ /// @cond DO_NOT_SHOW #include "2d/CCFont.h" +#include +#include NS_CC_BEGIN