Skip to content

Commit

Permalink
Support UBB gradient color for TTF label
Browse files Browse the repository at this point in the history
  • Loading branch information
WuJiayiSH committed Dec 12, 2022
1 parent b34be57 commit c571596
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 6 deletions.
200 changes: 196 additions & 4 deletions display/FUILabel.cpp
Expand Up @@ -6,11 +6,77 @@
NS_FGUI_BEGIN
USING_NS_CC;

static Color3B toGrayed(const Color3B& source)
namespace
{
Color3B c = source;
c.r = c.g = c.b = c.r * 0.299f + c.g * 0.587f + c.b * 0.114f;
return c;
inline Color3B toGrayed(const Color3B& source)
{
Color3B c = source;
c.r = c.g = c.b = c.r * 0.299f + c.g * 0.587f + c.b * 0.114f;
return c;
}

Texture2D* _getTexture(Label* label)
{
Texture2D* texture = nullptr;

if (FontAtlas* fontAtlas = label->getFontAtlas())
{
auto textures = fontAtlas->getTextures();
if (!textures.empty())
{
texture = textures.begin()->second;
}
}

return texture;
}

GLProgram* labelOutlineProgram = nullptr;
const char* labelOutlineFrag = R"(
#ifdef GL_ES
precision lowp float;
#endif
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
uniform vec4 u_effectColor;
#ifdef GL_ES
uniform lowp int u_effectType; // 0: None (Draw text), 1: Outline, 2: Shadow
#else
uniform int u_effectType;
#endif
void main()
{
vec4 sample = texture2D(CC_Texture0, v_texCoord);
// fontAlpha == 1 means the area of solid text (without edge)
// fontAlpha == 0 means the area outside text, including outline area
// fontAlpha == (0, 1) means the edge of text
float fontAlpha = sample.a;
// outlineAlpha == 1 means the area of 'solid text' and 'solid outline'
// outlineAlpha == 0 means the transparent area outside text and outline
// outlineAlpha == (0, 1) means the edge of outline
float outlineAlpha = sample.r;
if (u_effectType == 0) // draw text
{
gl_FragColor = v_fragmentColor * vec4(u_effectColor.rgb, u_effectColor.a * fontAlpha);
}
else if (u_effectType == 1) // draw outline
{
// multipy (1.0 - fontAlpha) to make the inner edge of outline smoother and make the text itself transparent.
gl_FragColor = vec4(u_effectColor.rgb, v_fragmentColor.a * u_effectColor.a * outlineAlpha * (1.0 - fontAlpha));
}
else // draw shadow
{
gl_FragColor = vec4(u_effectColor.rgb, v_fragmentColor.a * u_effectColor.a * fontAlpha);
}
}
)";

}

FUILabel::FUILabel() : _fontSize(-1),
Expand Down Expand Up @@ -182,6 +248,132 @@ void FUILabel::updateBMFontScale()
}
}

void FUILabel::updateColor()
{
if (_batchNodes.empty())
return;

if (_textFormat->hasEffect(TextFormat::GRADIENT))
{
Color4B color4bl(_textFormat->gradientColor[1].r, _textFormat->gradientColor[1].g, _textFormat->gradientColor[1].b, _displayedOpacity);
Color4B color4br(_textFormat->gradientColor[3].r, _textFormat->gradientColor[3].g, _textFormat->gradientColor[3].b, _displayedOpacity);
Color4B color4tl(_textFormat->gradientColor[0].r, _textFormat->gradientColor[0].g, _textFormat->gradientColor[0].b, _displayedOpacity);
Color4B color4tr(_textFormat->gradientColor[2].r, _textFormat->gradientColor[2].g, _textFormat->gradientColor[2].b, _displayedOpacity);

if (_isOpacityModifyRGB)
{
color4bl.r *= _displayedOpacity / 255.0f;
color4bl.g *= _displayedOpacity / 255.0f;
color4bl.b *= _displayedOpacity / 255.0f;

color4br.r *= _displayedOpacity / 255.0f;
color4br.g *= _displayedOpacity / 255.0f;
color4br.b *= _displayedOpacity / 255.0f;

color4tl.r *= _displayedOpacity / 255.0f;
color4tl.g *= _displayedOpacity / 255.0f;
color4tl.b *= _displayedOpacity / 255.0f;

color4tr.r *= _displayedOpacity / 255.0f;
color4tr.g *= _displayedOpacity / 255.0f;
color4tr.b *= _displayedOpacity / 255.0f;
}

for (auto&& batchNode:_batchNodes)
{
TextureAtlas* textureAtlas = batchNode->getTextureAtlas();
V3F_C4B_T2F_Quad* quads = textureAtlas->getQuads();
ssize_t totalQuads = textureAtlas->getTotalQuads();

for (int i = 0; i < totalQuads; i++)
{
quads[i].bl.colors = color4bl;
quads[i].br.colors = color4br;
quads[i].tl.colors = color4tl;
quads[i].tr.colors = color4tr;
textureAtlas->updateQuad(&quads[i], i);
}
}

return;
}

Label::updateColor();
}

void FUILabel::updateShaderProgram()
{
if (_currentLabelType == LabelType::TTF && (_textFormat->hasEffect(TextFormat::OUTLINE | TextFormat::SHADOW)))
{
if (!labelOutlineProgram)
labelOutlineProgram = GLProgram::createWithByteArrays(ccLabel_vert, labelOutlineFrag);
setGLProgramState(GLProgramState::getOrCreateWithGLProgram(labelOutlineProgram));

_uniformEffectColor = glGetUniformLocation(getGLProgram()->getProgram(), "u_effectColor");
_uniformEffectType = glGetUniformLocation(getGLProgram()->getProgram(), "u_effectType");

return;
}

Label::updateShaderProgram();
}


