diff --git a/cocos/2d/CCLabel.cpp b/cocos/2d/CCLabel.cpp index 448dc2c0b1..0b7a5f6dd5 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; + 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(_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)); + 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 bef78167a6..2e4ecea274 100644 --- a/cocos/2d/CCLabel.h +++ b/cocos/2d/CCLabel.h @@ -116,6 +116,7 @@ public: 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 @@ protected: Point position; Size contentSize; + int atlasIndex; }; enum class LabelType { @@ -282,7 +284,7 @@ protected: bool setOriginalString(unsigned short *stringToSet); void computeStringNumLines(); - void updateSpriteWithLetterDefinition(const FontLetterDefinition &theDefinition, Texture2D *theTexture); + void updateQuads(); virtual void updateColor() override; @@ -295,6 +297,8 @@ protected: 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 d95fcfcaf4..b35b0fe610 100644 --- a/cocos/2d/CCSpriteBatchNode.h +++ b/cocos/2d/CCSpriteBatchNode.h @@ -172,16 +172,16 @@ public: 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 c4f647dcfc..dbd963d0bd 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 6017b9e851..7ea2f570e3 100644 --- a/tests/cpp-tests/Classes/LabelTest/LabelTestNew.h +++ b/tests/cpp-tests/Classes/LabelTest/LabelTestNew.h @@ -484,6 +484,17 @@ private: 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