blob: 96fed9156dd9a572ac2394e6752b754e5f05251c [file] [log] [blame] [edit]
#ifdef WITH_RIVE_SCRIPTING
#include "rive/lua/rive_lua_libs.hpp"
#endif
#include "rive/assets/script_asset.hpp"
#include "rive/artboard.hpp"
#include "rive/file.hpp"
#include "rive/script_input_artboard.hpp"
#include "rive/scripted/scripted_data_converter.hpp"
#include "rive/scripted/scripted_drawable.hpp"
#include "rive/scripted/scripted_layout.hpp"
#include "rive/scripted/scripted_path_effect.hpp"
#include "rive/scripted/scripted_object.hpp"
using namespace rive;
ScriptedObject* ScriptedObject::from(Core* object)
{
switch (object->coreType())
{
case ScriptedDataConverter::typeKey:
return object->as<ScriptedDataConverter>();
case ScriptedDrawable::typeKey:
return object->as<ScriptedDrawable>();
case ScriptedLayout::typeKey:
return object->as<ScriptedLayout>();
case ScriptedPathEffect::typeKey:
return object->as<ScriptedPathEffect>();
}
return nullptr;
}
#ifdef WITH_RIVE_SCRIPTING
void ScriptedObject::setArtboardInput(std::string name, Artboard* artboard)
{
if (m_state == nullptr || scriptAsset() == nullptr)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
lua_newrive<ScriptedArtboard>(state,
state,
ref_rcp(scriptAsset()->file()),
artboard->instance());
lua_setfield(state, -2, name.c_str());
rive_lua_pop(state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
void ScriptedObject::setBooleanInput(std::string name, bool value)
{
if (m_state == nullptr)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
lua_pushboolean(state, value);
lua_setfield(state, -2, name.c_str());
rive_lua_pop(state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
void ScriptedObject::setNumberInput(std::string name, float value)
{
if (m_state == nullptr)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
lua_pushnumber(state, value);
lua_setfield(state, -2, name.c_str());
rive_lua_pop(state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
void ScriptedObject::setIntegerInput(std::string name, int value)
{
if (m_state == nullptr)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
lua_pushunsigned(state, value);
lua_setfield(state, -2, name.c_str());
rive_lua_pop(state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
void ScriptedObject::setStringInput(std::string name, std::string value)
{
if (m_state == nullptr)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
lua_pushstring(state, value.c_str());
lua_setfield(state, -2, name.c_str());
rive_lua_pop(state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
void ScriptedObject::setViewModelInput(std::string name,
ViewModelInstanceValue* value)
{
if (m_state == nullptr)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
switch (value->coreType())
{
case ViewModelInstanceViewModelBase::typeKey:
{
auto vm = value->as<ViewModelInstanceViewModel>();
auto vmi = vm->referenceViewModelInstance();
if (vmi == nullptr)
{
fprintf(stderr,
"riveLuaPushViewModelInstanceValue - passed in a "
"ViewModelInstanceViewModel with no associated "
"ViewModelInstance.\n");
return;
}
lua_newrive<ScriptedViewModel>(state,
state,
ref_rcp(vmi->viewModel()),
vmi);
break;
}
default:
break;
}
lua_setfield(state, -2, name.c_str());
rive_lua_pop(state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
void ScriptedObject::trigger(std::string name)
{
if (m_state == nullptr)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
if (static_cast<lua_Type>(lua_getfield(state, -1, name.c_str())) !=
LUA_TFUNCTION)
{
rive_lua_pop(state, 2);
return;
}
lua_pushvalue(state, -2);
rive_lua_pcall(state, 1, 0);
rive_lua_pop(state, 1);
addScriptedDirt(ComponentDirt::ScriptUpdate);
}
bool ScriptedObject::scriptAdvance(float elapsedSeconds)
{
if (!advances() || m_state == nullptr)
{
return false;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
if (static_cast<lua_Type>(lua_getfield(state, -1, "advance")) !=
LUA_TFUNCTION)
{
rive_lua_pop(state, 2);
return false;
}
lua_pushvalue(state, -2);
lua_pushnumber(state, elapsedSeconds);
if (static_cast<lua_Status>(rive_lua_pcall(state, 2, 1)) != LUA_OK)
{
rive_lua_pop(state, 2);
return false;
}
bool result = lua_toboolean(state, -1);
rive_lua_pop(state, 2);
return result;
}
void ScriptedObject::scriptUpdate()
{
if (!updates() || m_state == nullptr)
{
return;
}
auto state = m_state->state;
rive_lua_pushRef(state, m_self);
if (static_cast<lua_Type>(lua_getfield(state, -1, "update")) !=
LUA_TFUNCTION)
{
rive_lua_pop(state, 2);
return;
}
lua_pushvalue(state, -2);
if (static_cast<lua_Status>(rive_lua_pcall(state, 1, 0)) != LUA_OK)
{
rive_lua_pop(state, 1);
}
rive_lua_pop(state, 1);
}
bool ScriptedObject::scriptInit(LuaState* luaState)
{
auto state = luaState->state;
for (auto prop : m_customProperties)
{
auto scriptInput = ScriptInput::from(prop);
if (scriptInput && !scriptInput->validateForScriptInit())
{
rive_lua_pop(state, 1);
return false;
}
}
if (static_cast<lua_Status>(rive_lua_pcall(state, 0, 1)) != LUA_OK)
{
rive_lua_pop(state, 1);
return false;
}
if (static_cast<lua_Type>(lua_type(state, -1)) != LUA_TTABLE)
{
rive_lua_pop(state, 1);
return false;
}
else
{
lua_newrive<ScriptedContext>(state, this);
m_context = lua_ref(state, -1);
rive_lua_pop(state, 1);
m_self = lua_ref(state, -1);
m_state = luaState;
for (auto prop : m_customProperties)
{
auto scriptInput = ScriptInput::from(prop);
if (scriptInput)
{
scriptInput->initScriptedValue();
}
}
if (inits())
{
if (static_cast<lua_Type>(lua_getfield(state, -1, "init")) !=
LUA_TFUNCTION)
{
lua_unref(state, m_self);
lua_unref(state, m_context);
rive_lua_pop(state, 2);
m_state = nullptr;
m_self = 0;
m_context = 0;
return false;
}
lua_pushvalue(state, -2);
rive_lua_pushRef(state, m_context);
auto pCallResult = rive_lua_pcall(state, 2, 1);
if (static_cast<lua_Status>(pCallResult) != LUA_OK)
{
lua_unref(state, m_self);
lua_unref(state, m_context);
rive_lua_pop(state, 2);
m_state = nullptr;
m_self = 0;
m_context = 0;
return false;
}
if (!lua_toboolean(state, -1))
{
lua_unref(state, m_self);
lua_unref(state, m_context);
// Pop boolean and self table
rive_lua_pop(state, 2);
m_state = nullptr;
m_self = 0;
m_context = 0;
return false;
}
else
{
rive_lua_pop(state, 1);
assert(static_cast<lua_Type>(lua_type(state, -1)) ==
LUA_TTABLE);
rive_lua_pop(state, 1);
}
}
else
{
// Init function doesn't exist, just pop the self table
rive_lua_pop(state, 1);
}
}
return true;
}
void ScriptedObject::disposeScriptInputs()
{
for (auto prop : m_customProperties)
{
auto scriptInput = ScriptInput::from(prop);
if (scriptInput != nullptr)
{
scriptInput->scriptedObject(nullptr);
}
}
m_customProperties.clear();
}
void ScriptedObject::scriptDispose()
{
disposeScriptInputs();
if (m_state != nullptr)
{
lua_unref(m_state->state, m_self);
lua_unref(m_state->state, m_context);
#ifdef TESTING
// Force GC to collect any ScriptedArtboard instances created via
// instance()
lua_gc(m_state->state, LUA_GCCOLLECT, 0);
#endif
}
m_state = nullptr;
m_self = 0;
}
#else
void ScriptedObject::setArtboardInput(std::string name, Artboard* artboard) {}
void ScriptedObject::setBooleanInput(std::string name, bool value) {}
void ScriptedObject::setIntegerInput(std::string name, int value) {}
void ScriptedObject::setNumberInput(std::string name, float value) {}
void ScriptedObject::setStringInput(std::string name, std::string value) {}
void ScriptedObject::setViewModelInput(std::string name,
ViewModelInstanceValue* value)
{}
void ScriptedObject::trigger(std::string name) {}
bool ScriptedObject::scriptAdvance(float elapsedSeconds) { return false; }
void ScriptedObject::scriptUpdate() {}
void ScriptedObject::scriptDispose() {}
void ScriptedObject::disposeScriptInputs() {}
#endif
void ScriptedObject::reinit()
{
if (scriptAsset() != nullptr)
{
scriptAsset()->initScriptedObject(this);
}
}
ScriptAsset* ScriptedObject::scriptAsset() const
{
return (ScriptAsset*)m_fileAsset.get();
}
void ScriptedObject::setAsset(rcp<FileAsset> asset)
{
if (asset != nullptr && asset->is<ScriptAsset>())
{
FileAssetReferencer::setAsset(asset);
}
}
void ScriptedObject::markNeedsUpdate() {}