diff --git a/cocos/2d/CCLabel.cpp b/cocos/2d/CCLabel.cpp index 448dc2c0b1e1..0b7a5f6dd5a5 100644 --- a/cocos/2d/CCLabel.cpp +++ b/cocos/2d/CCLabel.cpp @@ -446,7 +446,7 @@ bool Label::setBMFontFilePath(const std::string& bmfontFilePath, const Point& im reset(); return false; } - + _bmFontPath = bmfontFilePath; setFontAtlas(newAtlas); _currentLabelType = LabelType::BMFONT; @@ -624,17 +624,7 @@ void Label::alignText() } } - int index; - for (int ctr = 0; ctr < _limitShowCount; ++ctr) - { - if (_lettersInfo[ctr].def.validDefinition) - { - updateSpriteWithLetterDefinition(_lettersInfo[ctr].def,textures[_lettersInfo[ctr].def.textureID]); - _reusedLetter->setPosition(_lettersInfo[ctr].position); - index = _batchNodes[_lettersInfo[ctr].def.textureID]->getTextureAtlas()->getTotalQuads(); - _batchNodes[_lettersInfo[ctr].def.textureID]->insertQuadFromSprite(_reusedLetter,index); - } - } + updateQuads(); updateColor(); } @@ -691,16 +681,30 @@ bool Label::setCurrentString(unsigned short *stringToSet) return true; } -void Label::updateSpriteWithLetterDefinition(const FontLetterDefinition &theDefinition, Texture2D *theTexture) +void Label::updateQuads() { - _reusedRect.size.height = theDefinition.height; - _reusedRect.size.width = theDefinition.width; - _reusedRect.origin.x = theDefinition.U; - _reusedRect.origin.y = theDefinition.V; + int index; + for (int ctr = 0; ctr < _limitShowCount; ++ctr) + { + auto &letterDef = _lettersInfo[ctr].def; - if(_reusedLetter->getBatchNode() != _batchNodes[theDefinition.textureID]) - _reusedLetter->setBatchNode(_batchNodes[theDefinition.textureID]); - _reusedLetter->setTextureRect(_reusedRect,false,_reusedRect.size); + if (letterDef.validDefinition) + { + _reusedRect.size.height = letterDef.height; + _reusedRect.size.width = letterDef.width; + _reusedRect.origin.x = letterDef.U; + _reusedRect.origin.y = letterDef.V; + + if(_reusedLetter->getBatchNode() != _batchNodes[letterDef.textureID]) + _reusedLetter->setBatchNode(_batchNodes[letterDef.textureID]); + _reusedLetter->setTextureRect(_reusedRect,false,_reusedRect.size); + + _reusedLetter->setPosition(_lettersInfo[ctr].position); + index = _batchNodes[letterDef.textureID]->getTextureAtlas()->getTotalQuads(); + _lettersInfo[ctr].atlasIndex = index; + _batchNodes[letterDef.textureID]->insertQuadFromSprite(_reusedLetter,index); + } + } } bool Label::recordLetterInfo(const cocos2d::Point& point,const FontLetterDefinition& letterDef, int spriteIndex) @@ -1054,35 +1058,41 @@ int Label::getFontSize() const } ///// PROTOCOL STUFF -Sprite * Label::getLetter(int lettetIndex) +Sprite * Label::getLetter(int letterIndex) { + if (_fontDirty) + { + updateFont(); + } if (_contentDirty) { updateContent(); } - if (! _textSprite && lettetIndex < _limitShowCount) + if (! _textSprite && letterIndex < _limitShowCount) { - if(! _lettersInfo[lettetIndex].def.validDefinition) + const auto &letter = _lettersInfo[letterIndex]; + + if(! letter.def.validDefinition) return nullptr; - Sprite* sp = static_cast(this->getChildByTag(lettetIndex)); + Sprite* sp = static_cast(this->getChildByTag(letterIndex)); if (!sp) { Rect uvRect; - uvRect.size.height = _lettersInfo[lettetIndex].def.height; - uvRect.size.width = _lettersInfo[lettetIndex].def.width; - uvRect.origin.x = _lettersInfo[lettetIndex].def.U; - uvRect.origin.y = _lettersInfo[lettetIndex].def.V; - - sp = Sprite::createWithTexture(_fontAtlas->getTexture(_lettersInfo[lettetIndex].def.textureID),uvRect); - sp->setBatchNode(this); - sp->setAnchorPoint(Point::ANCHOR_MIDDLE); - sp->setPosition(Point(_lettersInfo[lettetIndex].position.x+uvRect.size.width/2,_lettersInfo[lettetIndex].position.y-uvRect.size.height/2)); + uvRect.size.height = letter.def.height; + uvRect.size.width = letter.def.width; + uvRect.origin.x = letter.def.U; + uvRect.origin.y = letter.def.V; + + sp = Sprite::createWithTexture(_fontAtlas->getTexture(letter.def.textureID),uvRect); + sp->setBatchNode(_batchNodes[letter.def.textureID]); + sp->setPosition(Point(letter.position.x + uvRect.size.width / 2, + letter.position.y - uvRect.size.height / 2)); sp->setOpacity(_realOpacity); - this->addSpriteWithoutQuad(sp, lettetIndex, lettetIndex); + _batchNodes[letter.def.textureID]->addSpriteWithoutQuad(sp, letter.atlasIndex, letterIndex); } return sp; } @@ -1120,7 +1130,7 @@ void Label::computeStringNumLines() int Label::getStringLength() const { - return _currentUTF16String ? cc_wcslen(_currentUTF16String) : 0; + return _currentUTF16String ? cc_wcslen(_currentUTF16String) : _originalUTF8String.length(); } // RGBA protocol diff --git a/cocos/2d/CCLabel.h b/cocos/2d/CCLabel.h index bef78167a667..2e4ecea274e0 100644 --- a/cocos/2d/CCLabel.h +++ b/cocos/2d/CCLabel.h @@ -116,6 +116,7 @@ class CC_DLL Label : public SpriteBatchNode, public LabelProtocol virtual bool setTTFConfig(const TTFConfig& ttfConfig); virtual bool setBMFontFilePath(const std::string& bmfontFilePath, const Point& imageOffset = Point::ZERO); + const std::string& getBMFontFilePath() const { return _bmFontPath;} virtual bool setCharMap(const std::string& charMapFile, int itemWidth, int itemHeight, int startCharMap); virtual bool setCharMap(Texture2D* texture, int itemWidth, int itemHeight, int startCharMap); @@ -248,6 +249,7 @@ class CC_DLL Label : public SpriteBatchNode, public LabelProtocol Point position; Size contentSize; + int atlasIndex; }; enum class LabelType { @@ -282,7 +284,7 @@ class CC_DLL Label : public SpriteBatchNode, public LabelProtocol bool setOriginalString(unsigned short *stringToSet); void computeStringNumLines(); - void updateSpriteWithLetterDefinition(const FontLetterDefinition &theDefinition, Texture2D *theTexture); + void updateQuads(); virtual void updateColor() override; @@ -295,6 +297,8 @@ class CC_DLL Label : public SpriteBatchNode, public LabelProtocol void updateFont(); void reset(); + std::string _bmFontPath; + bool _isOpacityModifyRGB; bool _contentDirty; bool _fontDirty; diff --git a/cocos/2d/CCSpriteBatchNode.h b/cocos/2d/CCSpriteBatchNode.h index d95fcfcaf4bd..b35b0fe61002 100644 --- a/cocos/2d/CCSpriteBatchNode.h +++ b/cocos/2d/CCSpriteBatchNode.h @@ -172,16 +172,16 @@ class CC_DLL SpriteBatchNode : public Node, public TextureProtocol For example: a tile map (TMXMap) or a label with lots of characters (LabelBMFont) */ void insertQuadFromSprite(Sprite *sprite, ssize_t index); + /* This is the opposite of "addQuadFromSprite. + It add the sprite to the children and descendants array, but it doesn't update add it to the texture atlas + */ + SpriteBatchNode * addSpriteWithoutQuad(Sprite *child, int z, int aTag); protected: /** Updates a quad at a certain index into the texture atlas. The Sprite won't be added into the children array. This method should be called only when you are dealing with very big AtlasSrite and when most of the Sprite won't be updated. For example: a tile map (TMXMap) or a label with lots of characters (LabelBMFont) */ - void updateQuadFromSprite(Sprite *sprite, ssize_t index); - /* This is the opposite of "addQuadFromSprite. - It add the sprite to the children and descendants array, but it doesn't update add it to the texture atlas - */ - SpriteBatchNode * addSpriteWithoutQuad(Sprite *child, int z, int aTag); + void updateQuadFromSprite(Sprite *sprite, ssize_t index); void updateAtlasIndex(Sprite* sprite, ssize_t* curIndex); void swap(ssize_t oldIndex, ssize_t newIndex); diff --git a/tests/cpp-tests/Classes/LabelTest/LabelTestNew.cpp b/tests/cpp-tests/Classes/LabelTest/LabelTestNew.cpp index c4f647dcfc92..dbd963d0bdec 100644 --- a/tests/cpp-tests/Classes/LabelTest/LabelTestNew.cpp +++ b/tests/cpp-tests/Classes/LabelTest/LabelTestNew.cpp @@ -77,7 +77,8 @@ static std::function createFunctions[] = CL(LabelCrashTest), CL(LabelTTFOldNew), CL(LabelFontNameTest), - CL(LabelAlignmentTest) + CL(LabelAlignmentTest), + CL(LabelIssue4428Test) }; #define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0])) @@ -1779,3 +1780,33 @@ std::string LabelAlignmentTest::subtitle() const { return "Select the buttons on the sides to change alignment"; } + +LabelIssue4428Test::LabelIssue4428Test() +{ + auto size = Director::getInstance()->getWinSize(); + + auto label = Label::createWithBMFont( "fonts/bitmapFontTest3.fnt", "123\n456"); + label->setPosition(Point(size.width /2.0f, size.height / 2.0f)); + label->setAnchorPoint(Point::ANCHOR_BOTTOM_LEFT); + addChild(label); + + int len = label->getStringLength(); + for (int i = 0; i < len; ++i) + { + auto sprite = label->getLetter(i); + if (sprite != nullptr) + { + sprite->setFlippedY(true); + } + } +} + +std::string LabelIssue4428Test::title() const +{ + return "New Label Bugs Test"; +} + +std::string LabelIssue4428Test::subtitle() const +{ + return "Reorder issue #4428.The label should be flipped vertically."; +} diff --git a/tests/cpp-tests/Classes/LabelTest/LabelTestNew.h b/tests/cpp-tests/Classes/LabelTest/LabelTestNew.h index 6017b9e8516a..7ea2f570e3cd 100644 --- a/tests/cpp-tests/Classes/LabelTest/LabelTestNew.h +++ b/tests/cpp-tests/Classes/LabelTest/LabelTestNew.h @@ -484,6 +484,17 @@ class LabelAlignmentTest : public AtlasDemoNew TextVAlignment _vertAlign; }; +class LabelIssue4428Test : public AtlasDemoNew +{ +public: + CREATE_FUNC(LabelIssue4428Test); + + LabelIssue4428Test(); + + virtual std::string title() const override; + virtual std::string subtitle() const override; +}; + // we don't support linebreak mode #endif