| /* | |
| * Copyright 2025 Rive | |
| */ | |
| #pragma once | |
| #include "rive/object_stream.hpp" | |
| #include "rive/refcnt.hpp" | |
| #include "rive/math/vec2d.hpp" | |
| #include "rive/viewmodel/runtime/viewmodel_runtime.hpp" | |
| #include "rive/animation/semantic_listener_group.hpp" | |
| #include "rive/semantic/semantic_snapshot.hpp" | |
| #include <condition_variable> | |
| #include <cstdint> | |
| #include <functional> | |
| #include <memory> | |
| #include <mutex> | |
| #include <string> | |
| #include <vector> | |
| #include <unordered_map> | |
| #include "file_asset_loader.hpp" | |
| // Macros for defining and working with command buffer handles. | |
| #if INTPTR_MAX == INT64_MAX | |
| static_assert(sizeof(void*) == 8, "expected a 64-bit environment"); | |
| // Define handles as pointers to forward-declared types for type safety. | |
| #define RIVE_DEFINE_HANDLE(NAME) using NAME = struct NAME##_HandlePlaceholder*; | |
| #define RIVE_NULL_HANDLE nullptr | |
| #elif INTPTR_MAX == INT32_MAX | |
| static_assert(sizeof(void*) == 4, "expected a 32-bit environment"); | |
| #define RIVE_DEFINE_HANDLE(NAME) using NAME = uint64_t; | |
| #define RIVE_NULL_HANDLE 0 | |
| #else | |
| #error "environment not 32 or 64-bit." | |
| #endif | |
| namespace rive | |
| { | |
| class Factory; | |
| class File; | |
| class ArtboardInstance; | |
| class StateMachineInstance; | |
| class CommandServer; | |
| class ScriptingContext; | |
| RIVE_DEFINE_HANDLE(FontHandle); | |
| RIVE_DEFINE_HANDLE(FileHandle); | |
| RIVE_DEFINE_HANDLE(ArtboardHandle); | |
| RIVE_DEFINE_HANDLE(AudioSourceHandle); | |
| RIVE_DEFINE_HANDLE(RenderImageHandle); | |
| RIVE_DEFINE_HANDLE(BlobAssetHandle); | |
| RIVE_DEFINE_HANDLE(StateMachineHandle); | |
| RIVE_DEFINE_HANDLE(ViewModelInstanceHandle); | |
| RIVE_DEFINE_HANDLE(DrawKey); | |
| // Function poimter that gets called back from the server thread. | |
| using CommandServerCallback = std::function<void(CommandServer*)>; | |
| using CommandServerDrawCallback = std::function<void(DrawKey, CommandServer*)>; | |
| // Creates the ScriptingContext used for a loaded file's Lua VM. Invoked on the | |
| // command server thread with the server's Factory so the context is built with | |
| // the correct factory on the correct thread. Return nullptr (or leave the | |
| // factory empty) to fall back to the default CPPRuntimeScriptingContext. Used | |
| // by hosts (e.g. Unreal) to redirect Lua console/error output to their own | |
| // logging. | |
| using ScriptingContextFactory = | |
| std::function<std::unique_ptr<ScriptingContext>(Factory*)>; | |
| struct ViewModelEnum | |
| { | |
| std::string name; | |
| std::vector<std::string> enumerants; | |
| }; | |
| // Client-side recorder for commands that will be executed by a CommandServer. | |
| // Synchronized operations require an active CommandServer processing this | |
| // queue on another thread and must not be called after disconnect(); otherwise, | |
| // they block indefinitely. | |
| class CommandQueue : public RefCnt<CommandQueue> | |
| { | |
| public: | |
| template <typename ListenerType, typename HandleType> class ListenerBase | |
| { | |
| public: | |
| friend class CommandQueue; | |
| ListenerBase(const ListenerBase&) = delete; | |
| ListenerBase& operator=(const ListenerBase&) = delete; | |
| ListenerBase(ListenerBase&& other) : | |
| m_owningQueue(std::move(other.m_owningQueue)), | |
| m_handle(std::move(other.m_handle)) | |
| { | |
| if (m_owningQueue) | |
| { | |
| m_owningQueue->unregisterListener( | |
| m_handle, | |
| static_cast<ListenerType*>(&other)); | |
| m_owningQueue->registerListener( | |
| m_handle, | |
| static_cast<ListenerType*>(this)); | |
| } | |
| } | |
| ~ListenerBase() | |
| { | |
| if (m_owningQueue) | |
| m_owningQueue->unregisterListener( | |
| m_handle, | |
| static_cast<ListenerType*>(this)); | |
| } | |
| ListenerBase() : m_handle(RIVE_NULL_HANDLE) {} | |
| private: | |
| rcp<CommandQueue> m_owningQueue; | |
| HandleType m_handle; | |
| }; | |
| class FileListener | |
| : public CommandQueue::ListenerBase<FileListener, FileHandle> | |
| { | |
| public: | |
| virtual void onFileError(const FileHandle, | |
| uint64_t requestId, | |
| std::string error) | |
| {} | |
| virtual void onFileDeleted(const FileHandle, uint64_t requestId) {} | |
| virtual void onFileLoaded(const FileHandle, uint64_t requestId) {} | |
| /** | |
| * Called after an artboard instance is created. | |
| * | |
| * @param fileHandle The file from which the artboard was instantiated. | |
| * @param requestId The request that created the artboard handle. | |
| * @param artboardHandle The confirmed artboard handle. | |
| */ | |
| virtual void onArtboardInstantiated(const FileHandle fileHandle, | |
| uint64_t requestId, | |
| ArtboardHandle artboardHandle) | |
| {} | |
| /** | |
| * Called after a view model instance or instance reference is created. | |
| * | |
| * @param fileHandle The source file for a newly instantiated view | |
| * model, or RIVE_NULL_HANDLE when the new handle references an existing | |
| * nested or list-item instance. Confirmations with RIVE_NULL_HANDLE are | |
| * delivered only to a FileListener registered for RIVE_NULL_HANDLE. | |
| * @param requestId The request that created the instance handle. | |
| * @param viewModelInstanceHandle The confirmed instance handle. | |
| */ | |
| virtual void onViewModelInstanceInstantiated( | |
| const FileHandle fileHandle, | |
| uint64_t requestId, | |
| ViewModelInstanceHandle viewModelInstanceHandle) | |
| {} | |
| virtual void onArtboardsListed(const FileHandle, | |
| uint64_t requestId, | |
| std::vector<std::string> artboardNames) | |
| {} | |
| virtual void onViewModelsListed(const FileHandle, | |
| uint64_t requestId, | |
| std::vector<std::string> viewModelNames) | |
| {} | |
| virtual void onGlobalViewModelNamesListed( | |
| const FileHandle, | |
| uint64_t requestId, | |
| std::vector<std::string> globalViewModelNames) | |
| {} | |
| virtual void onViewModelInstanceNamesListed( | |
| const FileHandle, | |
| uint64_t requestId, | |
| std::string viewModelName, | |
| std::vector<std::string> instanceNames) | |
| {} | |
| struct ViewModelPropertyData | |
| { | |
| DataType type = DataType::none; | |
| std::string name = ""; | |
| std::string metaData = ""; | |
| }; | |
| virtual void onViewModelPropertiesListed( | |
| const FileHandle, | |
| uint64_t requestId, | |
| std::string viewModelName, | |
| std::vector<ViewModelPropertyData> properties) | |
| {} | |
| virtual void onViewModelEnumsListed(const FileHandle, | |
| uint64_t requestId, | |
| std::vector<ViewModelEnum> enums) | |
| {} | |
| struct FileAssetData | |
| { | |
| std::string name; | |
| std::string uniqueName; | |
| uint32_t assetID = 0; | |
| std::string cdnUUID; | |
| std::string cdnBaseURL; | |
| std::string fileExtension; | |
| uint16_t type = 0; | |
| }; | |
| virtual void onFileAssetsListed(const FileHandle, | |
| uint64_t requestId, | |
| std::vector<FileAssetData> assets) | |
| {} | |
| }; | |
| class RenderImageListener | |
| : public CommandQueue::ListenerBase<RenderImageListener, | |
| RenderImageHandle> | |
| { | |
| public: | |
| virtual void onRenderImageDecoded(const RenderImageHandle, | |
| uint64_t requestId) | |
| {} | |
| virtual void onRenderImageError(const RenderImageHandle, | |
| uint64_t requestId, | |
| std::string error) | |
| {} | |
| virtual void onRenderImageDeleted(const RenderImageHandle, | |
| uint64_t requestId) | |
| {} | |
| }; | |
| class AudioSourceListener | |
| : public CommandQueue::ListenerBase<AudioSourceListener, | |
| AudioSourceHandle> | |
| { | |
| public: | |
| virtual void onAudioSourceDecoded(const AudioSourceHandle, | |
| uint64_t requestId) | |
| {} | |
| virtual void onAudioSourceError(const AudioSourceHandle, | |
| uint64_t requestId, | |
| std::string error) | |
| {} | |
| virtual void onAudioSourceDeleted(const AudioSourceHandle, | |
| uint64_t requestId) | |
| {} | |
| }; | |
| class FontListener | |
| : public CommandQueue::ListenerBase<FontListener, FontHandle> | |
| { | |
| public: | |
| virtual void onFontDecoded(const FontHandle, uint64_t requestId) {} | |
| virtual void onFontError(const FontHandle, | |
| uint64_t requestId, | |
| std::string error) | |
| {} | |
| virtual void onFontDeleted(const FontHandle, uint64_t requestId) {} | |
| }; | |
| class BlobAssetListener | |
| : public CommandQueue::ListenerBase<BlobAssetListener, BlobAssetHandle> | |
| { | |
| public: | |
| virtual void onBlobAssetDecoded(const BlobAssetHandle, | |
| uint64_t requestId) | |
| {} | |
| virtual void onBlobAssetError(const BlobAssetHandle, | |
| uint64_t requestId, | |
| std::string error) | |
| {} | |
| virtual void onBlobAssetDeleted(const BlobAssetHandle, | |
| uint64_t requestId) | |
| {} | |
| }; | |
| class ArtboardListener | |
| : public CommandQueue::ListenerBase<ArtboardListener, ArtboardHandle> | |
| { | |
| public: | |
| virtual void onArtboardError(const ArtboardHandle, | |
| uint64_t requestId, | |
| std::string error) | |
| {} | |
| virtual void onDefaultViewModelInfoReceived(const ArtboardHandle, | |
| uint64_t requestId, | |
| std::string viewModelName, | |
| std::string instanceName) | |
| {} | |
| virtual void onArtboardDeleted(const ArtboardHandle, uint64_t requestId) | |
| {} | |
| /** | |
| * Called after a state machine instance is created. | |
| * | |
| * @param artboardHandle The artboard from which the state machine was | |
| * instantiated. | |
| * @param requestId The request that created the state machine handle. | |
| * @param stateMachineHandle The confirmed state machine handle. | |
| */ | |
| virtual void onStateMachineInstantiated( | |
| const ArtboardHandle artboardHandle, | |
| uint64_t requestId, | |
| StateMachineHandle stateMachineHandle) | |
| {} | |
| virtual void onStateMachinesListed( | |
| const ArtboardHandle, | |
| uint64_t requestId, | |
| std::vector<std::string> stateMachineNames) | |
| {} | |
| virtual void onArtboardVolumeReceived(const ArtboardHandle, | |
| uint64_t requestId, | |
| float volume) | |
| {} | |
| virtual void onArtboardSizeReceived(const ArtboardHandle, | |
| uint64_t requestId, | |
| float width, | |
| float height) | |
| {} | |
| }; | |
| struct ViewModelInstanceData | |
| { | |
| // The path and type of this property | |
| PropertyData metaData; | |
| // The specific value of this property, you must use the correct union | |
| // member base on type in metaData, both enumType and string use | |
| // stringValue | |
| // std::string is non trival, so it stays outside the union | |
| std::string stringValue; | |
| union | |
| { | |
| bool boolValue; | |
| float numberValue; | |
| ColorInt colorValue; | |
| }; | |
| }; | |
| // Mirrors StateMachineInstance::FocusState for command queue responses. | |
| struct FocusState | |
| { | |
| bool hasFocus = false; | |
| bool expectsKeyboardInput = false; | |
| }; | |
| class ViewModelInstanceListener | |
| : public CommandQueue::ListenerBase<ViewModelInstanceListener, | |
| ViewModelInstanceHandle> | |
| { | |
| public: | |
| virtual void onViewModelInstanceError(const ViewModelInstanceHandle, | |
| uint64_t requestId, | |
| std::string error) | |
| {} | |
| virtual void onViewModelInstanceViewModelNameReceived( | |
| const ViewModelInstanceHandle, | |
| uint64_t requestId, | |
| std::string viewModelName) | |
| {} | |
| virtual void onViewModelInstanceNameReceived( | |
| const ViewModelInstanceHandle handle, | |
| uint64_t requestId, | |
| std::string instanceName) | |
| {} | |
| virtual void onViewModelDeleted(const ViewModelInstanceHandle, | |
| uint64_t requestId) | |
| {} | |
| virtual void onViewModelDataReceived(const ViewModelInstanceHandle, | |
| uint64_t requestId, | |
| ViewModelInstanceData) | |
| {} | |
| virtual void onViewModelListSizeReceived(const ViewModelInstanceHandle, | |
| uint64_t requestId, | |
| std::string path, | |
| size_t size) | |
| {} | |
| virtual void onViewModelListCleared(const ViewModelInstanceHandle, | |
| uint64_t requestId, | |
| std::string path) | |
| {} | |
| }; | |
| class StateMachineListener | |
| : public CommandQueue::ListenerBase<StateMachineListener, | |
| StateMachineHandle> | |
| { | |
| public: | |
| virtual void onStateMachineError(const StateMachineHandle, | |
| uint64_t requestId, | |
| std::string error) | |
| {} | |
| virtual void onStateMachineDeleted(const StateMachineHandle, | |
| uint64_t requestId) | |
| {} | |
| // requestId in this case is the specific request that caused the | |
| // statemachine to settle | |
| virtual void onStateMachineSettled(const StateMachineHandle, | |
| uint64_t requestId) | |
| {} | |
| // Delivered when an incremental semantic diff is available for this | |
| // state machine. Emitted only when drainSemanticsDiff produces a | |
| // non-empty diff. Bounds inside the diff are reported in view space | |
| // using the fit/alignment/scale/view-bounds arguments provided to the | |
| // drain command. | |
| virtual void onSemanticsDiffReceived(const StateMachineHandle, | |
| uint64_t requestId, | |
| SemanticsDiff diff) | |
| {} | |
| virtual void onHasFocusNodesReceived(const StateMachineHandle, | |
| uint64_t requestId, | |
| bool hasFocusNodes) | |
| {} | |
| virtual void onFocusStateReceived(const StateMachineHandle, | |
| uint64_t requestId, | |
| FocusState focusState) | |
| {} | |
| }; | |
| CommandQueue(); | |
| ~CommandQueue(); | |
| FileHandle loadFile( | |
| std::vector<uint8_t> rivBytes, | |
| FileListener* listener = nullptr, | |
| uint64_t requestId = 0 | |
| #ifdef WITH_RIVE_SCRIPTING | |
| , | |
| ScriptingContextFactory scriptingContextFactory = nullptr | |
| #endif | |
| ); | |
| void deleteFile(FileHandle, uint64_t requestId = 0); | |
| void addGlobalImageAsset(std::string name, | |
| RenderImageHandle, | |
| uint64_t requestId = 0); | |
| void addGlobalFontAsset(std::string name, | |
| FontHandle, | |
| uint64_t requestId = 0); | |
| void addGlobalAudioAsset(std::string name, | |
| AudioSourceHandle, | |
| uint64_t requestId = 0); | |
| void removeGlobalImageAsset(std::string name, uint64_t requestId = 0); | |
| void removeGlobalFontAsset(std::string name, uint64_t requestId = 0); | |
| void removeGlobalAudioAsset(std::string name, uint64_t requestId = 0); | |
| ArtboardHandle instantiateArtboardNamed( | |
| FileHandle, | |
| std::string name, | |
| ArtboardListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| ArtboardHandle instantiateDefaultArtboard( | |
| FileHandle fileHandle, | |
| ArtboardListener* listener = nullptr, | |
| uint64_t requestId = 0) | |
| { | |
| return instantiateArtboardNamed(fileHandle, "", listener, requestId); | |
| } | |
| void setArtboardSize(ArtboardHandle, | |
| float width, | |
| float height, | |
| float scale = 1, | |
| uint64_t requestId = 0); | |
| void resetArtboardSize(ArtboardHandle, uint64_t requestId = 0); | |
| void deleteArtboard(ArtboardHandle, uint64_t requestId = 0); | |
| ViewModelInstanceHandle instantiateBlankViewModelInstance( | |
| FileHandle fileHandle, | |
| ArtboardHandle artboardHandle, | |
| ViewModelInstanceListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| ViewModelInstanceHandle instantiateBlankViewModelInstance( | |
| FileHandle fileHandle, | |
| std::string viewModelName, | |
| ViewModelInstanceListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| ViewModelInstanceHandle instantiateDefaultViewModelInstance( | |
| FileHandle fileHandle, | |
| ArtboardHandle artboardHandle, | |
| ViewModelInstanceListener* listener = nullptr, | |
| uint64_t requestId = 0) | |
| { | |
| return instantiateViewModelInstanceNamed(fileHandle, | |
| artboardHandle, | |
| "", | |
| listener, | |
| requestId); | |
| } | |
| ViewModelInstanceHandle instantiateDefaultViewModelInstance( | |
| FileHandle fileHandle, | |
| std::string viewModelName, | |
| ViewModelInstanceListener* listener = nullptr, | |
| uint64_t requestId = 0) | |
| { | |
| return instantiateViewModelInstanceNamed(fileHandle, | |
| viewModelName, | |
| "", | |
| listener, | |
| requestId); | |
| } | |
| ViewModelInstanceHandle instantiateViewModelInstanceNamed( | |
| FileHandle, | |
| ArtboardHandle, | |
| std::string viewModelInstanceName, | |
| ViewModelInstanceListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| ViewModelInstanceHandle instantiateViewModelInstanceNamed( | |
| FileHandle, | |
| std::string viewModelName, | |
| std::string viewModelInstanceName, | |
| ViewModelInstanceListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| ViewModelInstanceHandle referenceNestedViewModelInstance( | |
| ViewModelInstanceHandle, | |
| std::string path, | |
| ViewModelInstanceListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| ViewModelInstanceHandle referenceListViewModelInstance( | |
| ViewModelInstanceHandle, | |
| std::string path, | |
| int index, | |
| ViewModelInstanceListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| void fireViewModelTrigger(ViewModelInstanceHandle, | |
| std::string path, | |
| uint64_t requestId = 0); | |
| void setViewModelInstanceBool(ViewModelInstanceHandle, | |
| std::string path, | |
| bool value, | |
| uint64_t requestId = 0); | |
| void setViewModelInstanceNumber(ViewModelInstanceHandle, | |
| std::string path, | |
| float value, | |
| uint64_t requestId = 0); | |
| void setViewModelInstanceColor(ViewModelInstanceHandle, | |
| std::string path, | |
| ColorInt value, | |
| uint64_t requestId = 0); | |
| void setViewModelInstanceEnum(ViewModelInstanceHandle, | |
| std::string path, | |
| std::string value, | |
| uint64_t requestId = 0); | |
| void setViewModelInstanceString(ViewModelInstanceHandle, | |
| std::string path, | |
| std::string value, | |
| uint64_t requestId = 0); | |
| void setViewModelInstanceImage(ViewModelInstanceHandle, | |
| std::string path, | |
| RenderImageHandle value, | |
| uint64_t requestId = 0); | |
| void setViewModelInstanceBlob(ViewModelInstanceHandle, | |
| std::string path, | |
| BlobAssetHandle value, | |
| uint64_t requestId = 0); | |
| void setViewModelInstanceArtboard(ViewModelInstanceHandle, | |
| std::string path, | |
| ArtboardHandle value, | |
| uint64_t requestId = 0); | |
| void setViewModelInstanceNestedViewModel(ViewModelInstanceHandle, | |
| std::string path, | |
| ViewModelInstanceHandle value, | |
| uint64_t requestId = 0); | |
| void insertViewModelInstanceListViewModel(ViewModelInstanceHandle, | |
| std::string path, | |
| ViewModelInstanceHandle value, | |
| int index, | |
| uint64_t requestId = 0); | |
| void appendViewModelInstanceListViewModel(ViewModelInstanceHandle handle, | |
| std::string path, | |
| ViewModelInstanceHandle value, | |
| uint64_t requestId = 0) | |
| { | |
| insertViewModelInstanceListViewModel(handle, | |
| std::move(path), | |
| value, | |
| -1, | |
| requestId); | |
| } | |
| void removeViewModelInstanceListViewModel( | |
| ViewModelInstanceHandle, | |
| std::string path, | |
| int index, | |
| ViewModelInstanceHandle value = RIVE_NULL_HANDLE, | |
| uint64_t requestId = 0); | |
| void removeViewModelInstanceListViewModel(ViewModelInstanceHandle handle, | |
| std::string path, | |
| ViewModelInstanceHandle value, | |
| uint64_t requestId = 0) | |
| { | |
| removeViewModelInstanceListViewModel(handle, | |
| std::move(path), | |
| -1, | |
| value, | |
| requestId); | |
| } | |
| void swapViewModelInstanceListValues(ViewModelInstanceHandle handle, | |
| std::string path, | |
| int indexa, | |
| int indexb, | |
| uint64_t requestId = 0); | |
| void subscribeToViewModelProperty(ViewModelInstanceHandle handle, | |
| std::string path, | |
| DataType type, | |
| uint64_t requestId = 0); | |
| void unsubscribeToViewModelProperty(ViewModelInstanceHandle handle, | |
| std::string path, | |
| DataType type, | |
| uint64_t requestId = 0); | |
| void deleteViewModelInstance(ViewModelInstanceHandle, | |
| uint64_t requestId = 0); | |
| StateMachineHandle instantiateStateMachineNamed( | |
| ArtboardHandle, | |
| std::string name, | |
| StateMachineListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| StateMachineHandle instantiateDefaultStateMachine( | |
| ArtboardHandle artboardHandle, | |
| StateMachineListener* listener = nullptr, | |
| uint64_t requestId = 0) | |
| { | |
| return instantiateStateMachineNamed(artboardHandle, | |
| "", | |
| listener, | |
| requestId); | |
| } | |
| void bindViewModelInstance(StateMachineHandle, | |
| ViewModelInstanceHandle, | |
| uint64_t requestId = 0); | |
| // Sets the main (non-global) view model instance without rebinding. Call | |
| // bind() to apply. | |
| void setViewModelInstance(StateMachineHandle, | |
| ViewModelInstanceHandle, | |
| uint64_t requestId = 0); | |
| /** | |
| * Removes the main (non-global) view model instance from a state machine | |
| * without rebinding. Call bind() to create and apply its default main | |
| * instance. | |
| * | |
| * @param stateMachineHandle The state machine whose main instance should | |
| * be cleared. | |
| * @param requestId The identifier reported with any asynchronous error. | |
| */ | |
| void clearViewModelInstance(StateMachineHandle stateMachineHandle, | |
| uint64_t requestId = 0); | |
| // Sets/replaces the global view model instance bound under the given global | |
| // view model name without rebinding. Call bind() to apply. Reports a state | |
| // machine error if the name does not match a global view model. | |
| void setGlobalViewModelInstance(StateMachineHandle, | |
| std::string name, | |
| ViewModelInstanceHandle, | |
| uint64_t requestId = 0); | |
| /** | |
| * Removes the instance occupying a named global slot without rebinding, | |
| * preserving the main instance and every other global slot. Call bind() to | |
| * create and apply that slot's default instance. Reports a state machine | |
| * error if name does not identify a global view model. | |
| * | |
| * @param stateMachineHandle The state machine whose global slot should be | |
| * cleared. | |
| * @param name The global view model slot to clear. | |
| * @param requestId The identifier reported with any asynchronous error. | |
| */ | |
| void clearGlobalViewModelInstance(StateMachineHandle stateMachineHandle, | |
| std::string name, | |
| uint64_t requestId = 0); | |
| // Returns a handle to the global view model instance currently bound under | |
| // the given name. Never creates: if none is bound, reports a view model | |
| // error and the returned handle maps to nothing. | |
| ViewModelInstanceHandle globalViewModelInstance( | |
| StateMachineHandle, | |
| std::string name, | |
| ViewModelInstanceListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| /** | |
| * Applies the state machine's current data context to its artboard and | |
| * state machine data binds in a single pass. Any missing main or global | |
| * view model instances are created from their defaults before binding. | |
| * Reports a state machine error asynchronously if the handle is invalid. | |
| * | |
| * @param stateMachineHandle The state machine whose data context should be | |
| * applied. | |
| * @param requestId The identifier reported with any asynchronous error. | |
| */ | |
| void bind(StateMachineHandle stateMachineHandle, uint64_t requestId = 0); | |
| void advanceStateMachine(StateMachineHandle, | |
| float timeToAdvance, | |
| uint64_t requestId = 0); | |
| // Enable the semantic subsystem on the given state machine. Must be | |
| // called before diffs are delivered. Safe to call multiple times. | |
| void enableSemantics(StateMachineHandle, uint64_t requestId = 0); | |
| // Drain the current semantic diff for the given state machine. | |
| // The response is delivered via | |
| // StateMachineListener::onSemanticsDiffReceived when the diff is non-empty. | |
| // Output bounds are mapped to view space using the provided fit/alignment/ | |
| // scale/view-bounds parameters. | |
| void drainSemanticsDiff(StateMachineHandle, | |
| Fit fit, | |
| Alignment alignment, | |
| float scaleFactor, | |
| Vec2D viewBounds, | |
| uint64_t requestId = 0); | |
| // Pointer events | |
| struct PointerEvent | |
| { | |
| Fit fit = Fit::none; // the fit the artboard is drawn with | |
| Alignment alignment; // the alignment the artboard is drawn with | |
| Vec2D screenBounds; // the bounds of coordinate system of the cursor | |
| Vec2D position; // the cursor position | |
| float scaleFactor = 1.0f; // scale factor for things like retina display | |
| int pointerId = 0; // stable pointer identifier for multitouch | |
| }; | |
| // All pointer events will automatically convert between artboard and screen | |
| // space for you based on the values passed in the PointerEvent struct. | |
| void pointerMove(StateMachineHandle, PointerEvent, uint64_t requestId = 0); | |
| void pointerDown(StateMachineHandle, PointerEvent, uint64_t requestId = 0); | |
| void pointerUp(StateMachineHandle, PointerEvent, uint64_t requestId = 0); | |
| void pointerExit(StateMachineHandle, PointerEvent, uint64_t requestId = 0); | |
| void deleteStateMachine(StateMachineHandle, uint64_t requestId = 0); | |
| // Fire a semantic action (tap / increase / decrease) on the given node. | |
| // Fire-and-forget; reports a stateMachineError if the handle is unknown or | |
| // semantics isn't enabled. An unknown node id is a silent no-op. | |
| void fireSemanticAction(StateMachineHandle, | |
| uint32_t semanticNodeId, | |
| SemanticActionType actionType, | |
| uint64_t requestId = 0); | |
| // Request focus on the given semantic node. Fire-and-forget; reports a | |
| // stateMachineError if the handle is unknown or semantics isn't enabled. | |
| // An unknown or non-focusable node id is a silent no-op. | |
| void requestSemanticFocus(StateMachineHandle, | |
| uint32_t semanticNodeId, | |
| uint64_t requestId = 0); | |
| // Clear all semantic focus. Called when the screen reader moves | |
| // focus entirely away from the hosting view. | |
| void clearSemanticFocus(StateMachineHandle, uint64_t requestId = 0); | |
| RenderImageHandle decodeImage(std::vector<uint8_t> imageEncodedBytes, | |
| RenderImageListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| // This is needed for unreal rhi because all images come pre-decoded and | |
| // uploaded to gpu. | |
| RenderImageHandle addExternalImage(rcp<RenderImage> externalImage, | |
| RenderImageListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| void deleteImage(RenderImageHandle, uint64_t requestId = 0); | |
| AudioSourceHandle decodeAudio(std::vector<uint8_t> imageEncodedBytes, | |
| AudioSourceListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| AudioSourceHandle addExternalAudio(rcp<AudioSource> externalAudio, | |
| AudioSourceListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| void deleteAudio(AudioSourceHandle, uint64_t requestId = 0); | |
| FontHandle decodeFont(std::vector<uint8_t> imageEncodedBytes, | |
| FontListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| FontHandle addExternalFont(rcp<Font> externalFont, | |
| FontListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| void deleteFont(FontHandle, uint64_t requestId = 0); | |
| BlobAssetHandle decodeBlob(std::vector<uint8_t> blobBytes, | |
| BlobAssetListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| BlobAssetHandle addExternalBlob(rcp<BlobAsset> externalBlob, | |
| BlobAssetListener* listener = nullptr, | |
| uint64_t requestId = 0); | |
| void deleteBlob(BlobAssetHandle, uint64_t requestId = 0); | |
| // Create unique draw key for draw. | |
| DrawKey createDrawKey(); | |
| /** | |
| * Executes a one-time callback directly on the command server. | |
| * | |
| * This is an escape hatch for tests and runtime-specific operations that | |
| * cannot be represented by the shared command and message protocol. Do not | |
| * use it to implement capabilities common to multiple runtimes; add a | |
| * canonical command, message, and listener callback instead. | |
| * | |
| * @param callback The callback to execute on the command server. | |
| */ | |
| void runOnce(CommandServerCallback); | |
| // Run draw function for given draw key, only the latest function passed | |
| // will be run per pollCommands. | |
| void draw(DrawKey, CommandServerDrawCallback); | |
| // Cancel a pending draw for the given key if it has already been admitted | |
| // to the current coalesced draw batch. | |
| void cancelDraw(DrawKey); | |
| #ifdef TESTING | |
| // Sends a commandLoopBreak command to the server. This will cause the | |
| // processCommands to return even if there are more commands to consume. | |
| // This does not shutdown the server, it only causes processCommands to | |
| // return. To continue processing commands, another call to processCommands | |
| // is required. | |
| void testing_commandLoopBreak(); | |
| FileListener* testing_getFileListener(FileHandle); | |
| ArtboardListener* testing_getArtboardListener(ArtboardHandle); | |
| StateMachineListener* testing_getStateMachineListener(StateMachineHandle); | |
| #endif | |
| void disconnect(); | |
| void requestViewModelNames(FileHandle, uint64_t requestId = 0); | |
| void requestGlobalViewModelNames(FileHandle, uint64_t requestId = 0); | |
| void requestArtboardNames(FileHandle, uint64_t requestId = 0); | |
| void requestFileAssets(FileHandle, uint64_t requestId = 0); | |
| void requestViewModelEnums(FileHandle, uint64_t requestId = 0); | |
| void requestViewModelPropertyDefinitions(FileHandle, | |
| std::string viewModelName, | |
| uint64_t requestId = 0); | |
| void requestViewModelInstanceNames(FileHandle, | |
| std::string viewModelName, | |
| uint64_t requestId = 0); | |
| void requestViewModelInstanceViewModelName(ViewModelInstanceHandle, | |
| uint64_t requestId = 0); | |
| void requestViewModelInstanceName(ViewModelInstanceHandle handle, | |
| uint64_t requestId = 0); | |
| void requestViewModelInstanceBool(ViewModelInstanceHandle, | |
| std::string path, | |
| uint64_t requestId = 0); | |
| void requestViewModelInstanceNumber(ViewModelInstanceHandle, | |
| std::string path, | |
| uint64_t requestId = 0); | |
| void requestViewModelInstanceColor(ViewModelInstanceHandle, | |
| std::string path, | |
| uint64_t requestId = 0); | |
| void requestViewModelInstanceEnum(ViewModelInstanceHandle, | |
| std::string path, | |
| uint64_t requestId = 0); | |
| void requestViewModelInstanceString(ViewModelInstanceHandle, | |
| std::string path, | |
| uint64_t requestId = 0); | |
| void requestViewModelInstanceListSize(ViewModelInstanceHandle, | |
| std::string path, | |
| uint64_t requestId = 0); | |
| void requestViewModelInstanceListClear(ViewModelInstanceHandle, | |
| std::string path, | |
| uint64_t requestId = 0); | |
| void setArtboardVolume(ArtboardHandle, | |
| float volume, | |
| uint64_t requestId = 0); | |
| void requestArtboardVolume(ArtboardHandle, uint64_t requestId = 0); | |
| void requestArtboardSize(ArtboardHandle, uint64_t requestId = 0); | |
| void requestStateMachineNames(ArtboardHandle, uint64_t requestId = 0); | |
| void requestDefaultViewModelInfo(ArtboardHandle, | |
| FileHandle, | |
| uint64_t requestId = 0); | |
| // Consume all messages received from the server. | |
| void processMessages(); | |
| void setGlobalFileListener(FileListener* listener) | |
| { | |
| m_globalFileListener = listener; | |
| } | |
| void setGlobalArtboardListener(ArtboardListener* listener) | |
| { | |
| m_globalArtboardListener = listener; | |
| } | |
| void setGlobalStateMachineListener(StateMachineListener* listener) | |
| { | |
| m_globalStateMachineListener = listener; | |
| } | |
| void setGlobalViewModelInstanceListener(ViewModelInstanceListener* listener) | |
| { | |
| m_globalViewModelListener = listener; | |
| } | |
| void setGlobalRenderImageListener(RenderImageListener* listener) | |
| { | |
| m_globalImageListener = listener; | |
| } | |
| void setGlobalAudioSourceListener(AudioSourceListener* listener) | |
| { | |
| m_globalAudioListener = listener; | |
| } | |
| void setGlobalFontListener(FontListener* listener) | |
| { | |
| m_globalFontListener = listener; | |
| } | |
| void setGlobalBlobAssetListener(BlobAssetListener* listener) | |
| { | |
| m_globalBlobListener = listener; | |
| } | |
| bool focusNextSynchronized(StateMachineHandle); | |
| bool focusPreviousSynchronized(StateMachineHandle); | |
| void focusNext(StateMachineHandle, uint64_t requestId = 0); | |
| void focusPrevious(StateMachineHandle, uint64_t requestId = 0); | |
| void requestHasFocusNodes(StateMachineHandle, uint64_t requestId = 0); | |
| void clearFocus(StateMachineHandle, uint64_t requestId = 0); | |
| void requestFocusState(StateMachineHandle, uint64_t requestId = 0); | |
| private: | |
| void registerListener(FileHandle handle, FileListener* listener) | |
| { | |
| assert(listener); | |
| assert(m_fileListeners.find(handle) == m_fileListeners.end()); | |
| m_fileListeners.insert({handle, listener}); | |
| } | |
| void registerListener(RenderImageHandle handle, | |
| RenderImageListener* listener) | |
| { | |
| assert(listener); | |
| assert(m_imageListeners.find(handle) == m_imageListeners.end()); | |
| m_imageListeners.insert({handle, listener}); | |
| } | |
| void registerListener(AudioSourceHandle handle, | |
| AudioSourceListener* listener) | |
| { | |
| assert(listener); | |
| assert(m_audioListeners.find(handle) == m_audioListeners.end()); | |
| m_audioListeners.insert({handle, listener}); | |
| } | |
| void registerListener(FontHandle handle, FontListener* listener) | |
| { | |
| assert(listener); | |
| assert(m_fontListeners.find(handle) == m_fontListeners.end()); | |
| m_fontListeners.insert({handle, listener}); | |
| } | |
| void registerListener(BlobAssetHandle handle, BlobAssetListener* listener) | |
| { | |
| assert(listener); | |
| assert(m_blobListeners.find(handle) == m_blobListeners.end()); | |
| m_blobListeners.insert({handle, listener}); | |
| } | |
| void registerListener(ArtboardHandle handle, ArtboardListener* listener) | |
| { | |
| assert(listener); | |
| assert(m_artboardListeners.find(handle) == m_artboardListeners.end()); | |
| m_artboardListeners.insert({handle, listener}); | |
| } | |
| void registerListener(ViewModelInstanceHandle handle, | |
| ViewModelInstanceListener* listener) | |
| { | |
| assert(listener); | |
| assert(m_viewModelListeners.find(handle) == m_viewModelListeners.end()); | |
| m_viewModelListeners.insert({handle, listener}); | |
| } | |
| void registerListener(StateMachineHandle handle, | |
| StateMachineListener* listener) | |
| { | |
| assert(listener); | |
| assert(m_stateMachineListeners.find(handle) == | |
| m_stateMachineListeners.end()); | |
| m_stateMachineListeners.insert({handle, listener}); | |
| } | |
| // On 32-bit architectures, Handles are all uint64_t (not unique types), so | |
| // it will think we are re-declaring unregisterListener 3 times if we don't | |
| // add the listener pointer (even though it is not needed). | |
| void unregisterListener(FileHandle handle, FileListener* listener) | |
| { | |
| m_fileListeners.erase(handle); | |
| } | |
| void unregisterListener(RenderImageHandle handle, | |
| RenderImageListener* listener) | |
| { | |
| m_imageListeners.erase(handle); | |
| } | |
| void unregisterListener(AudioSourceHandle handle, | |
| AudioSourceListener* listener) | |
| { | |
| m_audioListeners.erase(handle); | |
| } | |
| void unregisterListener(FontHandle handle, FontListener* listener) | |
| { | |
| m_fontListeners.erase(handle); | |
| } | |
| void unregisterListener(BlobAssetHandle handle, BlobAssetListener* listener) | |
| { | |
| m_blobListeners.erase(handle); | |
| } | |
| void unregisterListener(ArtboardHandle handle, ArtboardListener* listener) | |
| { | |
| m_artboardListeners.erase(handle); | |
| } | |
| void unregisterListener(ViewModelInstanceHandle handle, | |
| ViewModelInstanceListener* listener) | |
| { | |
| m_viewModelListeners.erase(handle); | |
| } | |
| void unregisterListener(StateMachineHandle handle, | |
| StateMachineListener* listener) | |
| { | |
| m_stateMachineListeners.erase(handle); | |
| } | |
| enum class Command | |
| { | |
| loadFile, | |
| deleteFile, | |
| decodeImage, | |
| externalImage, | |
| decodeAudio, | |
| externalAudio, | |
| decodeFont, | |
| externalFont, | |
| decodeBlob, | |
| externalBlob, | |
| deleteImage, | |
| deleteAudio, | |
| deleteFont, | |
| deleteBlob, | |
| addImageFileAsset, | |
| addAudioFileAsset, | |
| addFontFileAsset, | |
| removeImageFileAsset, | |
| removeAudioFileAsset, | |
| removeFontFileAsset, | |
| instantiateArtboard, | |
| deleteArtboard, | |
| setArtboardSize, | |
| resetArtboardSize, | |
| instantiateViewModel, | |
| refNestedViewModel, | |
| refListViewModel, | |
| instantiateBlankViewModel, | |
| instantiateViewModelForArtboard, | |
| instantiateBlankViewModelForArtboard, | |
| setViewModelInstanceValue, | |
| addViewModelListValue, | |
| removeViewModelListValue, | |
| swapViewModelListValue, | |
| subscribeViewModelProperty, | |
| unsubscribeViewModelProperty, | |
| deleteViewModel, | |
| instantiateStateMachine, | |
| deleteStateMachine, | |
| advanceStateMachine, | |
| enableSemantics, | |
| drainSemanticsDiff, | |
| fireSemanticAction, | |
| requestSemanticFocus, | |
| clearSemanticFocus, | |
| bindViewModelInstance, | |
| setViewModelInstance, | |
| clearViewModelInstance, | |
| setGlobalViewModelInstance, | |
| clearGlobalViewModelInstance, | |
| getGlobalViewModelInstance, | |
| bind, | |
| runOnce, | |
| draw, | |
| cancelDraw, | |
| pointerMove, | |
| pointerDown, | |
| pointerUp, | |
| pointerExit, | |
| disconnect, | |
| // This will cause processCommands to return once received. We want to | |
| // ensure that we do not indefinetly block the calling thread. This is | |
| // how we achieve that. | |
| commandLoopBreak, | |
| // messages | |
| listViewModelEnums, | |
| listArtboards, | |
| listStateMachines, | |
| getDefaultViewModel, | |
| listViewModels, | |
| listGlobalViewModelNames, | |
| listViewModelInstanceNames, | |
| listViewModelProperties, | |
| listViewModelPropertyValue, | |
| getViewModelInstanceViewModelName, | |
| getViewModelInstanceName, | |
| getViewModelListSize, | |
| clearViewModelList, | |
| listFileAssets, | |
| setArtboardVolume, | |
| getArtboardVolume, | |
| getArtboardSize, | |
| focusNext, | |
| focusPrevious, | |
| requestHasFocusNodes, | |
| clearFocus, | |
| requestFocusState | |
| }; | |
| enum class Message | |
| { | |
| // Same as commandLoopBreak for processMessages | |
| messageLoopBreak, | |
| viewModelEnumsListed, | |
| artboardsListed, | |
| stateMachinesListed, | |
| defaultViewModelReceived, | |
| viewModelInstanceViewModelNameReceived, | |
| viewModelInstanceNameReceived, | |
| viewModelsListend, | |
| globalViewModelNamesListed, | |
| viewModelInstanceNamesListed, | |
| viewModelPropertiesListed, | |
| viewModelPropertyValueReceived, | |
| viewModelListSizeReceived, | |
| viewModelListCleared, | |
| fileLoaded, | |
| fileDeleted, | |
| artboardInstantiated, | |
| stateMachineInstantiated, | |
| viewModelInstanceInstantiated, | |
| imageDecoded, | |
| imageDeleted, | |
| audioDecoded, | |
| audioDeleted, | |
| fontDecoded, | |
| fontDeleted, | |
| blobDecoded, | |
| blobDeleted, | |
| artboardDeleted, | |
| viewModelDeleted, | |
| stateMachineDeleted, | |
| stateMachineSettled, | |
| semanticsDiffReceived, | |
| fileAssetsListed, | |
| artboardSizeReceived, | |
| fileError, | |
| artboardError, | |
| viewModelError, | |
| imageError, | |
| audioError, | |
| fontError, | |
| blobError, | |
| stateMachineError, | |
| artboardVolumeReceived, | |
| hasFocusNodesReceived, | |
| focusStateReceived | |
| }; | |
| friend class CommandServer; | |
| uint64_t m_currentFileHandleIdx = 0; | |
| uint64_t m_currentListHandleIdx = 0; | |
| uint64_t m_currentFontHandleIdx = 0; | |
| uint64_t m_currentArtboardHandleIdx = 0; | |
| uint64_t m_currentViewModelHandleIdx = 0; | |
| uint64_t m_currentRenderImageHandleIdx = 0; | |
| uint64_t m_currentBlobAssetHandleIdx = 0; | |
| uint64_t m_currentAudioSourceHandleIdx = 0; | |
| uint64_t m_currentStateMachineHandleIdx = 0; | |
| uint64_t m_currentDrawKeyIdx = 0; | |
| std::mutex m_commandMutex; | |
| std::condition_variable m_commandConditionVariable; | |
| PODStream m_commandStream; | |
| ObjectStream<rcp<RenderImage>> m_externalImages; | |
| ObjectStream<rcp<AudioSource>> m_externalAudioSources; | |
| ObjectStream<rcp<Font>> m_externalFonts; | |
| ObjectStream<rcp<BlobAsset>> m_externalBlobs; | |
| ObjectStream<std::vector<uint8_t>> m_byteVectors; | |
| #ifdef WITH_RIVE_SCRIPTING | |
| ObjectStream<ScriptingContextFactory> m_scriptingContextFactories; | |
| #endif | |
| ObjectStream<PointerEvent> m_pointerEvents; | |
| ObjectStream<std::string> m_names; | |
| ObjectStream<CommandServerCallback> m_callbacks; | |
| ObjectStream<CommandServerDrawCallback> m_drawCallbacks; | |
| // Messages streams | |
| std::mutex m_messageMutex; | |
| PODStream m_messageStream; | |
| ObjectStream<std::string> m_messageNames; | |
| ObjectStream<SemanticsDiff> m_messageSemanticsDiffs; | |
| // Listeners | |
| FileListener* m_globalFileListener = nullptr; | |
| RenderImageListener* m_globalImageListener = nullptr; | |
| AudioSourceListener* m_globalAudioListener = nullptr; | |
| FontListener* m_globalFontListener = nullptr; | |
| BlobAssetListener* m_globalBlobListener = nullptr; | |
| ArtboardListener* m_globalArtboardListener = nullptr; | |
| ViewModelInstanceListener* m_globalViewModelListener = nullptr; | |
| StateMachineListener* m_globalStateMachineListener = nullptr; | |
| std::unordered_map<FileHandle, FileListener*> m_fileListeners; | |
| std::unordered_map<RenderImageHandle, RenderImageListener*> | |
| m_imageListeners; | |
| std::unordered_map<AudioSourceHandle, AudioSourceListener*> | |
| m_audioListeners; | |
| std::unordered_map<FontHandle, FontListener*> m_fontListeners; | |
| std::unordered_map<BlobAssetHandle, BlobAssetListener*> m_blobListeners; | |
| std::unordered_map<ArtboardHandle, ArtboardListener*> m_artboardListeners; | |
| std::unordered_map<ViewModelInstanceHandle, ViewModelInstanceListener*> | |
| m_viewModelListeners; | |
| std::unordered_map<StateMachineHandle, StateMachineListener*> | |
| m_stateMachineListeners; | |
| }; | |
| }; // namespace rive |