Files
rive-cpp/src/scripted/scripted_path_effect.cpp
bodymovin d920ee0efd fix(scripting): search first parent transform component to build scri… (#11443) 99ca3a30cc
fix(scripting): search first parent transform component to build script node

feature: modulate opacity (#11427) 128d9d61e0
* feature: modulate opacity

* fix: clang-format

* fix: rust renderer has a no-op modulateOpacity

* fix: no-op modulateOpacity for canvas android

* feature: modulate opacity on android canvas

* fix: rcp ref

* fix: missing override

* fix: gms

* fix: make flutter_renderer match cg one

* fix: josh pr feedback

* fix: remove CG transparency layer

* fix: save modulated gradient up-front

* fix: store only one gradient ref

* fix: remove specific constructor

* fix: use GradDataArray!

* fix: expose currentModulatedOpacity

* fix: cg_factory modulated opacity value

* fix: modulate negative opacity test

* fix: verify double modulate negative also clamps

Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
Co-authored-by: hernan <hernan@rive.app>
2026-01-13 01:13:05 +00:00

189 lines
5.0 KiB
C++

#ifdef WITH_RIVE_SCRIPTING
#include "rive/lua/rive_lua_libs.hpp"
#endif
#include "rive/component_dirt.hpp"
#include "rive/assets/script_asset.hpp"
#include "rive/scripted/scripted_path_effect.hpp"
#include "rive/shapes/paint/stroke.hpp"
using namespace rive;
void ScriptedEffectPath::invalidateEffect() { m_path.rewind(); }
#ifdef WITH_RIVE_SCRIPTING
bool ScriptedPathEffect::scriptInit(LuaState* state)
{
ScriptedObject::scriptInit(state);
addScriptedDirt(ComponentDirt::Paint, true);
return true;
}
void ScriptedPathEffect::updateEffect(PathProvider* pathProvider,
const ShapePaintPath* source,
const ShapePaint* shapePaint)
{
if (!updates())
{
return;
}
auto effectPathIt = m_effectPaths.find(pathProvider);
if (effectPathIt != m_effectPaths.end())
{
auto trimEffectPath =
static_cast<ScriptedEffectPath*>(effectPathIt->second);
auto path = trimEffectPath->path();
if (path->hasRenderPath())
{
// Previous result hasn't been invalidated, it's still good.
return;
}
path->rewind(source->isLocal(), source->fillRule());
if (m_state == nullptr)
{
return;
}
auto state = m_state->state;
// Stack: []
rive_lua_pushRef(state, m_self);
// Stack: [self]
lua_getfield(state, -1, "update");
// Stack: [self, "update"]
lua_pushvalue(state, -2);
// Stack: [self, "update", self]
lua_newrive<ScriptedPathData>(state, source->rawPath());
// Stack: [self, "update", self, pathData]
lua_newrive<ScriptedNode>(state,
nullptr,
shapePaint->parentTransformComponent());
auto scriptedNode = lua_torive<ScriptedNode>(state, -1);
scriptedNode->shapePaint(shapePaint);
// Stack: [self, "update", self, pathData, node]
if (static_cast<lua_Status>(rive_lua_pcall(state, 3, 1)) != LUA_OK)
{
fprintf(stderr, "update function failed\n");
}
else
{
// Stack: [self, outputPathData]
auto scriptedPath = (ScriptedPathData*)lua_touserdata(state, -1);
auto rawPath = path->mutableRawPath();
rawPath->addPath(scriptedPath->rawPath);
}
// Stack: [self, status] or [self, outputPathData]
rive_lua_pop(state, 2);
}
}
#else
void ScriptedPathEffect::updateEffect(PathProvider* pathProvider,
const ShapePaintPath* source,
const ShapePaint* shapePaint)
{}
#endif
StatusCode ScriptedPathEffect::onAddedDirty(CoreContext* context)
{
auto code = Super::onAddedDirty(context);
if (code != StatusCode::Ok)
{
return code;
}
artboard()->addScriptedObject(this);
return StatusCode::Ok;
}
StatusCode ScriptedPathEffect::onAddedClean(CoreContext* context)
{
auto effectsContainer = EffectsContainer::from(parent());
if (!effectsContainer)
{
return StatusCode::InvalidObject;
}
effectsContainer->addStrokeEffect(this);
return StatusCode::Ok;
}
bool ScriptedPathEffect::advanceComponent(float elapsedSeconds,
AdvanceFlags flags)
{
if (elapsedSeconds == 0)
{
return false;
}
if ((flags & AdvanceFlags::AdvanceNested) == 0)
{
elapsedSeconds = 0;
}
return scriptAdvance(elapsedSeconds);
}
bool ScriptedPathEffect::addScriptedDirt(ComponentDirt value, bool recurse)
{
return Component::addDirt(value, recurse);
}
void ScriptedPathEffect::addProperty(CustomProperty* prop)
{
auto scriptInput = ScriptInput::from(prop);
if (scriptInput != nullptr)
{
scriptInput->scriptedObject(this);
}
CustomPropertyContainer::addProperty(prop);
}
StatusCode ScriptedPathEffect::import(ImportStack& importStack)
{
auto result = registerReferencer(importStack);
if (result != StatusCode::Ok)
{
return result;
}
return Super::import(importStack);
}
Core* ScriptedPathEffect::clone() const
{
ScriptedPathEffect* twin =
ScriptedPathEffectBase::clone()->as<ScriptedPathEffect>();
if (m_fileAsset != nullptr)
{
twin->setAsset(m_fileAsset);
}
return twin;
}
void ScriptedPathEffect::markNeedsUpdate()
{
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
EffectsContainer* ScriptedPathEffect::parentPaint()
{
return EffectsContainer::from(parent());
}
EffectPath* ScriptedPathEffect::createEffectPath()
{
return new ScriptedEffectPath();
}
void ScriptedPathEffect::buildDependencies()
{
Super::buildDependencies();
if (parent())
{
parent()->addDependent(this);
}
}
void ScriptedPathEffect::update(ComponentDirt value)
{
Super::update(value);
if (hasDirt(value, ComponentDirt::ScriptUpdate))
{
invalidateEffectFromLocal();
}
}