blob: d7f210d164c60a7dd681d8e1eb3a7208ba1406b9 [file] [log] [blame] [edit]
#include "rive/text/text_style_paint.hpp"
#include "rive/text/text.hpp"
#include "rive/text/text_variation_helper.hpp"
#include "rive/shapes/paint/shape_paint.hpp"
#include "rive/shapes/paint/feather.hpp"
#include "rive/artboard.hpp"
#include "rive/factory.hpp"
using namespace rive;
TextStylePaint::TextStylePaint() : m_path(true, FillRule::clockwise) {}
void TextStylePaint::rewindPath()
{
m_path.rewind();
m_hasContents = false;
m_opacityPaths.clear();
}
bool TextStylePaint::addPath(const RawPath& rawPath, float opacity)
{
bool hadContents = m_hasContents;
m_hasContents = true;
if (opacity > 0.0f)
{
// m_path contains everything, so inner feather bounds can work.
m_path.addPathClockwise(rawPath);
// Bucket by opacity
auto itr = m_opacityPaths.find(opacity);
ShapePaintPath* shapePaintPath = nullptr;
if (itr != m_opacityPaths.end())
{
ShapePaintPath& path = itr->second;
shapePaintPath = &path;
}
else
{
m_opacityPaths[opacity] = ShapePaintPath(true, FillRule::clockwise);
shapePaintPath = &m_opacityPaths.at(opacity);
}
shapePaintPath->addPathClockwise(rawPath);
}
return !hadContents;
}
void TextStylePaint::draw(Renderer* renderer, const Mat2D& worldTransform)
{
for (auto shapePaint : m_ShapePaints)
{
if (!shapePaint->shouldDraw())
{
continue;
}
shapePaint->blendMode(parent()->as<Text>()->blendMode());
// For blend modes to work, opaque paths render first
auto itr = m_opacityPaths.find(1.0f);
if (itr != m_opacityPaths.end())
{
ShapePaintPath& path = itr->second;
shapePaint->draw(renderer, &path, worldTransform, true);
}
if (m_paintPool.size() < m_opacityPaths.size())
{
m_paintPool.reserve(m_opacityPaths.size());
Factory* factory = artboard()->factory();
while (m_paintPool.size() < m_opacityPaths.size())
{
m_paintPool.emplace_back(factory->makeRenderPaint());
}
}
uint32_t paintIndex = 0;
for (itr = m_opacityPaths.begin(); itr != m_opacityPaths.end(); itr++)
{
// Don't render opaque paths twice
if (itr->first == 1.0f)
{
continue;
}
RenderPaint* renderPaint = m_paintPool[paintIndex++].get();
shapePaint->applyTo(renderPaint, itr->first);
if (auto feather = shapePaint->feather())
{
renderPaint->feather(feather->strength());
}
ShapePaintPath& path = itr->second;
shapePaint->draw(renderer,
&path,
worldTransform,
true,
renderPaint);
}
}
}
const Mat2D& TextStylePaint::shapeWorldTransform() const
{
return parent()->as<Text>()->shapeWorldTransform();
}
Component* TextStylePaint::pathBuilder() { return parent(); }
Core* TextStylePaint::clone() const
{
TextStylePaint* twin = TextStylePaintBase::clone()->as<TextStylePaint>();
if (m_fileAsset != nullptr)
{
twin->setAsset(m_fileAsset);
}
return twin;
}