blob: 04034dbe2f0298f639de131682f942e4fc2ed9bc [file] [log] [blame]
#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_drawable.hpp"
using namespace rive;
#ifdef WITH_RIVE_SCRIPTING
bool ScriptedDrawable::scriptInit(LuaState* state)
{
ScriptedObject::scriptInit(state);
addDirt(ComponentDirt::Paint);
return true;
}
void ScriptedDrawable::draw(Renderer* renderer)
{
auto state = m_state->state;
if (m_needsSaveOperation)
{
renderer->save();
}
renderer->transform(worldTransform());
rive_lua_pushRef(state, m_self);
if (static_cast<lua_Type>(lua_getfield(state, -1, "draw")) != LUA_TFUNCTION)
{
fprintf(stderr, "expected draw to be a function\n");
}
else
{
lua_pushvalue(state, -2);
auto scriptedRenderer = lua_newrive<ScriptedRenderer>(state, renderer);
if (static_cast<lua_Status>(rive_lua_pcall(state, 2, 0)) != LUA_OK)
{
rive_lua_pop(state, 1);
}
scriptedRenderer->end();
}
rive_lua_pop(state, 1);
if (m_needsSaveOperation)
{
renderer->restore();
}
}
std::vector<HitComponent*> ScriptedDrawable::hitComponents(
StateMachineInstance* sm)
{
if (!listensToPointerEvents())
{
return {};
}
auto* hitComponent = new HitScriptedDrawable(this, sm);
return std::vector<HitComponent*>{hitComponent};
}
HitResult HitScriptedDrawable::processEvent(Vec2D position,
ListenerType hitType,
bool canHit,
float timeStamp,
int pointerId)
{
HitResult hitResult = HitResult::none;
auto scriptAsset = m_drawable->scriptAsset();
auto vm = m_drawable->state();
if (vm == nullptr || scriptAsset == nullptr ||
!handlesEvent(canHit, hitType))
{
return HitResult::none;
}
Vec2D localPos;
auto hasLocalPos = m_drawable->worldToLocal(position, &localPos);
if (!hasLocalPos)
{
return hitResult;
}
auto state = vm->state;
rive_lua_pushRef(state, m_drawable->self());
auto mName = methodName(canHit, hitType);
if (static_cast<lua_Type>(lua_getfield(state, -1, mName.c_str())) !=
LUA_TFUNCTION)
{
fprintf(stderr, "expected %s to be a function\n", mName.c_str());
rive_lua_pop(state, 1);
}
else
{
lua_pushvalue(state, -2);
auto pointerEvent =
lua_newrive<ScriptedPointerEvent>(state, pointerId, localPos);
if (static_cast<lua_Status>(rive_lua_pcall(state, 2, 0)) != LUA_OK)
{
fprintf(stderr, "%s failed\n", mName.c_str());
rive_lua_pop(state, 1);
}
hitResult = pointerEvent->m_hitResult;
}
rive_lua_pop(state, 1);
return hitResult;
}
bool ScriptedDrawable::willDraw()
{
return Super::willDraw() && m_state != nullptr && draws();
}
#else
void ScriptedDrawable::draw(Renderer* renderer) {}
std::vector<HitComponent*> ScriptedDrawable::hitComponents(
StateMachineInstance* sm)
{
return {};
}
HitResult HitScriptedDrawable::processEvent(Vec2D position,
ListenerType hitType,
bool canHit,
float timeStamp,
int pointerId)
{
return HitResult::none;
}
bool ScriptedDrawable::willDraw() { return Super::willDraw() && draws(); }
#endif
void ScriptedDrawable::update(ComponentDirt value)
{
Super::update(value);
if ((value & ComponentDirt::ScriptUpdate) == ComponentDirt::ScriptUpdate)
{
scriptUpdate();
}
}
Core* ScriptedDrawable::hitTest(HitInfo*, const Mat2D&) { return nullptr; }
StatusCode ScriptedDrawable::onAddedDirty(CoreContext* context)
{
auto code = Super::onAddedDirty(context);
if (code != StatusCode::Ok)
{
return code;
}
artboard()->addScriptedObject(this);
return StatusCode::Ok;
}
bool ScriptedDrawable::advanceComponent(float elapsedSeconds,
AdvanceFlags flags)
{
if (elapsedSeconds == 0)
{
return false;
}
if ((flags & AdvanceFlags::AdvanceNested) == 0)
{
elapsedSeconds = 0;
}
return scriptAdvance(elapsedSeconds);
}
bool ScriptedDrawable::addScriptedDirt(ComponentDirt value, bool recurse)
{
return Drawable::addDirt(value, recurse);
}
void ScriptedDrawable::addProperty(CustomProperty* prop)
{
auto scriptInput = ScriptInput::from(prop);
if (scriptInput != nullptr)
{
scriptInput->scriptedObject(this);
}
CustomPropertyContainer::addProperty(prop);
}
StatusCode ScriptedDrawable::import(ImportStack& importStack)
{
auto result = registerReferencer(importStack);
if (result != StatusCode::Ok)
{
return result;
}
return Super::import(importStack);
}
Core* ScriptedDrawable::clone() const
{
ScriptedDrawable* twin =
ScriptedDrawableBase::clone()->as<ScriptedDrawable>();
if (m_fileAsset != nullptr)
{
twin->setAsset(m_fileAsset);
}
return twin;
}
void ScriptedDrawable::markNeedsUpdate()
{
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
bool ScriptedDrawable::worldToLocal(Vec2D world, Vec2D* local)
{
Mat2D toMountedArtboard;
if (!worldTransform().invert(&toMountedArtboard))
{
return false;
}
*local = toMountedArtboard * world;
return true;
}
bool HitScriptedDrawable::handlesEvent(bool canHit, ListenerType hitEvent)
{
if (canHit)
{
switch (hitEvent)
{
case ListenerType::down:
return m_drawable->wantsPointerDown();
case ListenerType::up:
return m_drawable->wantsPointerUp();
case ListenerType::dragStart:
return false;
case ListenerType::dragEnd:
return false;
default:
return m_drawable->wantsPointerMove();
}
}
return m_drawable->wantsPointerExit();
}
std::string HitScriptedDrawable::methodName(bool canHit, ListenerType hitEvent)
{
if (canHit)
{
switch (hitEvent)
{
case ListenerType::down:
return "pointerDown";
case ListenerType::up:
return "pointerUp";
case ListenerType::dragStart:
case ListenerType::dragEnd:
return "";
default:
return "pointerMove";
}
}
return "pointerExit";
}