From 158d96046e8c0fc734b0b38c5f352980382b5936 Mon Sep 17 00:00:00 2001 From: WenhaiLin Date: Tue, 7 Jul 2015 14:20:23 +0800 Subject: [PATCH] Label:Support add child nodes. --- cocos/2d/CCLabel.cpp | 622 ++++++++++++++++++++++++++----------------- cocos/2d/CCLabel.h | 23 +- 2 files changed, 396 insertions(+), 249 deletions(-) diff --git a/cocos/2d/CCLabel.cpp b/cocos/2d/CCLabel.cpp index 82459e063e..c847a0d36a 100644 --- a/cocos/2d/CCLabel.cpp +++ b/cocos/2d/CCLabel.cpp @@ -42,6 +42,102 @@ NS_CC_BEGIN const int Label::DistanceFieldFontSize = 50; +class LabelLetter : public Sprite +{ +#if CC_SPRITEBATCHNODE_RENDER_SUBPIXEL +#define RENDER_IN_SUBPIXEL +#else +#define RENDER_IN_SUBPIXEL(__ARGS__) (ceil(__ARGS__)) +#endif + +public: + LabelLetter() + { + _textureAtlas = nullptr; + } + + static LabelLetter* createWithTexture(Texture2D *texture, const Rect& rect, bool rotated = false) + { + auto letter = new (std::nothrow) LabelLetter(); + if (letter && letter->initWithTexture(texture, rect, rotated)) + { + letter->setVisible(false); + letter->autorelease(); + return letter; + } + CC_SAFE_DELETE(letter); + return nullptr; + } + + virtual void updateTransform() override + { + if (isDirty()) + { + _transformToBatch = getNodeToParentTransform(); + Size &size = _rect.size; + + float x1 = _offsetPosition.x; + float y1 = _offsetPosition.y; + float x2 = x1 + size.width; + float y2 = y1 + size.height; + float x = _transformToBatch.m[12]; + float y = _transformToBatch.m[13]; + + float cr = _transformToBatch.m[0]; + float sr = _transformToBatch.m[1]; + float cr2 = _transformToBatch.m[5]; + float sr2 = -_transformToBatch.m[4]; + float ax = x1 * cr - y1 * sr2 + x; + float ay = x1 * sr + y1 * cr2 + y; + + float bx = x2 * cr - y1 * sr2 + x; + float by = x2 * sr + y1 * cr2 + y; + float cx = x2 * cr - y2 * sr2 + x; + float cy = x2 * sr + y2 * cr2 + y; + float dx = x1 * cr - y2 * sr2 + x; + float dy = x1 * sr + y2 * cr2 + y; + + _quad.bl.vertices.set(RENDER_IN_SUBPIXEL(ax), RENDER_IN_SUBPIXEL(ay), _positionZ); + _quad.br.vertices.set(RENDER_IN_SUBPIXEL(bx), RENDER_IN_SUBPIXEL(by), _positionZ); + _quad.tl.vertices.set(RENDER_IN_SUBPIXEL(dx), RENDER_IN_SUBPIXEL(dy), _positionZ); + _quad.tr.vertices.set(RENDER_IN_SUBPIXEL(cx), RENDER_IN_SUBPIXEL(cy), _positionZ); + + if (_textureAtlas) + { + _textureAtlas->updateQuad(&_quad, _atlasIndex); + } + + _recursiveDirty = false; + setDirty(false); + } + + Node::updateTransform(); + } + + virtual void updateColor() + { + if (_textureAtlas == nullptr) + { + return; + } + + Color4B color4(_displayedColor.r, _displayedColor.g, _displayedColor.b, _displayedOpacity); + // special opacity for premultiplied textures + if (_opacityModifyRGB) + { + color4.r *= _displayedOpacity / 255.0f; + color4.g *= _displayedOpacity / 255.0f; + color4.b *= _displayedOpacity / 255.0f; + } + _quad.bl.colors = color4; + _quad.br.colors = color4; + _quad.tl.colors = color4; + _quad.tr.colors = color4; + + _textureAtlas->updateQuad(&_quad, _atlasIndex); + } +}; + Label* Label::create() { auto ret = new (std::nothrow) Label(); @@ -257,6 +353,7 @@ Label::Label(FontAtlas *atlas /* = nullptr */, TextHAlignment hAlignment /* = Te , _effectColorF(Color4F::BLACK) , _uniformEffectColor(0) , _shadowDirty(false) +, _blendFunc(BlendFunc::ALPHA_PREMULTIPLIED) , _insideBounds(true) { setAnchorPoint(Vec2::ANCHOR_MIDDLE); @@ -265,9 +362,11 @@ Label::Label(FontAtlas *atlas /* = nullptr */, TextHAlignment hAlignment /* = Te _purgeTextureListener = EventListenerCustom::create(FontAtlas::CMD_PURGE_FONTATLAS, [this](EventCustom* event){ if (_fontAtlas && _currentLabelType == LabelType::TTF && event->getUserData() == _fontAtlas) { - Node::removeAllChildrenWithCleanup(true); + for (auto it : _letters) + { + it.second->setTexture(nullptr); + } _batchNodes.clear(); - _batchNodes.push_back(this); if (_fontAtlas) { @@ -282,6 +381,10 @@ Label::Label(FontAtlas *atlas /* = nullptr */, TextHAlignment hAlignment /* = Te { _fontAtlas = nullptr; this->setTTFConfig(_fontConfig); + for (auto it : _letters) + { + getLetter(it.first); + } } }); _eventDispatcher->addEventListenerWithFixedPriority(_resetTextureListener, 2); @@ -299,6 +402,8 @@ Label::~Label() _eventDispatcher->removeEventListener(_resetTextureListener); CC_SAFE_RELEASE_NULL(_reusedLetter); + CC_SAFE_RELEASE_NULL(_textSprite); + CC_SAFE_RELEASE_NULL(_shadowNode); } void Label::reset() @@ -311,7 +416,6 @@ void Label::reset() _systemFontSize = 12; _batchNodes.clear(); - _batchNodes.push_back(this); if (_fontAtlas) { @@ -384,16 +488,6 @@ void Label::setFontAtlas(FontAtlas* atlas,bool distanceFieldEnabled /* = false * } _fontAtlas = atlas; - - if (_textureAtlas) - { - _textureAtlas->setTexture(_fontAtlas->getTexture(0)); - } - else - { - SpriteBatchNode::initWithTexture(_fontAtlas->getTexture(0), 30); - } - if (_reusedLetter == nullptr) { _reusedLetter = Sprite::create(); @@ -401,7 +495,6 @@ void Label::setFontAtlas(FontAtlas* atlas,bool distanceFieldEnabled /* = false * _reusedLetter->retain(); _reusedLetter->setAnchorPoint(Vec2::ANCHOR_TOP_LEFT); } - _reusedLetter->setBatchNode(this); if (_fontAtlas) { @@ -594,12 +687,21 @@ void Label::alignText() for (auto index = _batchNodes.size(); index < textures.size(); ++index) { auto batchNode = SpriteBatchNode::createWithTexture(textures.at(index)); - batchNode->setAnchorPoint(Vec2::ANCHOR_TOP_LEFT); - batchNode->setPosition(Vec2::ZERO); - Node::addChild(batchNode,0,Node::INVALID_TAG); - _batchNodes.push_back(batchNode); + if (batchNode) + { + _blendFunc = batchNode->getBlendFunc(); + batchNode->setAnchorPoint(Vec2::ANCHOR_TOP_LEFT); + batchNode->setPosition(Vec2::ZERO); + _batchNodes.pushBack(batchNode); + } } } + if (_batchNodes.empty()) + { + return; + } + _reusedLetter->setBatchNode(_batchNodes.at(0)); + LabelTextFormatter::createStringSprites(this); if(_maxLineWidth > 0 && _contentSize.width > _maxLineWidth && LabelTextFormatter::multilineText(this) ) LabelTextFormatter::createStringSprites(this); @@ -607,39 +709,36 @@ void Label::alignText() if(_labelWidth > 0 || (_currNumLines > 1 && _hAlignment != TextHAlignment::LEFT)) LabelTextFormatter::alignText(this); - if (!_children.empty()) + if (!_letters.empty()) { - int strLen = static_cast(_currentUTF16String.length()); Rect uvRect; Sprite* letterSprite; - for (auto index = 0; index < _children.size();) { - auto child = _children.at(index); - int tag = child->getTag(); - if (tag >= strLen) + int letterIndex; + + for (auto it = _letters.begin(); it != _letters.end();) + { + letterIndex = it->first; + letterSprite = it->second; + + if (letterIndex >= _limitShowCount) { - child->removeFromParentAndCleanup(true); - } - else if (tag >= 0) - { - letterSprite = dynamic_cast(child); - if (letterSprite) - { - auto& letterDef = _lettersInfo[tag].def; - uvRect.size.height = letterDef.height; - uvRect.size.width = letterDef.width; - uvRect.origin.x = letterDef.U; - uvRect.origin.y = letterDef.V; - - letterSprite->setBatchNode(_batchNodes[letterDef.textureID]); - letterSprite->setTextureRect(uvRect, false, uvRect.size); - letterSprite->setPosition(_lettersInfo[tag].position.x + letterDef.width/2, - _lettersInfo[tag].position.y - letterDef.height/2); - } - ++index; + Node::removeChild(letterSprite, true); + it = _letters.erase(it); } else { - ++index; + auto& letterDef = _lettersInfo[letterIndex].def; + uvRect.size.height = letterDef.height; + uvRect.size.width = letterDef.width; + uvRect.origin.x = letterDef.U; + uvRect.origin.y = letterDef.V; + + letterSprite->setBatchNode(_batchNodes.at(letterDef.textureID)); + letterSprite->setTextureRect(uvRect, false, uvRect.size); + letterSprite->setPosition(_lettersInfo[letterIndex].position.x + letterDef.width / 2, + _lettersInfo[letterIndex].position.y - letterDef.height / 2); + + ++it; } } } @@ -700,9 +799,9 @@ void Label::updateQuads() _reusedLetter->setTextureRect(_reusedRect,false,_reusedRect.size); _reusedLetter->setPosition(_lettersInfo[ctr].position); - index = static_cast(_batchNodes[letterDef.textureID]->getTextureAtlas()->getTotalQuads()); + index = static_cast(_batchNodes.at(letterDef.textureID)->getTextureAtlas()->getTotalQuads()); _lettersInfo[ctr].atlasIndex = index; - _batchNodes[letterDef.textureID]->insertQuadFromSprite(_reusedLetter,index); + _batchNodes.at(letterDef.textureID)->insertQuadFromSprite(_reusedLetter,index); } } } @@ -738,16 +837,6 @@ bool Label::recordPlaceholderInfo(int spriteIndex) return false; } -void Label::addChild(Node * child, int zOrder/* =0 */, int tag/* =0 */) -{ - CCASSERT(0, "addChild: is not supported on Label."); -} - -void Label::sortAllChildren() -{ - // Label ignore sort children -} - void Label::enableGlow(const Color4B& glowColor) { if (_currentLabelType == LabelType::TTF) @@ -821,7 +910,7 @@ void Label::enableShadow(const Color4B& shadowColor /* = Color4B::BLACK */,const { if (shadowColor != _shadowColor4F) { - Node::removeChild(_shadowNode, true); + _shadowNode->release(); _shadowNode = nullptr; createShadowSpriteForSystemFont(); } @@ -872,11 +961,7 @@ void Label::disableEffect(LabelEffect effect) if (_shadowEnabled) { _shadowEnabled = false; - if (_shadowNode) - { - Node::removeChild(_shadowNode, true); - _shadowNode = nullptr; - } + CC_SAFE_RELEASE_NULL(_shadowNode); } break; case cocos2d::LabelEffect::GLOW: @@ -904,121 +989,6 @@ void Label::setFontScale(float fontScale) Node::setScale(_fontScale); } -void Label::onDraw(const Mat4& transform, bool transformUpdated) -{ - // Optimization: Fast Dispatch - if( _textureAtlas == NULL || (_batchNodes.size() == 1 && _textureAtlas->getTotalQuads() == 0) ) - { - return; - } - - auto glprogram = getGLProgram(); - glprogram->use(); - GL::blendFunc( _blendFunc.src, _blendFunc.dst ); - - if (_shadowEnabled) - { - if (_currentLabelType == LabelType::TTF) - { - glprogram->setUniformLocationWith4f(_uniformTextColor, - _shadowColor4F.r, _shadowColor4F.g, _shadowColor4F.b, _shadowColor4F.a); - if (_currLabelEffect == LabelEffect::OUTLINE || _currLabelEffect == LabelEffect::GLOW) - { - glprogram->setUniformLocationWith4f(_uniformEffectColor, - _shadowColor4F.r, _shadowColor4F.g, _shadowColor4F.b, _shadowColor4F.a); - } - - getGLProgram()->setUniformsForBuiltins(_shadowTransform); - for (const auto &child : _children) - { - child->updateTransform(); - } - for (const auto& batchNode : _batchNodes) - { - batchNode->getTextureAtlas()->drawQuads(); - } - } - else - { - Color3B oldColor = _realColor; - GLubyte oldOPacity = _displayedOpacity; - _displayedOpacity = _shadowOpacity; - setColor(_shadowColor3B); - - getGLProgram()->setUniformsForBuiltins(_shadowTransform); - for (const auto &child : _children) - { - child->updateTransform(); - } - for (const auto& batchNode : _batchNodes) - { - batchNode->getTextureAtlas()->drawQuads(); - } - - _displayedOpacity = oldOPacity; - setColor(oldColor); - } - } - - glprogram->setUniformsForBuiltins(transform); - for(const auto &child: _children) - { - child->updateTransform(); - } - - if (_currentLabelType == LabelType::TTF) - { - switch (_currLabelEffect) { - case LabelEffect::OUTLINE: - //draw text with outline - glprogram->setUniformLocationWith4f(_uniformTextColor, - _textColorF.r,_textColorF.g,_textColorF.b,_textColorF.a); - glprogram->setUniformLocationWith4f(_uniformEffectColor, - _effectColorF.r, _effectColorF.g, _effectColorF.b, _effectColorF.a); - for (const auto& batchNode:_batchNodes) - { - batchNode->getTextureAtlas()->drawQuads(); - } - - //draw text without outline - glprogram->setUniformLocationWith4f(_uniformEffectColor, - _effectColorF.r, _effectColorF.g, _effectColorF.b, 0.f); - break; - case LabelEffect::GLOW: - glprogram->setUniformLocationWith4f(_uniformEffectColor, - _effectColorF.r, _effectColorF.g, _effectColorF.b, _effectColorF.a); - case LabelEffect::NORMAL: - glprogram->setUniformLocationWith4f(_uniformTextColor, - _textColorF.r,_textColorF.g,_textColorF.b,_textColorF.a); - break; - default: - break; - } - } - - for (const auto& batchNode:_batchNodes) - { - batchNode->getTextureAtlas()->drawQuads(); - } -} - -void Label::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) -{ - // Don't do calculate the culling if the transform was not updated - bool transformUpdated = flags & FLAGS_TRANSFORM_DIRTY; -#if CC_USE_CULLING - _insideBounds = transformUpdated ? renderer->checkVisibility(transform, _contentSize) : _insideBounds; - - if(_insideBounds) -#endif - { - _customCommand.init(_globalZOrder, transform, flags); - _customCommand.func = CC_CALLBACK_0(Label::onDraw, this, transform, transformUpdated); - - renderer->addCommand(&_customCommand); - } -} - void Label::createSpriteForSystemFont() { _currentLabelType = LabelType::STRING_TEXTURE; @@ -1078,8 +1048,7 @@ void Label::createSpriteForSystemFont() _textSprite->setBlendFunc(_blendFunc); } - Node::addChild(_textSprite, 0, Node::INVALID_TAG); - + _textSprite->retain(); _textSprite->updateDisplayedColor(_displayedColor); _textSprite->updateDisplayedOpacity(_displayedOpacity); } @@ -1117,8 +1086,8 @@ void Label::createShadowSpriteForSystemFont() _shadowNode->setCameraMask(getCameraMask()); _shadowNode->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT); _shadowNode->setPosition(_shadowOffset.width, _shadowOffset.height); - Node::addChild(_shadowNode, 0, Node::INVALID_TAG); + _shadowNode->retain(); _shadowNode->updateDisplayedColor(_displayedColor); _shadowNode->updateDisplayedOpacity(_displayedOpacity); } @@ -1126,7 +1095,7 @@ void Label::createShadowSpriteForSystemFont() void Label::setCameraMask(unsigned short mask, bool applyChildren) { - SpriteBatchNode::setCameraMask(mask, applyChildren); + Node::setCameraMask(mask, applyChildren); if (_textSprite) { @@ -1163,7 +1132,6 @@ void Label::updateContent() if (_fontAtlas) { _batchNodes.clear(); - _batchNodes.push_back(this); FontAtlasCache::releaseFontAtlas(_fontAtlas); _fontAtlas = nullptr; @@ -1172,16 +1140,8 @@ void Label::updateContent() _systemFontDirty = false; } - if (_textSprite) - { - Node::removeChild(_textSprite, true); - _textSprite = nullptr; - if (_shadowNode) - { - Node::removeChild(_shadowNode, true); - _shadowNode = nullptr; - } - } + CC_SAFE_RELEASE_NULL(_textSprite); + CC_SAFE_RELEASE_NULL(_shadowNode); if (_fontAtlas) { @@ -1206,9 +1166,123 @@ void Label::updateContent() _contentDirty = false; } +void Label::onDraw(const Mat4& transform, bool transformUpdated) +{ + if (_batchNodes.empty() || _limitShowCount <= 0) + { + return; + } + + auto glprogram = getGLProgram(); + glprogram->use(); + GL::blendFunc(_blendFunc.src, _blendFunc.dst); + + if (_shadowEnabled) + { + if (_currentLabelType == LabelType::TTF) + { + glprogram->setUniformLocationWith4f(_uniformTextColor, + _shadowColor4F.r, _shadowColor4F.g, _shadowColor4F.b, _shadowColor4F.a); + if (_currLabelEffect == LabelEffect::OUTLINE || _currLabelEffect == LabelEffect::GLOW) + { + glprogram->setUniformLocationWith4f(_uniformEffectColor, + _shadowColor4F.r, _shadowColor4F.g, _shadowColor4F.b, _shadowColor4F.a); + } + + getGLProgram()->setUniformsForBuiltins(_shadowTransform); + for (auto it : _letters) + { + it.second->updateTransform(); + } + for (const auto& batchNode : _batchNodes) + { + batchNode->getTextureAtlas()->drawQuads(); + } + } + else + { + Color3B oldColor = _realColor; + GLubyte oldOPacity = _displayedOpacity; + _displayedOpacity = _shadowOpacity; + setColor(_shadowColor3B); + + getGLProgram()->setUniformsForBuiltins(_shadowTransform); + for (auto it : _letters) + { + it.second->updateTransform(); + } + for (const auto& batchNode : _batchNodes) + { + batchNode->getTextureAtlas()->drawQuads(); + } + + _displayedOpacity = oldOPacity; + setColor(oldColor); + } + } + + glprogram->setUniformsForBuiltins(transform); + for (auto it : _letters) + { + it.second->updateTransform(); + } + + if (_currentLabelType == LabelType::TTF) + { + switch (_currLabelEffect) { + case LabelEffect::OUTLINE: + //draw text with outline + glprogram->setUniformLocationWith4f(_uniformTextColor, + _textColorF.r, _textColorF.g, _textColorF.b, _textColorF.a); + glprogram->setUniformLocationWith4f(_uniformEffectColor, + _effectColorF.r, _effectColorF.g, _effectColorF.b, _effectColorF.a); + for (const auto& batchNode : _batchNodes) + { + batchNode->getTextureAtlas()->drawQuads(); + } + + //draw text without outline + glprogram->setUniformLocationWith4f(_uniformEffectColor, + _effectColorF.r, _effectColorF.g, _effectColorF.b, 0.f); + break; + case LabelEffect::GLOW: + glprogram->setUniformLocationWith4f(_uniformEffectColor, + _effectColorF.r, _effectColorF.g, _effectColorF.b, _effectColorF.a); + case LabelEffect::NORMAL: + glprogram->setUniformLocationWith4f(_uniformTextColor, + _textColorF.r, _textColorF.g, _textColorF.b, _textColorF.a); + break; + default: + break; + } + } + + for (const auto& batchNode : _batchNodes) + { + batchNode->getTextureAtlas()->drawQuads(); + } +} + +void Label::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) +{ + // Don't do calculate the culling if the transform was not updated + bool transformUpdated = flags & FLAGS_TRANSFORM_DIRTY; +#if CC_USE_CULLING + _insideBounds = transformUpdated ? renderer->checkVisibility(transform, _contentSize) : _insideBounds; + + if (_insideBounds) +#endif + { + _customCommand.init(_globalZOrder, transform, flags); + _customCommand.func = CC_CALLBACK_0(Label::onDraw, this, transform, transformUpdated); + + renderer->addCommand(&_customCommand); + } +} + void Label::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags) { - if (! _visible || _originalUTF8String.empty()) + if (! _visible || (_originalUTF8String.empty() && _children.empty()) ) { return; } @@ -1220,7 +1294,8 @@ void Label::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t pare uint32_t flags = processParentFlags(parentTransform, parentFlags); - if (_shadowEnabled && _shadowBlurRadius <= 0 && (_shadowDirty || (flags & FLAGS_DIRTY_MASK))) + if (!_originalUTF8String.empty() && _shadowEnabled && _shadowBlurRadius <= 0 + && (_shadowDirty || (flags & FLAGS_DIRTY_MASK))) { _position.x += _shadowOffset.width; _position.y += _shadowOffset.height; @@ -1235,7 +1310,8 @@ void Label::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t pare _shadowDirty = false; } - if (!_textSprite && !isVisitableByVisitingCamera()) + bool visibleByCamera = isVisitableByVisitingCamera(); + if (_children.empty() && !_textSprite && !visibleByCamera) { return; } @@ -1246,6 +1322,41 @@ void Label::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t pare _director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); _director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform); + if (!_children.empty()) + { + sortAllChildren(); + + int i = 0; + // draw children zOrder < 0 + for (; i < _children.size(); i++) + { + auto node = _children.at(i); + + if (node && node->getLocalZOrder() < 0) + node->visit(renderer, _modelViewTransform, flags); + else + break; + } + // self draw + if (visibleByCamera) + this->drawSelf(renderer, flags); + + for (auto it = _children.cbegin() + i; it != _children.cend(); ++it) + { + (*it)->visit(renderer, _modelViewTransform, flags); + } + + } + else if (visibleByCamera) + { + this->drawSelf(renderer, flags); + } + + _director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); +} + +void Label::drawSelf(Renderer* renderer, uint32_t flags) +{ if (_textSprite) { if (_shadowNode) @@ -1258,12 +1369,6 @@ void Label::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t pare { draw(renderer, _modelViewTransform, flags); } - - _director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); - - // FIX ME: Why need to set _orderOfArrival to 0?? - // Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920 - // setOrderOfArrival(0); } void Label::setSystemFontName(const std::string& systemFont) @@ -1287,45 +1392,63 @@ void Label::setSystemFontSize(float fontSize) ///// PROTOCOL STUFF Sprite * Label::getLetter(int letterIndex) { - if (_systemFontDirty || _currentLabelType == LabelType::STRING_TEXTURE) + Sprite* letter = nullptr; + do { - return nullptr; - } - - if (_contentDirty) - { - updateContent(); - } - - if (! _textSprite && letterIndex < _limitShowCount) - { - const auto &letter = _lettersInfo[letterIndex]; - - if(! letter.def.validDefinition) - return nullptr; - - Sprite* sp = static_cast(this->getChildByTag(letterIndex)); - - if (!sp) + if (_systemFontDirty || _currentLabelType == LabelType::STRING_TEXTURE) { - Rect uvRect; - uvRect.size.height = letter.def.height; - uvRect.size.width = letter.def.width; - uvRect.origin.x = letter.def.U; - uvRect.origin.y = letter.def.V; + break; + } - sp = Sprite::createWithTexture(_fontAtlas->getTexture(letter.def.textureID),uvRect); - sp->setBatchNode(_batchNodes[letter.def.textureID]); - sp->setPosition(letter.position.x + uvRect.size.width / 2, - letter.position.y - uvRect.size.height / 2); - sp->setOpacity(_realOpacity); - - _batchNodes[letter.def.textureID]->addSpriteWithoutQuad(sp, letter.atlasIndex, letterIndex); + auto contentDirty = _contentDirty; + if (contentDirty) + { + updateContent(); } - return sp; - } - return nullptr; + if (_textSprite == nullptr && letterIndex < _limitShowCount) + { + const auto &letterInfo = _lettersInfo[letterIndex]; + if (!letterInfo.def.validDefinition) + { + break; + } + + if (_letters.find(letterIndex) != _letters.end()) + { + letter = _letters[letterIndex]; + } + + auto textureID = letterInfo.def.textureID; + Rect uvRect; + uvRect.size.height = letterInfo.def.height; + uvRect.size.width = letterInfo.def.width; + uvRect.origin.x = letterInfo.def.U; + uvRect.origin.y = letterInfo.def.V; + + if (letter == nullptr) + { + letter = LabelLetter::createWithTexture(_fontAtlas->getTexture(textureID), uvRect); + letter->setTextureAtlas(_batchNodes.at(textureID)->getTextureAtlas()); + letter->setAtlasIndex(letterInfo.atlasIndex); + + letter->setPosition(letterInfo.position.x + uvRect.size.width / 2, + letterInfo.position.y - uvRect.size.height / 2); + letter->setOpacity(_realOpacity); + addChild(letter); + + _letters[letterIndex] = letter; + } + else if (contentDirty) + { + letter->setTexture(_fontAtlas->getTexture(textureID)); + letter->setTextureRect(uvRect, false, uvRect.size); + letter->setTextureAtlas(_batchNodes.at(textureID)->getTextureAtlas()); + } + } + } while (false); + + return letter; } void Label::setLineHeight(float height) @@ -1416,10 +1539,7 @@ void Label::setOpacityModifyRGB(bool isOpacityModifyRGB) void Label::updateDisplayedColor(const Color3B& parentColor) { - _displayedColor.r = _realColor.r * parentColor.r/255.0; - _displayedColor.g = _realColor.g * parentColor.g/255.0; - _displayedColor.b = _realColor.b * parentColor.b/255.0; - updateColor(); + Node::updateDisplayedColor(parentColor); if (_textSprite) { @@ -1433,8 +1553,7 @@ void Label::updateDisplayedColor(const Color3B& parentColor) void Label::updateDisplayedOpacity(GLubyte parentOpacity) { - _displayedOpacity = _realOpacity * parentOpacity/255.0; - updateColor(); + Node::updateDisplayedOpacity(parentOpacity); if (_textSprite) { @@ -1468,7 +1587,7 @@ void Label::setTextColor(const Color4B &color) void Label::updateColor() { - if (nullptr == _textureAtlas) + if (_batchNodes.empty()) { return; } @@ -1539,4 +1658,23 @@ void Label::setBlendFunc(const BlendFunc &blendFunc) } } +void Label::removeAllChildrenWithCleanup(bool cleanup) +{ + Node::removeAllChildrenWithCleanup(cleanup); + _letters.clear(); +} + +void Label::removeChild(Node* child, bool cleanup /* = true */) +{ + Node::removeChild(child, cleanup); + for (auto it : _letters) + { + if (it.second == child) + { + _letters.erase(it.first); + break; + } + } +} + NS_CC_END diff --git a/cocos/2d/CCLabel.h b/cocos/2d/CCLabel.h index 1285deb52a..85218b6d26 100644 --- a/cocos/2d/CCLabel.h +++ b/cocos/2d/CCLabel.h @@ -26,7 +26,7 @@ #ifndef _COCOS2D_CCLABEL_H_ #define _COCOS2D_CCLABEL_H_ -#include "2d/CCSpriteBatchNode.h" +#include "2d/CCNode.h" #include "renderer/CCCustomCommand.h" #include "2d/CCFontAtlas.h" #include "base/ccTypes.h" @@ -83,6 +83,9 @@ typedef struct _ttfConfig } }TTFConfig; +class Sprite; +class SpriteBatchNode; + /** * @brief Label is a subclass of SpriteBatchNode that knows how to render text labels. * @@ -99,7 +102,7 @@ typedef struct _ttfConfig * - http://www.angelcode.com/products/bmfont/ (Free, Windows only) * @js NA */ -class CC_DLL Label : public SpriteBatchNode, public LabelProtocol +class CC_DLL Label : public Node, public LabelProtocol { public: static const int DistanceFieldFontSize; @@ -435,7 +438,8 @@ public: FontAtlas* getFontAtlas() { return _fontAtlas; } - virtual void setBlendFunc(const BlendFunc &blendFunc) override; + virtual const BlendFunc& getBlendFunc() const { return _blendFunc; } + virtual void setBlendFunc(const BlendFunc &blendFunc); virtual bool isOpacityModifyRGB() const override; virtual void setOpacityModifyRGB(bool isOpacityModifyRGB) override; @@ -448,9 +452,6 @@ public: virtual float getScaleX() const override; virtual float getScaleY() const override; - virtual void addChild(Node * child, int zOrder=0, int tag=0) override; - virtual void sortAllChildren() override; - virtual std::string getDescription() const override; virtual const Size& getContentSize() const override; @@ -462,6 +463,9 @@ public: virtual void setCameraMask(unsigned short mask, bool applyChildren = true) override; + virtual void removeAllChildrenWithCleanup(bool cleanup) override; + virtual void removeChild(Node* child, bool cleanup = true) override; + CC_DEPRECATED_ATTRIBUTE static Label* create(const std::string& text, const std::string& font, float fontSize, const Size& dimensions = Size::ZERO, TextHAlignment hAlignment = TextHAlignment::LEFT, TextVAlignment vAlignment = TextVAlignment::TOP); @@ -533,6 +537,8 @@ protected: void reset(); + void drawSelf(Renderer* renderer, uint32_t flags); + std::string _bmFontPath; bool _isOpacityModifyRGB; @@ -543,7 +549,7 @@ protected: float _systemFontSize; LabelType _currentLabelType; - std::vector _batchNodes; + Vector _batchNodes; FontAtlas * _fontAtlas; std::vector _lettersInfo; EventListenerCustom* _purgeTextureListener; @@ -607,9 +613,12 @@ protected: bool _clipEnabled; bool _blendFuncDirty; + BlendFunc _blendFunc; /// whether or not the sprite was inside bounds the previous frame bool _insideBounds; + std::unordered_map _letters; + private: CC_DISALLOW_COPY_AND_ASSIGN(Label);