void FUILabel::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
if (_batchNodes.empty() || _lengthOfString <= 0)
return;

if (_currentLabelType == LabelType::TTF && (_textFormat->hasEffect(TextFormat::OUTLINE | TextFormat::SHADOW)))
{
_customCommand.init(_globalZOrder, transform, flags);
_customCommand.func = CC_CALLBACK_0(FUILabel::onDraw, this, transform, flags & FLAGS_TRANSFORM_DIRTY);
renderer->addCommand(&_customCommand);
return;
}

Label::draw(renderer, transform, flags);
}

void FUILabel::onDraw(const Mat4& transform, bool /*transformUpdated*/)
{
GLProgram* program = getGLProgram();
program->use();
GL::blendFunc(_blendFunc.src, _blendFunc.dst);

if (_shadowEnabled)
{
program->setUniformsForBuiltins(_shadowTransform);
for (auto&& it : _letters)
it.second->updateTransform();

drawQuads(2, _boldEnabled ? _textColorF : _shadowColor4F);
}

program->setUniformsForBuiltins(transform);
for (auto&& it : _letters)
it.second->updateTransform();

// draw outline of text
if (_currLabelEffect == LabelEffect::OUTLINE)
drawQuads(1, _effectColorF);

// draw text without outline
drawQuads(0, _textColorF);
}

void FUILabel::drawQuads(GLint type, const cocos2d::Color4F& color)
{
GLProgram* program = getGLProgram();
program->setUniformLocationWith1i(_uniformEffectType, type);
program->setUniformLocationWith4f(_uniformEffectColor, color.r, color.g, color.b, color.a);

for (auto&& batchNode : _batchNodes)
{
batchNode->getTextureAtlas()->drawQuads();
}
}

// void FUILabel::setUnderlineColor(const cocos2d::Color3B& value)
// {
// if (_textFormat->underline) {
Expand Down
6 changes: 6 additions & 0 deletions display/FUILabel.h
Expand Up @@ -28,11 +28,17 @@ class FUILabel : public cocos2d::Label
virtual bool setBMFontFilePath(const std::string& bmfontFilePath, const cocos2d::Vec2& imageOffset = cocos2d::Vec2::ZERO, float fontSize = 0) override;

void setGrayed(bool value);

virtual void draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &transform, uint32_t flags) override;
protected:
/* 2d/CCLabel.h add `virtual` defore `void updateBMFontScale()` */
virtual void updateBMFontScale() override;
virtual void updateColor() override;
virtual void updateShaderProgram() override;

void onDraw(const cocos2d::Mat4& transform, bool transformUpdated);
private:
void drawQuads(GLint type, const cocos2d::Color4F& color);
TextFormat* _textFormat;
std::string _fontName;
int _fontSize;
Expand Down
1 change: 1 addition & 0 deletions display/TextFormat.cpp
Expand Up @@ -47,6 +47,7 @@ TextFormat & TextFormat::operator=(const TextFormat & other)
shadowBlurRadius = other.shadowBlurRadius;
glowColor = other.glowColor;
_hasColor = other._hasColor;
std::copy(std::begin(other.gradientColor), std::end(other.gradientColor), std::begin(gradientColor));
}
return *this;
}
Expand Down
2 changes: 2 additions & 0 deletions display/TextFormat.h
Expand Up @@ -21,6 +21,7 @@ class TextFormat
static const int OUTLINE = 1;
static const int SHADOW = 2;
static const int GLOW = 4;
static const int GRADIENT = 8;

std::string face;
float fontSize;
Expand All @@ -40,6 +41,7 @@ class TextFormat
cocos2d::Size shadowOffset;
int shadowBlurRadius;
cocos2d::Color3B glowColor;
cocos2d::Color3B gradientColor[4];

//internal use
bool _hasColor;
Expand Down
38 changes: 36 additions & 2 deletions utils/html/HtmlParser.cpp
Expand Up @@ -135,8 +135,42 @@ void HtmlParser::startElement(void* /*ctx*/, const char *elementName, const char
auto it = attrMap.find("color");
if (it != attrMap.end())
{
_format.color = (Color3B)ToolSet::hexToColor(it->second.asString().c_str());
_format._hasColor = true;
const string& color = it->second.asString();
const char* s = color.c_str();
size_t pos = color.find(',');
if (pos == string::npos)
{
_format.color = (Color3B)ToolSet::hexToColor(s);
_format._hasColor = true;
}
else
{
_format.gradientColor[0] = (Color3B)ToolSet::hexToColor(s);
_format.gradientColor[1] = (Color3B)ToolSet::hexToColor(s + pos + 1);
pos = color.find(',', pos + 1);
if (pos != string::npos)
{
_format.gradientColor[2] = (Color3B)ToolSet::hexToColor(s + pos + 1);
pos = color.find(',', pos + 1);
if (pos != string::npos)
{
_format.gradientColor[3] = (Color3B)ToolSet::hexToColor(s + pos + 1);
}
else
{
_format.gradientColor[3] = _format.gradientColor[2];
}
}
else
{
_format.gradientColor[2] = _format.gradientColor[0];
_format.gradientColor[3] = _format.gradientColor[1];
}

_format.enableEffect(TextFormat::GRADIENT);
_format._hasColor = true;
_format.color = ccColor3B::WHITE;
}
}
}
else if (strcasecmp(elementName, "br") == 0)
Expand Down

0 comments on commit c571596

Please sign in to comment.