diff --git a/defold-rive/src/comp_rive_databinding.cpp b/defold-rive/src/comp_rive_databinding.cpp index 1b097f64..184ab76c 100644 --- a/defold-rive/src/comp_rive_databinding.cpp +++ b/defold-rive/src/comp_rive_databinding.cpp @@ -187,6 +187,12 @@ uint32_t CompRiveCreateViewModelInstanceRuntime(RiveComponent* component, dmhash return handle; } +rive::ViewModelInstanceRuntime* CompRiveGetViewModelInstance(RiveComponent* component) +{ + rive::ViewModelInstanceRuntime* vmir = FromHandle(component, component->m_CurrentViewModelInstanceRuntime); + return vmir; +} + bool CompRiveDestroyViewModelInstanceRuntime(RiveComponent* component, uint32_t handle) { rive::ViewModelInstanceRuntime* vmir = FromHandle(component, handle); diff --git a/defold-rive/src/comp_rive_private.h b/defold-rive/src/comp_rive_private.h index b1364d4f..5f02ee6f 100644 --- a/defold-rive/src/comp_rive_private.h +++ b/defold-rive/src/comp_rive_private.h @@ -147,7 +147,8 @@ namespace dmRive bool CompRiveRuntimeListAddInstance(RiveComponent* component, uint32_t handle, const char* path, uint32_t instance); bool CompRiveRuntimeListRemoveInstance(RiveComponent* component, uint32_t handle, const char* path, uint32_t instance); - RiveSceneData* CompRiveGetRiveSceneData(RiveComponent* component); + RiveSceneData* CompRiveGetRiveSceneData(RiveComponent* component); + rive::ViewModelInstanceRuntime* CompRiveGetViewModelInstance(RiveComponent* component); } #endif //DM_COMP_RIVE_PRIVATE_H diff --git a/defold-rive/src/res_rive_data.cpp b/defold-rive/src/res_rive_data.cpp index fa3526ca..c4867f39 100644 --- a/defold-rive/src/res_rive_data.cpp +++ b/defold-rive/src/res_rive_data.cpp @@ -36,6 +36,7 @@ namespace dmRive { static void SetupData(RiveSceneData* scene_data, rive::File* file, const char* path, HRenderContext rive_render_context) { + scene_data->m_PathHash = dmHashString64(path); scene_data->m_File = file; scene_data->m_RiveRenderContext = rive_render_context; scene_data->m_ArtboardDefault = scene_data->m_File->artboardDefault(); @@ -98,13 +99,13 @@ namespace dmRive rive::Span data((const uint8_t*)params->m_Buffer, params->m_BufferSize); // Creates DefoldRenderImage with a hashed name for each image resource - AtlasNameResolver atlas_resolver = AtlasNameResolver(params->m_Factory, render_context_res); + rive::rcp atlas_resolver(new AtlasNameResolver(params->m_Factory, render_context_res)); rive::ImportResult result; rive::rcp file = rive::File::import(data, rive_factory, &result, - (rive::FileAssetLoader*) &atlas_resolver); + atlas_resolver); if (result != rive::ImportResult::success) { @@ -113,7 +114,7 @@ namespace dmRive } RiveSceneData* scene_data = new RiveSceneData(); - scene_data->m_FileAssets.Swap(atlas_resolver.GetAssets()); + scene_data->m_FileAssets.Swap(atlas_resolver->GetAssets()); SetupData(scene_data, file.release(), params->m_Filename, render_context_res); dmResource::SetResource(params->m_Resource, scene_data); @@ -146,13 +147,13 @@ namespace dmRive rive::Factory* rive_factory = GetRiveFactory(render_context_res); - AtlasNameResolver atlas_resolver = AtlasNameResolver(params->m_Factory, render_context_res); + rive::rcp atlas_resolver(new AtlasNameResolver(params->m_Factory, render_context_res)); rive::ImportResult result; rive::rcp file = rive::File::import(data, rive_factory, &result, - &atlas_resolver); + atlas_resolver); if (result != rive::ImportResult::success) { @@ -169,7 +170,7 @@ namespace dmRive RiveSceneData* scene_data = new RiveSceneData(); - scene_data->m_FileAssets.Swap(atlas_resolver.GetAssets()); + scene_data->m_FileAssets.Swap(atlas_resolver->GetAssets()); SetupData(scene_data, file.release(), params->m_Filename, render_context_res); dmResource::SetResource(params->m_Resource, scene_data); diff --git a/defold-rive/src/res_rive_data.h b/defold-rive/src/res_rive_data.h index 0332f8b7..2f3d898d 100644 --- a/defold-rive/src/res_rive_data.h +++ b/defold-rive/src/res_rive_data.h @@ -38,6 +38,7 @@ namespace dmRive struct RiveSceneData { + dmhash_t m_PathHash; // for printing debug info rive::File* m_File; HRenderContext m_RiveRenderContext; std::unique_ptr m_ArtboardDefault; diff --git a/defold-rive/src/script_rive.cpp b/defold-rive/src/script_rive.cpp index a89c5334..bb3a6b42 100644 --- a/defold-rive/src/script_rive.cpp +++ b/defold-rive/src/script_rive.cpp @@ -30,6 +30,7 @@ #include "comp_rive_private.h" #include "rive_ddf.h" #include "res_rive_data.h" +#include "script_rive_private.h" namespace dmRive @@ -490,6 +491,154 @@ namespace dmRive return 0; } +static dmhash_t GetCanonicalPathHash(const char* path) +{ + char canonical_path[1024]; + uint32_t path_len = dmResource::GetCanonicalPath(path, canonical_path, sizeof(canonical_path)); + return dmHashBuffer64(canonical_path, path_len); +} + +// TODO: Move this function into dmScript namespace +static void PreCreateResources(lua_State* L, const char* path_str, const char** supported_exts, uint32_t num_supported_exts, dmhash_t* canonical_path_hash_out) +{ + const char* path_ext = dmResource::GetExtFromPath(path_str); + while (path_ext[0] == '.') + path_ext++; + + bool path_ok = false; + if (path_ext) + { + for (uint32_t i = 0; i < num_supported_exts; ++i) + { + const char* ext = supported_exts[i]; + + if (dmStrCaseCmp(path_ext, ext) == 0) + { + path_ok = true; + break; + } + } + } + + if (!path_ok) + { + char message[1024]; + dmSnPrintf(message, sizeof(message), "Unable to create resource, path '%s' must have any of the following extensions: ", path_str); + for (uint32_t i = 0; i < num_supported_exts; ++i) + { + dmStrlCat(message, supported_exts[i], sizeof(message)); + } + luaL_error(L, "%s", message); + } + + dmhash_t canonical_path_hash = GetCanonicalPathHash(path_str); + + HResourceDescriptor rd = 0; + ResourceResult r = ResourceGetDescriptorByHash((HResourceFactory)g_Factory, canonical_path_hash, &rd); + if (r == RESOURCE_RESULT_OK || rd != 0) + { + luaL_error(L, "Unable to create resource, a resource is already registered at path '%s'", path_str); + } + + *canonical_path_hash_out = canonical_path_hash; +} + +static void PreCreateResource(lua_State* L, const char* path_str, const char* path_ext_wanted, dmhash_t* canonical_path_hash_out) +{ + PreCreateResources(L, path_str, &path_ext_wanted, 1, canonical_path_hash_out); +} + +static void PushResourceError(lua_State* L, ResourceResult result, dmhash_t path_hash) +{ + const char* format = 0; + switch(result) + { + case RESOURCE_RESULT_RESOURCE_NOT_FOUND: format = "The resource was not found (%d): %llu, %s"; break; + case RESOURCE_RESULT_NOT_SUPPORTED: format = "The resource type does not support this operation (%d): %llu, %s"; break; + default: format = "The resource was not updated (%d): %llu, %s"; break; + } + lua_pushfstring(L, format, (unsigned long long)path_hash, dmHashReverseSafe64(path_hash)); +} + +// TODO: from internal script_resource.cpp. Move to public dmsdk +static int ReportPathError(lua_State* L, ResourceResult result, dmhash_t path_hash) +{ + char msg[256]; + const char* format = 0; + switch(result) + { + case RESOURCE_RESULT_RESOURCE_NOT_FOUND: format = "The resource was not found (%d): %llu, %s"; break; + case RESOURCE_RESULT_NOT_SUPPORTED: format = "The resource type does not support this operation (%d): %llu, %s"; break; + default: format = "The resource was not updated (%d): %llu, %s"; break; + } + dmSnPrintf(msg, sizeof(msg), format, result, (unsigned long long)path_hash, dmHashReverseSafe64(path_hash)); + return luaL_error(L, "%s", msg); +} + +// TODO: from internal script_resource.cpp. Move to public dmsdk +static void* CheckResource(lua_State* L, dmResource::HFactory factory, dmhash_t path_hash, const char* resource_ext) +{ + HResourceDescriptor rd = 0; + ResourceResult r = ResourceGetDescriptorByHash((HResourceFactory)factory, path_hash, &rd); + if (r != RESOURCE_RESULT_OK) + { + luaL_error(L, "Could not get %s type resource: %s", resource_ext, dmHashReverseSafe64(path_hash)); + return 0; + } + + HResourceType expected_resource_type; + r = ResourceGetTypeFromExtension(factory, resource_ext, &expected_resource_type); + if( r != RESOURCE_RESULT_OK ) + { + ReportPathError(L, r, path_hash); + } + + HResourceType resource_type = ResourceDescriptorGetType(rd); + if (resource_type != expected_resource_type) + { + luaL_error(L, "Resource %s is not of type %s.", dmHashReverseSafe64(path_hash), resource_ext); + return 0; + } + + return ResourceDescriptorGetResource(rd); +} + +static int RiveComp_CreateRivFromMemory(lua_State* L) +{ + int top = lua_gettop(L); + + const char* path = luaL_checkstring(L, 1); // path to be associated with this resource + + size_t data_length = 0; + const char* data = luaL_checklstring(L, 2, &data_length); + + dmGameObject::HInstance instance = dmScript::CheckGOInstance(L); + dmGameObject::HCollection collection = dmGameObject::GetCollection(instance); + + dmhash_t path_hash; + PreCreateResource(L, path, "rivc", &path_hash); // create the hash, and check that no other resource is registered with the same hash + + void* resource = 0; + ResourceResult r = ResourceCreateResource(g_Factory, path, (void*)data, data_length, &resource); + if (r != RESOURCE_RESULT_OK) + { + assert(top == lua_gettop(L)); + + lua_pushnil(L); + PushResourceError(L, r, path_hash); + return 2; + } + + // Pass ownership of the resource to the current collection + dmGameObject::AddDynamicResourceHash(collection, path_hash); + dmScript::PushHash(L, path_hash); + lua_pushnil(L); + + assert((top+2) == lua_gettop(L)); + return 2; +} + + // This is an "all bets are off" mode. static int RiveComp_DebugSetBlitMode(lua_State* L) { @@ -521,17 +670,23 @@ namespace dmRive {"debug_set_blit_mode", RiveComp_DebugSetBlitMode}, {"riv_swap_asset", RiveComp_RivSwapAsset}, + + {"create_riv_from_memory", RiveComp_CreateRivFromMemory}, {0, 0} }; - extern void ScriptInitializeDataBinding(lua_State* L, dmResource::HFactory factory); - void ScriptRegister(lua_State* L, dmResource::HFactory factory) { + // deprecated luaL_register(L, "rive", RIVE_FUNCTIONS); ScriptInitializeDataBinding(L, factory); lua_pop(L, 1); + ScriptInitializeFile(L, factory); + ScriptInitializeArtboard(L, factory); + ScriptInitializeViewModel(L, factory); + ScriptInitializeViewModelProperty(L, factory); + g_Factory = factory; } } diff --git a/defold-rive/src/script_rive_artboard.cpp b/defold-rive/src/script_rive_artboard.cpp new file mode 100644 index 00000000..6d3f0657 --- /dev/null +++ b/defold-rive/src/script_rive_artboard.cpp @@ -0,0 +1,136 @@ +// Copyright 2021 The Defold Foundation +// Licensed under the Defold License version 1.0 (the "License"); you may not use +// this file except in compliance with the License. +// +// You may obtain a copy of the License, together with FAQs at +// https://www.defold.com/license +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + + +#if !defined(DM_RIVE_UNSUPPORTED) + +#include + +#include +#include +#include +#include +#include + +#include "comp_rive.h" +#include "comp_rive_private.h" +#include "res_rive_data.h" +#include "script_rive_private.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Artboard +#include +#include + + +namespace dmRive +{ + +static dmResource::HFactory g_Factory = 0; + +static const char* SCRIPT_TYPE_NAME_ARTBOARD = "Artboard"; +static uint32_t TYPE_HASH_ARTBOARD = 0; + + +// ********************************************************************************* + +static bool IsArtboard(lua_State* L, int index) +{ + return dmScript::GetUserType(L, index) == TYPE_HASH_ARTBOARD; +} + +static Artboard* ToArtboard(lua_State* L, int index) +{ + return (Artboard*)dmScript::ToUserType(L, index, TYPE_HASH_ARTBOARD); +} + +static int Artboard_tostring(lua_State* L) +{ + Artboard* artboard = ToArtboard(L, 1); + if (!artboard) + { + lua_pushstring(L, "no valid pointer!"); + return 1; + } + lua_pushfstring(L, "rive.artboard(%p : '%s')", artboard, artboard->m_Instance ? artboard->m_Instance->name().c_str() : "null"); + return 1; +} + +static int Artboard_eq(lua_State* L) +{ + Artboard* a1 = ToArtboard(L, 1); + Artboard* a2 = ToArtboard(L, 2); + lua_pushboolean(L, a1 && a2 && a1 == a2); + return 1; +} + +static int Artboard_gc(lua_State* L) +{ + Artboard* artboard = ToArtboard(L, 1); + delete artboard->m_Instance; + dmResource::Release(g_Factory, artboard->m_Resource); + return 0; +} + +static const luaL_reg Artboard_methods[] = +{ + {0,0} +}; + +static const luaL_reg Artboard_meta[] = +{ + {"__tostring", Artboard_tostring}, + {"__eq", Artboard_eq}, + {"__gc", Artboard_gc}, + {0,0} +}; + +void PushArtboard(lua_State* L, RiveSceneData* resource, rive::ArtboardInstance* instance) +{ + Artboard* artboard = (Artboard*)lua_newuserdata(L, sizeof(Artboard)); + artboard->m_Resource = resource; + artboard->m_Instance = instance; + luaL_getmetatable(L, SCRIPT_TYPE_NAME_ARTBOARD); + lua_setmetatable(L, -2); + dmResource::IncRef(g_Factory, resource); +} + +Artboard* CheckArtboard(lua_State* L, int index) +{ + Artboard* artboard = (Artboard*)dmScript::CheckUserType(L, index, TYPE_HASH_ARTBOARD, 0); + return artboard; +} + +void ScriptInitializeArtboard(lua_State* L, dmResource::HFactory factory) +{ + int top = lua_gettop(L); + + g_Factory = factory; + + TYPE_HASH_ARTBOARD = dmScript::RegisterUserType(L, SCRIPT_TYPE_NAME_ARTBOARD, Artboard_methods, Artboard_meta); + + assert(top == lua_gettop(L)); +} + +} + +#endif // DM_RIVE_UNSUPPORTED diff --git a/defold-rive/src/script_rive_file.cpp b/defold-rive/src/script_rive_file.cpp new file mode 100644 index 00000000..7d351fb2 --- /dev/null +++ b/defold-rive/src/script_rive_file.cpp @@ -0,0 +1,264 @@ +// Copyright 2021 The Defold Foundation +// Licensed under the Defold License version 1.0 (the "License"); you may not use +// this file except in compliance with the License. +// +// You may obtain a copy of the License, together with FAQs at +// https://www.defold.com/license +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + + +#if !defined(DM_RIVE_UNSUPPORTED) + +#include + +#include +#include +#include +#include +#include + +#include "comp_rive.h" +#include "comp_rive_private.h" +#include "res_rive_data.h" +#include "script_rive_private.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Artboard +#include +#include + + +namespace dmRive +{ + +static dmResource::HFactory g_Factory = 0; + +static dmhash_t RESOURCE_TYPE_HASH_RIVC = dmHashString64("rivc"); +static const char* SCRIPT_TYPE_NAME_RIVE_FILE = "RiveFile"; +static uint32_t TYPE_HASH_RIVE_FILE = 0; + +static bool IsTypeRivc(HResourceFactory factory, dmhash_t path_hash) +{ + HResourceDescriptor rd = 0; + ResourceResult result = ResourceGetDescriptorByHash(factory, path_hash, &rd); + if (RESOURCE_RESULT_OK != result) + { + return false; + } + HResourceType type = ResourceDescriptorGetType(rd); + dmhash_t type_hash = ResourceTypeGetNameHash(type); + return type_hash == RESOURCE_TYPE_HASH_RIVC; +} + + + +// ********************************************************************************* + + +bool IsRiveFile(lua_State* L, int index) +{ + return dmScript::GetUserType(L, index) == TYPE_HASH_RIVE_FILE; +} + +RiveFile* ToRiveFile(lua_State* L, int index) +{ + return (RiveFile*)dmScript::ToUserType(L, index, TYPE_HASH_RIVE_FILE); +} + +void PushRiveFile(lua_State* L, RiveSceneData* resource) +{ + RiveFile* file = (RiveFile*)lua_newuserdata(L, sizeof(RiveFile)); + file->m_Resource = resource; + luaL_getmetatable(L, SCRIPT_TYPE_NAME_RIVE_FILE); + lua_setmetatable(L, -2); + dmResource::IncRef(g_Factory, resource); +} + +RiveFile* CheckRiveFile(lua_State* L, int index) +{ + RiveFile* file = (RiveFile*)dmScript::CheckUserType(L, index, TYPE_HASH_RIVE_FILE, 0); + return file; +} + +static int RiveFile_tostring(lua_State* L) +{ + RiveFile* file = ToRiveFile(L, 1); + if (!file) + { + lua_pushstring(L, "no valid pointer!"); + return 1; + } + lua_pushfstring(L, "%s.file(%p : '%s')", "rive", file, dmHashReverseSafe64(file->m_Resource->m_PathHash)); + return 1; +} + +static int RiveFile_eq(lua_State* L) +{ + RiveFile* f1 = ToRiveFile(L, 1); + RiveFile* f2 = ToRiveFile(L, 2); + lua_pushboolean(L, f1 && f2 && f1 == f2); + return 1; +} + +static int RiveFile_gc(lua_State* L) +{ + RiveFile* file = ToRiveFile(L, 1); + dmResource::Release(g_Factory, file->m_Resource); + return 0; +} + +static int RiveFileGetArtboard(lua_State* L) +{ + DM_LUA_STACK_CHECK(L, 1); + RiveFile* file = CheckRiveFile(L, 1); + + const char* name = 0; + int index = -1; + + switch(lua_type(L, 2)) + { + case LUA_TSTRING: name = luaL_checkstring(L, 2); break; + case LUA_TNUMBER: index = luaL_checknumber(L, 2); break; + default: break; + } + + rive::ArtboardInstance* artboard = 0; + if (name) + { + artboard = file->m_Resource->m_File->artboardNamed(name).release(); + if (!artboard) + { + return DM_LUA_ERROR("No artboard named '%s' in file '%s'", name, dmHashReverseSafe64(file->m_Resource->m_PathHash)); + } + } + else if(index >= 0) + { + artboard = file->m_Resource->m_File->artboardAt((size_t)index).release(); + if (!artboard) + { + return DM_LUA_ERROR("No artboard named at index %d in file '%s'", index, dmHashReverseSafe64(file->m_Resource->m_PathHash)); + } + } + else + { + artboard = file->m_Resource->m_File->artboardDefault().release(); + if (!artboard) + { + return DM_LUA_ERROR("No default artboard in file '%s'", dmHashReverseSafe64(file->m_Resource->m_PathHash)); + } + } + + PushArtboard(L, file->m_Resource, artboard); + return 1; +} + +static int RiveFileGetPath(lua_State* L) +{ + RiveFile* file = CheckRiveFile(L, 1); + lua_pushstring(L, dmHashReverseSafe64(file->m_Resource->m_PathHash)); + return 1; +} + +static int RiveFileGetFileFromPath(lua_State* L) +{ + int top = lua_gettop(L); + + dmhash_t path_hash = dmScript::CheckHashOrString(L, 1); // the resource to get the artboard from + + if (!IsTypeRivc(g_Factory, path_hash)) + { + luaL_error(L, "Requested resource was not of type 'rivc': %s", dmHashReverseSafe64(path_hash)); + return 0; + } + + dmRive::RiveSceneData* resource; + dmResource::Result r = dmResource::Get(g_Factory, path_hash, (void**)&resource); + if (dmResource::RESULT_OK != r) + { + luaL_error(L, "Resource was not found: '%s'", dmHashReverseSafe64(path_hash)); + return 0; + } + + PushRiveFile(L, resource); + // since the PushRiveFile incref'ed it too, we need to release it once + dmResource::Release(g_Factory, resource); + + assert((top+1) == lua_gettop(L)); + return 1; +} + +static int RiveFileGetFileFromUrl(lua_State* L) +{ + int top = lua_gettop(L); + + RiveComponent* component = 0; + dmScript::GetComponentFromLua(L, 1, dmRive::RIVE_MODEL_EXT, 0, (void**)&component, 0); + RiveSceneData* resource = CompRiveGetRiveSceneData(component); + if (!resource) + { + return luaL_error(L, "Failed to get rive resource from '%s'", lua_tostring(L, 1)); + } + + PushRiveFile(L, resource); + + assert((top+1) == lua_gettop(L)); + return 1; +} + +// ********************************************************************************* + +static const luaL_reg RiveFile_methods[] = +{ + {"get_path", RiveFileGetPath}, + {"get_artboard",RiveFileGetArtboard}, + {0,0} +}; + +static const luaL_reg RiveFile_meta[] = +{ + {"__tostring", RiveFile_tostring}, + {"__eq", RiveFile_eq}, + {"__gc", RiveFile_gc}, + {0,0} +}; + +static const luaL_reg RiveFile_functions[] = +{ + {"get_file_from_path", RiveFileGetFileFromPath}, + {"get_file_from_url", RiveFileGetFileFromUrl}, + {0, 0} +}; + +// ********************************************************************************* + +void ScriptInitializeFile(lua_State* L, dmResource::HFactory factory) +{ + int top = lua_gettop(L); + + g_Factory = factory; + + TYPE_HASH_RIVE_FILE = dmScript::RegisterUserType(L, SCRIPT_TYPE_NAME_RIVE_FILE, RiveFile_methods, RiveFile_meta); + + luaL_register(L, "rive", RiveFile_functions); + lua_pop(L, 1); + + assert(top == lua_gettop(L)); +} + +} + +#endif // DM_RIVE_UNSUPPORTED diff --git a/defold-rive/src/script_rive_private.h b/defold-rive/src/script_rive_private.h new file mode 100644 index 00000000..ad74dae4 --- /dev/null +++ b/defold-rive/src/script_rive_private.h @@ -0,0 +1,91 @@ +// Copyright 2020 The Defold Foundation +// Licensed under the Defold License version 1.0 (the "License"); you may not use +// this file except in compliance with the License. +// +// You may obtain a copy of the License, together with FAQs at +// https://www.defold.com/license +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef DM_GAMESYS_SCRIPT_RIVE_PRIVATE_H +#define DM_GAMESYS_SCRIPT_RIVE_PRIVATE_H + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Artboard +#include +#include + +namespace rive +{ + class ArtboardInstance; + class ViewModelInstanceRuntime; + class ViewModelInstanceValueRuntime; +} + +namespace dmRive +{ + struct RiveFile + { + RiveSceneData* m_Resource; + }; + + struct Artboard + { + RiveSceneData* m_Resource; // The original file that it belongs to + rive::ArtboardInstance* m_Instance; // The instance + }; + + struct ViewModel + { + RiveSceneData* m_Resource; // The original file that it belongs to + rive::ViewModelInstanceRuntime* m_Instance; // The instance + }; + + struct ViewModelProperty + { + RiveSceneData* m_Resource; // The original file that it belongs to + rive::ViewModelInstanceValueRuntime* m_Instance; // The instance + }; + + bool IsRiveFile(lua_State* L, int index); + void PushRiveFile(lua_State* L, RiveSceneData* resource); + RiveFile* ToRiveFile(lua_State* L, int index); + RiveFile* CheckRiveFile(lua_State* L, int index); + + void PushArtboard(lua_State* L, RiveSceneData* resource, rive::ArtboardInstance* instance); + Artboard* CheckArtboard(lua_State* L, int index); + + void PushViewModel(lua_State* L, RiveSceneData* resource, rive::ViewModelInstanceRuntime* instance); + ViewModel* CheckViewModel(lua_State* L, int index); + + void PushViewModelProperty(lua_State* L, RiveSceneData* resource, rive::ViewModelInstanceValueRuntime* instance); + ViewModelProperty* CheckViewModelProperty(lua_State* L, int index); + + void ScriptInitializeFile(lua_State* L, dmResource::HFactory factory); + void ScriptInitializeArtboard(lua_State* L, dmResource::HFactory factory); + void ScriptInitializeViewModel(lua_State* L, dmResource::HFactory factory); + void ScriptInitializeViewModelProperty(lua_State* L, dmResource::HFactory factory); + + // Deprecated + void ScriptInitializeDataBinding(lua_State* L, dmResource::HFactory factory); +} + +#endif // DM_GAMESYS_SCRIPT_RIVE_PRIVATE_H diff --git a/defold-rive/src/script_rive_viewmodel.cpp b/defold-rive/src/script_rive_viewmodel.cpp new file mode 100644 index 00000000..a07fda28 --- /dev/null +++ b/defold-rive/src/script_rive_viewmodel.cpp @@ -0,0 +1,182 @@ +// Copyright 2021 The Defold Foundation +// Licensed under the Defold License version 1.0 (the "License"); you may not use +// this file except in compliance with the License. +// +// You may obtain a copy of the License, together with FAQs at +// https://www.defold.com/license +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + + +#if !defined(DM_RIVE_UNSUPPORTED) + +#include + +// #include +// #include +#include +#include + +#include "comp_rive.h" +#include "comp_rive_private.h" +#include "res_rive_data.h" +#include "script_rive_private.h" + +#include +#include +#include + +namespace dmRive +{ + +static dmResource::HFactory g_Factory = 0; + +static const char* SCRIPT_TYPE_NAME_VIEWMODEL = "ViewModel"; +static uint32_t TYPE_HASH_VIEWMODEL = 0; + +// ********************************************************************************* + +static bool IsViewModel(lua_State* L, int index) +{ + return dmScript::GetUserType(L, index) == TYPE_HASH_VIEWMODEL; +} + +static ViewModel* ToViewModel(lua_State* L, int index) +{ + return (ViewModel*)dmScript::ToUserType(L, index, TYPE_HASH_VIEWMODEL); +} + +static int ViewModel_tostring(lua_State* L) +{ + ViewModel* viewmodel = ToViewModel(L, 1); + if (!viewmodel) + { + lua_pushstring(L, "no valid pointer!"); + return 1; + } + lua_pushfstring(L, "rive.viewmodel(%p : '%s')", viewmodel, viewmodel->m_Instance ? viewmodel->m_Instance->name().c_str() : "null"); + return 1; +} + +static int ViewModel_eq(lua_State* L) +{ + ViewModel* v1 = ToViewModel(L, 1); + ViewModel* v2 = ToViewModel(L, 2); + lua_pushboolean(L, v1 && v2 && v1 == v2); + return 1; +} + +static int ViewModel_gc(lua_State* L) +{ + //printf("ViewModel_gc: begin\n"); + //fflush(stdout); + + ViewModel* viewmodel = ToViewModel(L, 1); + delete viewmodel->m_Instance; + //printf("ViewModel_gc: %p : %p", viewmodel, viewmodel->m_Instance); + //fflush(stdout); + + dmResource::Release(g_Factory, viewmodel->m_Resource); + + //printf("ViewModel_gc: end\n"); + //fflush(stdout); + return 0; +} + +static int ViewModelGetViewModel(lua_State* L) +{ + RiveComponent* component = 0; + dmScript::GetComponentFromLua(L, 1, dmRive::RIVE_MODEL_EXT, 0, (void**)&component, 0); + RiveSceneData* resource = CompRiveGetRiveSceneData(component); + rive::ViewModelInstanceRuntime* instance = CompRiveGetViewModelInstance(component); + if (instance) + { + PushViewModel(L, resource, instance); + } + else + { + lua_pushnil(L); + } + + return 1; +} + +static int ViewModelGetProperty(lua_State* L) +{ + DM_LUA_STACK_CHECK(L, 1); + ViewModel* viewmodel = CheckViewModel(L, 1); + const char* property_path = luaL_checkstring(L, 2);; + + rive::ViewModelInstanceValueRuntime* property = viewmodel->m_Instance->property(property_path); + if (!property) + { + return DM_LUA_ERROR("No property found with path '%s'", property_path); + } + + + printf("ViewModelGetProperty: %p : %p -> %p", viewmodel, viewmodel->m_Instance, property); + PushViewModelProperty(L, viewmodel->m_Resource, property); + return 1; +} + + +// ********************************************************************************* + +static const luaL_reg ViewModel_methods[] = +{ + {"get_property", ViewModelGetProperty}, + {0,0} +}; + +static const luaL_reg ViewModel_meta[] = +{ + {"__tostring", ViewModel_tostring}, + {"__eq", ViewModel_eq}, + {"__gc", ViewModel_gc}, + {0,0} +}; + +static const luaL_reg ViewModel_functions[] = +{ + {"get_viewmodel", ViewModelGetViewModel}, + {0, 0} +}; + +// ********************************************************************************* + +void PushViewModel(lua_State* L, RiveSceneData* resource, rive::ViewModelInstanceRuntime* instance) +{ + ViewModel* viewmodel = (ViewModel*)lua_newuserdata(L, sizeof(ViewModel)); + viewmodel->m_Resource = resource; + viewmodel->m_Instance = instance; + luaL_getmetatable(L, SCRIPT_TYPE_NAME_VIEWMODEL); + lua_setmetatable(L, -2); + dmResource::IncRef(g_Factory, resource); +} + +ViewModel* CheckViewModel(lua_State* L, int index) +{ + ViewModel* viewmodel = (ViewModel*)dmScript::CheckUserType(L, index, TYPE_HASH_VIEWMODEL, 0); + return viewmodel; +} + +void ScriptInitializeViewModel(lua_State* L, dmResource::HFactory factory) +{ + int top = lua_gettop(L); + + g_Factory = factory; + + TYPE_HASH_VIEWMODEL = dmScript::RegisterUserType(L, SCRIPT_TYPE_NAME_VIEWMODEL, ViewModel_methods, ViewModel_meta); + + luaL_register(L, "rive", ViewModel_functions); + lua_pop(L, 1); + + assert(top == lua_gettop(L)); +} + +} + +#endif // DM_RIVE_UNSUPPORTED diff --git a/defold-rive/src/script_rive_viewmodel_property.cpp b/defold-rive/src/script_rive_viewmodel_property.cpp new file mode 100644 index 00000000..e6905c12 --- /dev/null +++ b/defold-rive/src/script_rive_viewmodel_property.cpp @@ -0,0 +1,269 @@ +// Copyright 2021 The Defold Foundation +// Licensed under the Defold License version 1.0 (the "License"); you may not use +// this file except in compliance with the License. +// +// You may obtain a copy of the License, together with FAQs at +// https://www.defold.com/license +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + + +#if !defined(DM_RIVE_UNSUPPORTED) + +#include + +// #include +// #include +#include +#include + +#include "comp_rive.h" +#include "comp_rive_private.h" +#include "res_rive_data.h" +#include "script_rive_private.h" + +#include +#include +#include + +namespace dmRive +{ + +static dmResource::HFactory g_Factory = 0; + +static const char* SCRIPT_TYPE_NAME_VIEWMODEL_PROPERTY = "ViewModelProperty"; +static uint32_t TYPE_HASH_VIEWMODEL_PROPERTY = 0; + +// ********************************************************************************* + +static bool IsViewModelProperty(lua_State* L, int index) +{ + return dmScript::GetUserType(L, index) == TYPE_HASH_VIEWMODEL_PROPERTY; +} + +static ViewModelProperty* ToViewModelProperty(lua_State* L, int index) +{ + return (ViewModelProperty*)dmScript::ToUserType(L, index, TYPE_HASH_VIEWMODEL_PROPERTY); +} + +void PushViewModelProperty(lua_State* L, RiveSceneData* resource, rive::ViewModelInstanceValueRuntime* instance) +{ + ViewModelProperty* viewmodel = (ViewModelProperty*)lua_newuserdata(L, sizeof(ViewModelProperty)); + viewmodel->m_Resource = resource; + viewmodel->m_Instance = instance; + luaL_getmetatable(L, SCRIPT_TYPE_NAME_VIEWMODEL_PROPERTY); + lua_setmetatable(L, -2); + dmResource::IncRef(g_Factory, resource); +} + +ViewModelProperty* CheckViewModelProperty(lua_State* L, int index) +{ + ViewModelProperty* viewmodel = (ViewModelProperty*)dmScript::CheckUserType(L, index, TYPE_HASH_VIEWMODEL_PROPERTY, 0); + return viewmodel; +} + +// ********************************************************************************* + +static const char* DataTypeToString(rive::DataType type) +{ + #define DATATYPE_CASE(_NAME) case rive::DataType:: _NAME : return # _NAME; + switch(type) + { + DATATYPE_CASE(none); + DATATYPE_CASE(string); + DATATYPE_CASE(number); + DATATYPE_CASE(boolean); + DATATYPE_CASE(color); + DATATYPE_CASE(list); + DATATYPE_CASE(enumType); + DATATYPE_CASE(trigger); + DATATYPE_CASE(viewModel); + DATATYPE_CASE(integer); + DATATYPE_CASE(symbolListIndex); + DATATYPE_CASE(assetImage); + DATATYPE_CASE(artboard); + DATATYPE_CASE(input); + default: return "unknown"; + }; + #undef DATATYPE_CASE +} + +static int ViewModelProperty_tostring(lua_State* L) +{ + ViewModelProperty* prop = ToViewModelProperty(L, 1); + if (!prop) + { + lua_pushstring(L, "no valid pointer!"); + return 1; + } + + const char* typestr = DataTypeToString(prop->m_Instance->dataType()); + + lua_pushfstring(L, "rive.viewmodelprop(%p : '%s', '%s')", + prop, prop->m_Instance ? prop->m_Instance->name().c_str() : "null", typestr); + return 1; +} + +static int ViewModelProperty_eq(lua_State* L) +{ + ViewModelProperty* v1 = ToViewModelProperty(L, 1); + ViewModelProperty* v2 = ToViewModelProperty(L, 2); + lua_pushboolean(L, v1 && v2 && v1 == v2); + return 1; +} + +static int ViewModelProperty_gc(lua_State* L) +{ + ViewModelProperty* prop = ToViewModelProperty(L, 1); + dmResource::Release(g_Factory, prop->m_Resource); + return 0; +} + +static int ViewModelPropertyName(lua_State* L) +{ + ViewModelProperty* prop = CheckViewModelProperty(L, 1); + lua_pushstring(L, prop->m_Instance->name().c_str()); + return 1; +} + +static int ViewModelPropertyType(lua_State* L) +{ + ViewModelProperty* prop = CheckViewModelProperty(L, 1); + lua_pushinteger(L, (int)prop->m_Instance->dataType()); + return 1; +} + +static dmVMath::Vector4 GetColor(rive::ViewModelInstanceValueRuntime* _prop) +{ + rive::ViewModelInstanceColorRuntime* prop = (rive::ViewModelInstanceColorRuntime*)_prop; + + uint32_t argb = (uint32_t)prop->value(); + float a = ((argb >> 24) & 0xFF) / 255.0f; + float r = ((argb >> 16) & 0xFF) / 255.0f; + float g = ((argb >> 8) & 0xFF) / 255.0f; + float b = ((argb >> 0) & 0xFF) / 255.0f; + return dmVMath::Vector4(r, g, b, a); +} + +static void SetArtboard(rive::ViewModelInstanceValueRuntime* _prop, rive::ArtboardInstance* instance) +{ + rive::ViewModelInstanceArtboardRuntime* prop = (rive::ViewModelInstanceArtboardRuntime*)_prop; + prop->value(instance); +} + +static int ViewModelPropertyGet(lua_State* L) +{ + DM_LUA_STACK_CHECK(L, 1); + + ViewModelProperty* prop = CheckViewModelProperty(L, 1); + rive::DataType type = prop->m_Instance->dataType(); + + switch(type) + { + case rive::DataType::number: lua_pushnumber(L, ((rive::ViewModelInstanceNumberRuntime*)prop->m_Instance)->value()); break; + case rive::DataType::string: lua_pushstring(L, ((rive::ViewModelInstanceStringRuntime*)prop->m_Instance)->value().c_str()); break; + case rive::DataType::enumType: lua_pushstring(L, ((rive::ViewModelInstanceEnumRuntime*)prop->m_Instance)->value().c_str()); break; + case rive::DataType::boolean: lua_pushboolean(L, ((rive::ViewModelInstanceBooleanRuntime*)prop->m_Instance)->value()); break; + case rive::DataType::color: dmScript::PushVector4(L, GetColor(prop->m_Instance)); break; + + + // todo: support + case rive::DataType::list: + case rive::DataType::viewModel: + case rive::DataType::integer: + case rive::DataType::symbolListIndex: + case rive::DataType::assetImage: + case rive::DataType::input: + + // not gettable + case rive::DataType::artboard: + case rive::DataType::trigger: + case rive::DataType::none: + default: + dmLogError("Property '%s': Type has no gettable value: %d (%s)", + prop->m_Instance->name().c_str(), type, DataTypeToString(type)); + lua_pushnil(L); + } + + return 1; +} + +static int ViewModelPropertySet(lua_State* L) +{ + DM_LUA_STACK_CHECK(L, 0); + + ViewModelProperty* prop = CheckViewModelProperty(L, 1); + rive::DataType type = prop->m_Instance->dataType(); + + switch(type) + { + // case rive::DataType::number: lua_pushnumber(L, ((rive::ViewModelInstanceNumberRuntime*)prop->m_Instance)->value()); break; + // case rive::DataType::string: lua_pushstring(L, ((rive::ViewModelInstanceStringRuntime*)prop->m_Instance)->value().c_str()); break; + // case rive::DataType::enumType: lua_pushstring(L, ((rive::ViewModelInstanceEnumRuntime*)prop->m_Instance)->value().c_str()); break; + // case rive::DataType::boolean: lua_pushboolean(L, ((rive::ViewModelInstanceBooleanRuntime*)prop->m_Instance)->value()); break; + // case rive::DataType::color: dmScript::PushVector4(L, GetColor(prop->m_Instance)); break; + + case rive::DataType::artboard: + { + Artboard* artboard = CheckArtboard(L, 2); + SetArtboard(prop->m_Instance, artboard->m_Instance); + } + break; + + // todo: support + case rive::DataType::list: + case rive::DataType::viewModel: + case rive::DataType::integer: + case rive::DataType::symbolListIndex: + case rive::DataType::assetImage: + case rive::DataType::input: + + // not settable + case rive::DataType::trigger: + case rive::DataType::none: + default: + dmLogError("Property '%s': Type has no settable value: %d (%s)", + prop->m_Instance->name().c_str(), type, DataTypeToString(type)); + } + + return 0; +} + +// ********************************************************************************* + +static const luaL_reg ViewModelProperty_methods[] = +{ + {"get", ViewModelPropertyGet}, + {"set", ViewModelPropertySet}, + {"name", ViewModelPropertyName}, + {"type", ViewModelPropertyType}, + {0,0} +}; + +static const luaL_reg ViewModelProperty_meta[] = +{ + {"__tostring", ViewModelProperty_tostring}, + {"__eq", ViewModelProperty_eq}, + {"__gc", ViewModelProperty_gc}, + {0,0} +}; + +// ********************************************************************************* + +void ScriptInitializeViewModelProperty(lua_State* L, dmResource::HFactory factory) +{ + int top = lua_gettop(L); + + g_Factory = factory; + + TYPE_HASH_VIEWMODEL_PROPERTY = dmScript::RegisterUserType(L, SCRIPT_TYPE_NAME_VIEWMODEL_PROPERTY, ViewModelProperty_methods, ViewModelProperty_meta); + + assert(top == lua_gettop(L)); +} + +} + +#endif // DM_RIVE_UNSUPPORTED diff --git a/main/car/car.rivemodel b/main/car/car.rivemodel index 478174ff..47ea34ad 100644 --- a/main/car/car.rivemodel +++ b/main/car/car.rivemodel @@ -1,5 +1,3 @@ scene: "/main/car/car.rivescene" -default_animation: "idle" +default_animation: "" material: "/defold-rive/assets/rivemodel.material" -blend_mode: BLEND_MODE_ALPHA -default_state_machine: "" diff --git a/main/databind-artboard/databind-artboard.collection b/main/databind-artboard/databind-artboard.collection new file mode 100644 index 00000000..273fb2ee --- /dev/null +++ b/main/databind-artboard/databind-artboard.collection @@ -0,0 +1,38 @@ +name: "scrollist" +instances { + id: "back" + prototype: "/main/menu/back.go" +} +scale_along_z: 0 +embedded_instances { + id: "go" + data: "components {\n" + " id: \"swap_character_main\"\n" + " component: \"/main/databind-artboard/swap_character_main.rivemodel\"\n" + "}\n" + "components {\n" + " id: \"databind-artboard\"\n" + " component: \"/main/databind-artboard/databind-artboard.script\"\n" + "}\n" + "" + position { + x: 482.0 + y: 272.0 + } + scale3 { + x: 0.49 + y: 0.49 + } +} +embedded_instances { + id: "go1" + data: "components {\n" + " id: \"swap_character_assets\"\n" + " component: \"/main/databind-artboard/swap_character_assets.rivemodel\"\n" + "}\n" + "" + position { + x: -711.0 + y: 75.0 + } +} diff --git a/main/databind-artboard/databind-artboard.script b/main/databind-artboard/databind-artboard.script new file mode 100644 index 00000000..fb6eeb60 --- /dev/null +++ b/main/databind-artboard/databind-artboard.script @@ -0,0 +1,119 @@ + +local URL = "https://github.com/defold/extension-rive/raw/refs/heads/main/assets/rive/marty_v2.riv" + +local function create_resource(self, path, file_data) + local hash, error = rive.create_riv_from_memory(path, file_data) + if hash == nil then + print("Failed to create resource", path) + return nil + end + return hash +end + +-- local function create_thumb(self, image_data) +-- local thumb, errThumb = rive.databind.create_view_model_instance_runtime(self.rive_url, "ThumbVM") +-- if thumb == nil then +-- print("Failed to create view model instance:", errThumb) +-- return +-- end +-- table.insert(self.thumbs, thumb) + +-- rive.databind.set_properties(self.rive_url, thumb, {Border = 10, Image = image_data}) +-- -- add the thumb last in the list +-- rive.databind.list_add_instance(self.rive_url, self.modelViewInstanceRuntime, self.list_path, thumb) + +-- -- update borders +-- set_selected_thumb(self, #self.thumbs - 1) +-- end + +local function download_riv_file(self, path, image_url, callback) + http.request(image_url, "GET", function (self, _id, response) + if response.status == 200 or response.status == 206 or response.status == 304 then + print("downloaded", response.url, "length:", #response.response) + local hash = create_resource(self, path, response.response) + callback(path) + elseif response.status == 302 then + -- redirect + download_riv_file(self, path, response.headers.location, callback) + end + end) +end + +-- local function request_thumb(self, url) +-- print("Requesting new thumb") +-- download_image(self.modelViewInstanceRuntime, url) +-- end + +-- local function remove_thumb(self, index) +-- print("Removing thumb at index", index) +-- local thumb = table.remove(self.thumbs, index) +-- rive.databind.list_remove_instance(self.rive_url, self.modelViewInstanceRuntime, self.list_path, thumb) +-- set_selected_thumb(self, index-1) +-- end + +local function load_artboard_file(path) + local data, error = sys.load_resource(path) + if data then + print("Success", data) + else + print(error) + end +end + +local function attachCharacter(self) + rive.databind.set_properties() +end + +-- Rive events trigger when the splash intro starts and ends and is used to not allow input while the intro is playing. +-- The logic is done within the rive statemachine. +local function rive_event_handler(self, messagse_id, message) + print("received event", message.name) +end + +local function attach_character(self) + if self.character_artboard and self.viewModelInstanceArtboardProp then + self.viewModelInstanceArtboardProp:set(self.character_artboard) + end +end + +-- Get input focus then start the splash statemachine. +function init(self) + msg.post(".", "acquire_input_focus") + + self.rive_url = msg.url("#swap_character_main") + + self.viewModelInstance = rive.get_viewmodel(self.rive_url) + self.viewModelInstanceArtboardProp = self.viewModelInstance:get_property("Artboard property") + + self.character_file = rive.get_file_from_url("go1#swap_character_assets") + --go.delete("#swap_character_assets") + + --self.character_artboard = self.character_file:get_artboard() -- default: snapper + self.character_artboard = self.character_file:get_artboard('Character 1') -- ogre + --self.character_artboard = self.character_file:get_artboard('Character 2') -- snapper + attach_character(self) + + -- download_riv_file(self, "/unique/name/for/marty.rivc", URL, function (path_hash) + -- self.character_file = rive.get_file_from_path(path_hash) + -- self.character_artboard = self.character_file:get_artboard() + -- attach_character(self) + -- end) + +end + + +-- Enable rive input for the model. +function on_input(self, action_id, action) + -- if action_id == hash("left") or action_id == hash("right") or action_id == hash("up") or action_id == hash("down") then + -- if action.pressed and action_id == hash("left") then + -- move_left(self) + -- elseif action.pressed and action_id == hash("right") then + -- move_right(self) + -- elseif action.pressed and action_id == hash("up") then + -- request_thumb(self, URL) + -- elseif action.pressed and action_id == hash("down") then + -- remove_thumb(self, self.thumb_index+1) + -- end + -- return true + -- end +end diff --git a/main/databind-artboard/swap_character_assets.rev b/main/databind-artboard/swap_character_assets.rev new file mode 100644 index 00000000..144e2db1 Binary files /dev/null and b/main/databind-artboard/swap_character_assets.rev differ diff --git a/main/databind-artboard/swap_character_assets.riv b/main/databind-artboard/swap_character_assets.riv new file mode 100644 index 00000000..a92d2636 Binary files /dev/null and b/main/databind-artboard/swap_character_assets.riv differ diff --git a/main/databind-artboard/swap_character_assets.rivemodel b/main/databind-artboard/swap_character_assets.rivemodel new file mode 100644 index 00000000..d03600be --- /dev/null +++ b/main/databind-artboard/swap_character_assets.rivemodel @@ -0,0 +1,4 @@ +scene: "/main/databind-artboard/swap_character_assets.rivescene" +default_animation: "" +material: "/defold-rive/assets/rivemodel.material" +auto_bind: false diff --git a/main/databind-artboard/swap_character_assets.rivescene b/main/databind-artboard/swap_character_assets.rivescene new file mode 100644 index 00000000..d56f5b53 --- /dev/null +++ b/main/databind-artboard/swap_character_assets.rivescene @@ -0,0 +1,2 @@ +scene: "/main/databind-artboard/swap_character_assets.riv" +atlas: "/defold-rive/assets/empty.atlas" diff --git a/main/databind-artboard/swap_character_main.rev b/main/databind-artboard/swap_character_main.rev new file mode 100644 index 00000000..aa5af1d2 Binary files /dev/null and b/main/databind-artboard/swap_character_main.rev differ diff --git a/main/databind-artboard/swap_character_main.riv b/main/databind-artboard/swap_character_main.riv new file mode 100644 index 00000000..afe42d0c Binary files /dev/null and b/main/databind-artboard/swap_character_main.riv differ diff --git a/main/databind-artboard/swap_character_main.rivemodel b/main/databind-artboard/swap_character_main.rivemodel new file mode 100644 index 00000000..f45c88de --- /dev/null +++ b/main/databind-artboard/swap_character_main.rivemodel @@ -0,0 +1,3 @@ +scene: "/main/databind-artboard/swap_character_main.rivescene" +default_animation: "" +material: "/defold-rive/assets/rivemodel.material" diff --git a/main/databind-artboard/swap_character_main.rivescene b/main/databind-artboard/swap_character_main.rivescene new file mode 100644 index 00000000..b0c91ce2 --- /dev/null +++ b/main/databind-artboard/swap_character_main.rivescene @@ -0,0 +1,2 @@ +scene: "/main/databind-artboard/swap_character_main.riv" +atlas: "/defold-rive/assets/empty.atlas" diff --git a/main/input/input.collection b/main/input/input.collection index 972a04d5..634b0e7d 100644 --- a/main/input/input.collection +++ b/main/input/input.collection @@ -12,8 +12,6 @@ embedded_instances { " data: \"scene: \\\"/main/input/input.rivescene\\\"\\n" "default_animation: \\\"\\\"\\n" "material: \\\"/defold-rive/assets/rivemodel.material\\\"\\n" - "default_state_machine: \\\"State Machine 1\\\"\\n" - "artboard: \\\"Artboard\\\"\\n" "coordinate_system: COORDINATE_SYSTEM_RIVE\\n" "artboard_fit: FIT_CONTAIN\\n" "\"\n" diff --git a/main/loader.collection b/main/loader.collection index 74984f6a..83e93fb4 100644 --- a/main/loader.collection +++ b/main/loader.collection @@ -120,6 +120,12 @@ embedded_instances { " data: \"collection: \\\"/main/scrollist/scrollist.collection\\\"\\n" "\"\n" "}\n" + "embedded_components {\n" + " id: \"databind-artboard\"\n" + " type: \"collectionproxy\"\n" + " data: \"collection: \\\"/main/databind-artboard/databind-artboard.collection\\\"\\n" + "\"\n" + "}\n" "" } embedded_instances { diff --git a/main/menu/menu.gui_script b/main/menu/menu.gui_script index 4be9c9a4..2fd31d4e 100644 --- a/main/menu/menu.gui_script +++ b/main/menu/menu.gui_script @@ -19,7 +19,8 @@ local BUTTONS = { { id = "egg", text = "Feathering" }, { id = "outofband", text = "Out-of-band" }, { id = "databind", text = "Data Bindings" }, - { id = "scrollist", text = "Scroll List" }, + { id = "scrollist", text = "List Prop" }, + { id = "databind-artboard", text = "Artboard Prop" }, } local COLUMNS = 3 local WIDTH = 220 diff --git a/utils/build_rive_runtime.sh b/utils/build_rive_runtime.sh index e061fc0f..4608da48 100755 --- a/utils/build_rive_runtime.sh +++ b/utils/build_rive_runtime.sh @@ -4,12 +4,6 @@ set -e SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -PLATFORM=$1 -shift - -RIVECPP=$1 -shift - function Usage { echo "Usage: ./utils/build_rive_runtime.sh " echo "platforms:" @@ -27,18 +21,27 @@ function Usage { exit 1 } -if [ "" == "$RIVECPP" ]; then +PLATFORM=$1 + +RIVECPP=$2 + +if [ "" == "${PLATFORM}" ]; then echo "You must specify a runtime path" Usage fi -if [ ! -d "$RIVECPP" ]; then - echo "Rive folder does not exist: '$RIVECPP'" +if [ "" == "${RIVECPP}" ]; then + echo "You must specify a runtime path" + Usage +fi + +if [ ! -d "${RIVECPP}" ]; then + echo "Rive folder does not exist: '${RIVECPP}'" Usage fi # Check platforms -case $PLATFORM in +case ${PLATFORM} in arm64-android|armv7-android) ;; wasm-web|js-web|wasm_pthread-web)